Skip to content

Commit 775196c

Browse files
committed
Merge branch '2.6' into merge-2.6-20190814
2 parents 8391bfe + 8c8d967 commit 775196c

File tree

10 files changed

+246
-50
lines changed

10 files changed

+246
-50
lines changed

caas/kubernetes/provider/base_test.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,20 @@ func (s *BaseSuite) setupController(c *gc.C) *gomock.Controller {
130130
s.watchers = append(s.watchers, w)
131131
return w, err
132132
}
133-
return s.setupBroker(c, ctrl, newK8sRestClientFunc, newK8sWatcherForTest)
133+
randomPrefixFunc := func() (string, error) {
134+
return "appuuid", nil
135+
}
136+
return s.setupBroker(c, ctrl, newK8sRestClientFunc, newK8sWatcherForTest, randomPrefixFunc)
134137
}
135138

136139
func (s *BaseSuite) setupBroker(c *gc.C, ctrl *gomock.Controller,
137140
newK8sRestClientFunc provider.NewK8sClientFunc,
138-
newK8sWatcherFunc provider.NewK8sWatcherFunc) *gomock.Controller {
141+
newK8sWatcherFunc provider.NewK8sWatcherFunc,
142+
randomPrefixFunc provider.RandomPrefixFunc) *gomock.Controller {
139143
s.clock = testclock.NewClock(time.Time{})
140144
var err error
141-
s.broker, err = provider.NewK8sBroker(s.controllerUUID, s.k8sRestConfig, s.cfg, newK8sRestClientFunc, newK8sWatcherFunc, s.clock)
145+
s.broker, err = provider.NewK8sBroker(s.controllerUUID, s.k8sRestConfig, s.cfg, newK8sRestClientFunc,
146+
newK8sWatcherFunc, randomPrefixFunc, s.clock)
142147
c.Assert(err, jc.ErrorIsNil)
143148
return ctrl
144149
}

caas/kubernetes/provider/bootstrap_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,10 @@ func (s *bootstrapSuite) TestBootstrap(c *gc.C) {
192192
s.watchers = append(s.watchers, w)
193193
return w, err
194194
}
195-
s.setupBroker(c, ctrl, newK8sRestClientFunc, newK8sWatcherForTest)
195+
randomPrefixFunc := func() (string, error) {
196+
return "appuuid", nil
197+
}
198+
s.setupBroker(c, ctrl, newK8sRestClientFunc, newK8sWatcherForTest, randomPrefixFunc)
196199
// Broker's namespace is "controller" now - controllerModelConfig.Name()
197200
c.Assert(s.broker.GetCurrentNamespace(), jc.DeepEquals, "controller")
198201
c.Assert(

caas/kubernetes/provider/k8s.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ type kubernetesClient struct {
102102

103103
// newWatcher is the k8s watcher generator.
104104
newWatcher NewK8sWatcherFunc
105+
106+
// randomPrefix generates an annotation for stateful sets.
107+
randomPrefix RandomPrefixFunc
105108
}
106109

107110
// To regenerate the mocks for the kubernetes Client used by this broker,
@@ -121,13 +124,17 @@ type NewK8sClientFunc func(c *rest.Config) (kubernetes.Interface, apiextensionsc
121124
// NewK8sWatcherFunc defines a function which returns a k8s watcher based on the supplied config.
122125
type NewK8sWatcherFunc func(wi watch.Interface, name string, clock jujuclock.Clock) (*kubernetesWatcher, error)
123126

127+
// RandomPrefixFunc defines a function used to generate a random hex string.
128+
type RandomPrefixFunc func() (string, error)
129+
124130
// newK8sBroker returns a kubernetes client for the specified k8s cluster.
125131
func newK8sBroker(
126132
controllerUUID string,
127133
k8sRestConfig *rest.Config,
128134
cfg *config.Config,
129135
newClient NewK8sClientFunc,
130136
newWatcher NewK8sWatcherFunc,
137+
randomPrefix RandomPrefixFunc,
131138
clock jujuclock.Clock,
132139
) (*kubernetesClient, error) {
133140

@@ -153,6 +160,7 @@ func newK8sBroker(
153160
modelUUID: modelUUID,
154161
newWatcher: newWatcher,
155162
newClient: newClient,
163+
randomPrefix: randomPrefix,
156164
annotations: k8sannotations.New(nil).
157165
Add(annotationModelUUIDKey, modelUUID),
158166
}
@@ -1248,7 +1256,7 @@ func (k *kubernetesClient) EnsureService(
12481256
// Add a deployment controller or stateful set configured to create the specified number of units/pods.
12491257
// Defensively check to see if a stateful set is already used.
12501258
var useStatefulSet bool
1251-
if params.Deployment.ServiceType != "" {
1259+
if params.Deployment.DeploymentType != "" {
12521260
useStatefulSet = params.Deployment.DeploymentType == caas.DeploymentStateful
12531261
} else {
12541262
useStatefulSet = len(params.Filesystems) > 0
@@ -1273,11 +1281,10 @@ func (k *kubernetesClient) EnsureService(
12731281
randPrefix = existingStatefulSet.Annotations[labelApplicationUUID]
12741282
}
12751283
if randPrefix == "" {
1276-
var randPrefixBytes [4]byte
1277-
if _, err := io.ReadFull(rand.Reader, randPrefixBytes[0:4]); err != nil {
1284+
randPrefix, err = k.randomPrefix()
1285+
if err != nil {
12781286
return errors.Trace(err)
12791287
}
1280-
randPrefix = fmt.Sprintf("%x", randPrefixBytes)
12811288
}
12821289
}
12831290

@@ -1333,6 +1340,14 @@ func (k *kubernetesClient) EnsureService(
13331340
return nil
13341341
}
13351342

1343+
func randomPrefix() (string, error) {
1344+
var randPrefixBytes [4]byte
1345+
if _, err := io.ReadFull(rand.Reader, randPrefixBytes[0:4]); err != nil {
1346+
return "", errors.Trace(err)
1347+
}
1348+
return fmt.Sprintf("%x", randPrefixBytes), nil
1349+
}
1350+
13361351
// Upgrade sets the OCI image for the app's operator to the specified version.
13371352
func (k *kubernetesClient) Upgrade(appName string, vers version.Number) error {
13381353
var resourceName string

caas/kubernetes/provider/k8s_test.go

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,82 @@ func (s *K8sBrokerSuite) TestEnsureServiceNoStorageStateful(c *gc.C) {
11631163
},
11641164
}
11651165

1166+
serviceArg := *basicServiceArg
1167+
serviceArg.Spec.Type = core.ServiceTypeClusterIP
1168+
gomock.InOrder(
1169+
s.mockStatefulSets.EXPECT().Get("juju-operator-app-name", v1.GetOptions{IncludeUninitialized: true}).Times(1).
1170+
Return(nil, s.k8sNotFoundError()),
1171+
s.mockSecrets.EXPECT().Update(s.secretArg(c, nil)).Times(1).
1172+
Return(nil, nil),
1173+
s.mockStatefulSets.EXPECT().Get("app-name", v1.GetOptions{IncludeUninitialized: true}).Times(1).
1174+
Return(nil, s.k8sNotFoundError()),
1175+
s.mockServices.EXPECT().Get("app-name", v1.GetOptions{IncludeUninitialized: true}).Times(1).
1176+
Return(nil, s.k8sNotFoundError()),
1177+
s.mockServices.EXPECT().Update(&serviceArg).Times(1).
1178+
Return(nil, s.k8sNotFoundError()),
1179+
s.mockServices.EXPECT().Create(&serviceArg).Times(1).
1180+
Return(nil, nil),
1181+
s.mockServices.EXPECT().Get("app-name-endpoints", v1.GetOptions{IncludeUninitialized: true}).Times(1).
1182+
Return(nil, s.k8sNotFoundError()),
1183+
s.mockServices.EXPECT().Update(basicHeadlessServiceArg).Times(1).
1184+
Return(nil, s.k8sNotFoundError()),
1185+
s.mockServices.EXPECT().Create(basicHeadlessServiceArg).Times(1).
1186+
Return(nil, nil),
1187+
s.mockStatefulSets.EXPECT().Update(statefulSetArg).Times(1).
1188+
Return(nil, s.k8sNotFoundError()),
1189+
s.mockStatefulSets.EXPECT().Create(statefulSetArg).Times(1).
1190+
Return(nil, nil),
1191+
)
1192+
1193+
params := &caas.ServiceParams{
1194+
PodSpec: getBasicPodspec(),
1195+
Deployment: caas.DeploymentParams{
1196+
DeploymentType: caas.DeploymentStateful,
1197+
},
1198+
}
1199+
err = s.broker.EnsureService("app-name", nil, params, 2, application.ConfigAttributes{
1200+
"kubernetes-service-loadbalancer-ip": "10.0.0.1",
1201+
"kubernetes-service-externalname": "ext-name",
1202+
})
1203+
c.Assert(err, jc.ErrorIsNil)
1204+
}
1205+
1206+
func (s *K8sBrokerSuite) TestEnsureServiceCustomType(c *gc.C) {
1207+
ctrl := s.setupController(c)
1208+
defer ctrl.Finish()
1209+
1210+
unitSpec, err := provider.MakeUnitSpec("app-name", "app-name", getBasicPodspec())
1211+
c.Assert(err, jc.ErrorIsNil)
1212+
podSpec := provider.PodSpec(unitSpec)
1213+
1214+
numUnits := int32(2)
1215+
statefulSetArg := &appsv1.StatefulSet{
1216+
ObjectMeta: v1.ObjectMeta{
1217+
Name: "app-name",
1218+
Annotations: map[string]string{
1219+
"juju-app-uuid": "appuuid",
1220+
},
1221+
},
1222+
Spec: appsv1.StatefulSetSpec{
1223+
Replicas: &numUnits,
1224+
Selector: &v1.LabelSelector{
1225+
MatchLabels: map[string]string{"juju-app": "app-name"},
1226+
},
1227+
Template: core.PodTemplateSpec{
1228+
ObjectMeta: v1.ObjectMeta{
1229+
Labels: map[string]string{"juju-app": "app-name"},
1230+
Annotations: map[string]string{
1231+
"apparmor.security.beta.kubernetes.io/pod": "runtime/default",
1232+
"seccomp.security.beta.kubernetes.io/pod": "docker/default",
1233+
},
1234+
},
1235+
Spec: podSpec,
1236+
},
1237+
PodManagementPolicy: apps.ParallelPodManagement,
1238+
ServiceName: "app-name-endpoints",
1239+
},
1240+
}
1241+
11661242
serviceArg := *basicServiceArg
11671243
serviceArg.Spec.Type = core.ServiceTypeExternalName
11681244
gomock.InOrder(
@@ -1193,8 +1269,7 @@ func (s *K8sBrokerSuite) TestEnsureServiceNoStorageStateful(c *gc.C) {
11931269
params := &caas.ServiceParams{
11941270
PodSpec: getBasicPodspec(),
11951271
Deployment: caas.DeploymentParams{
1196-
DeploymentType: caas.DeploymentStateful,
1197-
ServiceType: caas.ServiceExternal,
1272+
ServiceType: caas.ServiceExternal,
11981273
},
11991274
}
12001275
err = s.broker.EnsureService("app-name", nil, params, 2, application.ConfigAttributes{

caas/kubernetes/provider/provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (p kubernetesEnvironProvider) Open(args environs.OpenParams) (caas.Broker,
106106
return nil, errors.Trace(err)
107107
}
108108
broker, err := newK8sBroker(
109-
args.ControllerUUID, k8sRestConfig, args.Config, newK8sClient, newKubernetesWatcher, jujuclock.WallClock,
109+
args.ControllerUUID, k8sRestConfig, args.Config, newK8sClient, newKubernetesWatcher, randomPrefix, jujuclock.WallClock,
110110
)
111111
if err != nil {
112112
return nil, err

cloud/fallback-public-cloud.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,19 @@ clouds:
214214
francecentral:
215215
endpoint: https://management.azure.com
216216
storage-endpoint: https://core.windows.net
217-
identity-endpoint: https://graph.windows.net
217+
identity-endpoint: https://graph.windows.net
218+
francesouth:
219+
endpoint: https://management.azure.com
220+
storage-endpoint: https://core.windows.net
221+
identity-endpoint: https://graph.windows.net
222+
southafricanorth:
223+
endpoint: https://management.azure.com
224+
storage-endpoint: https://core.windows.net
225+
identity-endpoint: https://graph.windows.net
226+
southafricawest:
227+
endpoint: https://management.azure.com
228+
storage-endpoint: https://core.windows.net
229+
identity-endpoint: https://graph.windows.net
218230
azure-china:
219231
type: azure
220232
description: Microsoft Azure China

cloud/fallback_public_cloud.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,19 @@ clouds:
221221
francecentral:
222222
endpoint: https://management.azure.com
223223
storage-endpoint: https://core.windows.net
224-
identity-endpoint: https://graph.windows.net
224+
identity-endpoint: https://graph.windows.net
225+
francesouth:
226+
endpoint: https://management.azure.com
227+
storage-endpoint: https://core.windows.net
228+
identity-endpoint: https://graph.windows.net
229+
southafricanorth:
230+
endpoint: https://management.azure.com
231+
storage-endpoint: https://core.windows.net
232+
identity-endpoint: https://graph.windows.net
233+
southafricawest:
234+
endpoint: https://management.azure.com
235+
storage-endpoint: https://core.windows.net
236+
identity-endpoint: https://graph.windows.net
225237
azure-china:
226238
type: azure
227239
description: Microsoft Azure China
@@ -327,5 +339,4 @@ clouds:
327339
endpoint: https://compute.em2.oraclecloud.com
328340
em3:
329341
endpoint: https://compute.em3.oraclecloud.com
330-
331342
`

cmd/juju/cloud/regions_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,5 +224,8 @@ func (s *regionsSuite) TestListRegionsJson(c *gc.C) {
224224
"koreacentral": {Endpoint: "https://management.azure.com", IdentityEndpoint: "https://graph.windows.net", StorageEndpoint: "https://core.windows.net"},
225225
"koreasouth": {Endpoint: "https://management.azure.com", IdentityEndpoint: "https://graph.windows.net", StorageEndpoint: "https://core.windows.net"},
226226
"francecentral": {Endpoint: "https://management.azure.com", IdentityEndpoint: "https://graph.windows.net", StorageEndpoint: "https://core.windows.net"},
227+
"francesouth": {Endpoint: "https://management.azure.com", IdentityEndpoint: "https://graph.windows.net", StorageEndpoint: "https://core.windows.net"},
228+
"southafricanorth": {Endpoint: "https://management.azure.com", IdentityEndpoint: "https://graph.windows.net", StorageEndpoint: "https://core.windows.net"},
229+
"southafricawest": {Endpoint: "https://management.azure.com", IdentityEndpoint: "https://graph.windows.net", StorageEndpoint: "https://core.windows.net"},
227230
})
228231
}

provider/azure/environ.go

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net/http"
1010
"net/url"
1111
"sort"
12+
"strconv"
1213
"strings"
1314
"sync"
1415
"time"
@@ -1775,22 +1776,72 @@ func (env *azureEnviron) getInstanceTypesLocked(ctx context.ProviderCallContext)
17751776
return env.instanceTypes, nil
17761777
}
17771778

1778-
location := env.location
1779-
client := compute.VirtualMachineSizesClient{env.compute}
1779+
client := compute.ResourceSkusClient{env.compute}
17801780

1781-
result, err := client.List(stdcontext.Background(), location)
1781+
res, err := client.ListComplete(stdcontext.Background())
17821782
if err != nil {
17831783
return nil, errorutils.HandleCredentialError(errors.Annotate(err, "listing VM sizes"), ctx)
17841784
}
17851785
instanceTypes := make(map[string]instances.InstanceType)
1786-
if result.Value != nil {
1787-
for _, size := range *result.Value {
1788-
instanceType := newInstanceType(size)
1789-
instanceTypes[instanceType.Name] = instanceType
1790-
// Create aliases for standard role sizes.
1791-
if strings.HasPrefix(instanceType.Name, "Standard_") {
1792-
instanceTypes[instanceType.Name[len("Standard_"):]] = instanceType
1786+
sdkCtx := stdcontext.Background()
1787+
for ; res.NotDone(); err = res.NextWithContext(sdkCtx) {
1788+
if err != nil {
1789+
return nil, errors.Annotate(err, "listing resources")
1790+
}
1791+
resource := res.Value()
1792+
if resource.ResourceType == nil || *resource.ResourceType != "virtualMachines" {
1793+
continue
1794+
}
1795+
if resource.Restrictions != nil {
1796+
for _, r := range *resource.Restrictions {
1797+
if r.ReasonCode == compute.NotAvailableForSubscription {
1798+
continue
1799+
}
1800+
}
1801+
}
1802+
locationOk := false
1803+
if resource.Locations != nil {
1804+
for _, loc := range *resource.Locations {
1805+
if strings.ToLower(loc) == env.location {
1806+
locationOk = true
1807+
break
1808+
}
1809+
}
1810+
}
1811+
if !locationOk {
1812+
continue
1813+
}
1814+
var (
1815+
cores *int32
1816+
mem *int32
1817+
rootDisk *int32
1818+
)
1819+
for _, capability := range *resource.Capabilities {
1820+
if capability.Name == nil || capability.Value == nil {
1821+
continue
17931822
}
1823+
switch *capability.Name {
1824+
case "MemoryGB":
1825+
memValue, _ := strconv.ParseFloat(*capability.Value, 32)
1826+
mem = to.Int32Ptr(int32(1024 * memValue))
1827+
case "vCPUsAvailable", "vCPUs":
1828+
coresValue, _ := strconv.Atoi(*capability.Value)
1829+
cores = to.Int32Ptr(int32(coresValue))
1830+
case "OSVhdSizeMB":
1831+
rootDiskValue, _ := strconv.Atoi(*capability.Value)
1832+
rootDisk = to.Int32Ptr(int32(rootDiskValue))
1833+
}
1834+
}
1835+
instanceType := newInstanceType(compute.VirtualMachineSize{
1836+
Name: resource.Name,
1837+
NumberOfCores: cores,
1838+
OsDiskSizeInMB: rootDisk,
1839+
MemoryInMB: mem,
1840+
})
1841+
instanceTypes[instanceType.Name] = instanceType
1842+
// Create aliases for standard role sizes.
1843+
if strings.HasPrefix(instanceType.Name, "Standard_") {
1844+
instanceTypes[instanceType.Name[len("Standard_"):]] = instanceType
17941845
}
17951846
}
17961847
env.instanceTypes = instanceTypes

0 commit comments

Comments
 (0)