Skip to content

Commit 1e25af6

Browse files
authored
feat(hatchery/openstack): check flavor (#5148)
* fix(hatchery/openstack): check flavor Signed-off-by: Yvonnick Esnault <[email protected]>
1 parent dfc8535 commit 1e25af6

File tree

6 files changed

+96
-23
lines changed

6 files changed

+96
-23
lines changed

engine/hatchery/openstack/get.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func (h *HatcheryOpenstack) getServers(ctx context.Context) []servers.Server {
125125
if !worker {
126126
continue
127127
}
128-
workerHatcheryName, _ := s.Metadata["hatchery_name"]
128+
workerHatcheryName := s.Metadata["hatchery_name"]
129129
if workerHatcheryName == "" || workerHatcheryName != h.Name() {
130130
continue
131131
}

engine/hatchery/openstack/init.go

+14-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
1010
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
1111

12+
"github.com/ovh/cds/sdk"
1213
"github.com/ovh/cds/sdk/log"
1314
)
1415

@@ -27,27 +28,27 @@ func (h *HatcheryOpenstack) InitHatchery(ctx context.Context) error {
2728
DomainName: h.Config.Domain,
2829
}
2930

30-
provider, errac := openstack.AuthenticatedClient(authOpts)
31-
if errac != nil {
32-
return fmt.Errorf("Unable to openstack.AuthenticatedClient: %v", errac)
31+
provider, err := openstack.AuthenticatedClient(authOpts)
32+
if err != nil {
33+
return sdk.WithStack(fmt.Errorf("unable to openstack.AuthenticatedClient: %v", err))
3334
}
3435

35-
openstackClient, errn := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{Region: h.Config.Region})
36-
if errn != nil {
37-
return fmt.Errorf("Unable to openstack.NewComputeV2: %s", errn)
36+
openstackClient, err := openstack.NewComputeV2(provider, gophercloud.EndpointOpts{Region: h.Config.Region})
37+
if err != nil {
38+
return sdk.WithStack(fmt.Errorf("unable to openstack.NewComputeV2: %v", err))
3839
}
3940
h.openstackClient = openstackClient
4041

4142
if err := h.initFlavors(); err != nil {
42-
log.Warning(ctx, "Error getting flavors: %s", err)
43+
log.Warning(ctx, "Error getting flavors: %v", err)
4344
}
4445

4546
if err := h.initNetworks(); err != nil {
46-
log.Warning(ctx, "Error getting networks: %s", err)
47+
log.Warning(ctx, "Error getting networks: %v", err)
4748
}
4849

4950
if err := h.initIPStatus(ctx); err != nil {
50-
log.Warning(ctx, "Error on initIPStatus(): %s", err)
51+
log.Warning(ctx, "Error on initIPStatus(): %v", err)
5152
}
5253

5354
go h.main(ctx)
@@ -58,11 +59,11 @@ func (h *HatcheryOpenstack) InitHatchery(ctx context.Context) error {
5859
func (h *HatcheryOpenstack) initFlavors() error {
5960
all, err := flavors.ListDetail(h.openstackClient, nil).AllPages()
6061
if err != nil {
61-
return fmt.Errorf("initFlavors> error on flavors.ListDetail: %s", err)
62+
return sdk.WithStack(fmt.Errorf("initFlavors> error on flavors.ListDetail: %v", err))
6263
}
6364
lflavors, err := flavors.ExtractFlavors(all)
6465
if err != nil {
65-
return fmt.Errorf("initFlavors> error on flavors.ExtractFlavors: %s", err)
66+
return sdk.WithStack(fmt.Errorf("initFlavors> error on flavors.ExtractFlavors: %v", err))
6667
}
6768
h.flavors = lflavors
6869
return nil
@@ -71,11 +72,11 @@ func (h *HatcheryOpenstack) initFlavors() error {
7172
func (h *HatcheryOpenstack) initNetworks() error {
7273
all, err := tenantnetworks.List(h.openstackClient).AllPages()
7374
if err != nil {
74-
return fmt.Errorf("initNetworks> Unable to get Network: %s", err)
75+
return sdk.WithStack(fmt.Errorf("initNetworks> Unable to get Network: %v", err))
7576
}
7677
nets, err := tenantnetworks.ExtractNetworks(all)
7778
if err != nil {
78-
return fmt.Errorf("initNetworks> Unable to get Network: %s", err)
79+
return sdk.WithStack(fmt.Errorf("initNetworks> Unable to get Network: %v", err))
7980
}
8081
for _, n := range nets {
8182
if n.Name == h.Config.NetworkString {

engine/hatchery/openstack/openstack.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ func (h *HatcheryOpenstack) WorkerModelsEnabled() ([]sdk.Model, error) {
157157
// CanSpawn return wether or not hatchery can spawn model
158158
// requirements are not supported
159159
func (h *HatcheryOpenstack) CanSpawn(ctx context.Context, model *sdk.Model, jobID int64, requirements []sdk.Requirement) bool {
160+
// if there is a model, we have to check if the flavor attached to model is knowned by this hatchery
161+
if model != nil {
162+
if _, err := h.flavorID(model.ModelVirtualMachine.Flavor); err != nil {
163+
log.Debug("CanSpawn> h.flavorID on %s err:%v", model.ModelVirtualMachine.Flavor, err)
164+
return false
165+
}
166+
log.Debug("CanSpawn> flavor '%s' found", model.ModelVirtualMachine.Flavor)
167+
}
168+
160169
for _, r := range requirements {
161170
if r.Type == sdk.ServiceRequirement || r.Type == sdk.MemoryRequirement || r.Type == sdk.HostnameRequirement {
162171
return false
@@ -297,7 +306,7 @@ func (h *HatcheryOpenstack) killAwolServers(ctx context.Context) {
297306
func (h *HatcheryOpenstack) killAwolServersComputeImage(ctx context.Context, workerModelName, workerModelNameLastModified, serverID, model, flavor string) {
298307
oldImagesID := []string{}
299308
for _, img := range h.getImages(ctx) {
300-
if w, _ := img.Metadata["worker_model_name"]; w == workerModelName {
309+
if w := img.Metadata["worker_model_name"]; w == workerModelName {
301310
oldImagesID = append(oldImagesID, img.ID)
302311
if d, ok := img.Metadata["worker_model_last_modified"]; ok && d.(string) == workerModelNameLastModified {
303312
// no need to recreate an image
@@ -460,8 +469,7 @@ func (h *HatcheryOpenstack) NeedRegistration(ctx context.Context, m *sdk.Model)
460469
return true
461470
}
462471
for _, img := range h.getImages(ctx) {
463-
w, _ := img.Metadata["worker_model_name"]
464-
if w == m.Name {
472+
if w := img.Metadata["worker_model_name"]; w == m.Name {
465473
if d, ok := img.Metadata["worker_model_last_modified"]; ok {
466474
if fmt.Sprintf("%d", m.UserLastModified.Unix()) == d.(string) {
467475
log.Debug("NeedRegistration> false. An image is already available for this worker model %s workerModel.UserLastModified", m.Name)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package openstack
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/ovh/cds/sdk"
11+
)
12+
13+
func TestHatcheryOpenstack_CanSpawn(t *testing.T) {
14+
h := &HatcheryOpenstack{}
15+
16+
// no model, no requirement, canSpawn must be true
17+
canSpawn := h.CanSpawn(context.TODO(), nil, 1, nil)
18+
require.True(t, canSpawn)
19+
20+
// no model, service requirement, canSpawn must be false: service can't be managed by openstack hatchery
21+
canSpawn = h.CanSpawn(context.TODO(), nil, 1, []sdk.Requirement{{Name: "pg", Type: sdk.ServiceRequirement, Value: "postgres:9.5.4"}})
22+
require.False(t, canSpawn)
23+
24+
// no model, memory prerequisite, canSpawn must be false: memory prerequisite can't be managed by openstack hatchery
25+
canSpawn = h.CanSpawn(context.TODO(), nil, 1, []sdk.Requirement{{Name: "mem", Type: sdk.MemoryRequirement, Value: "4096"}})
26+
require.False(t, canSpawn)
27+
28+
// no model, hostname prerequisite, canSpawn must be false: hostname can't be managed by openstack hatchery
29+
canSpawn = h.CanSpawn(context.TODO(), nil, 1, []sdk.Requirement{{Type: sdk.HostnameRequirement, Value: "localhost"}})
30+
require.False(t, canSpawn)
31+
32+
flavors := []flavors.Flavor{
33+
{Name: "b2-7"},
34+
}
35+
h.flavors = flavors
36+
37+
m := &sdk.Model{
38+
ID: 1,
39+
Name: "my-model",
40+
Group: &sdk.Group{
41+
ID: 1,
42+
Name: "mygroup",
43+
},
44+
ModelVirtualMachine: sdk.ModelVirtualMachine{
45+
Flavor: "vps-ssd-3",
46+
},
47+
}
48+
49+
// model with a unknowned flavor
50+
canSpawn = h.CanSpawn(context.TODO(), m, 1, nil)
51+
require.False(t, canSpawn)
52+
53+
m = &sdk.Model{
54+
ID: 1,
55+
Name: "my-model",
56+
Group: &sdk.Group{
57+
ID: 1,
58+
Name: "mygroup",
59+
},
60+
ModelVirtualMachine: sdk.ModelVirtualMachine{
61+
Flavor: "b2-7",
62+
},
63+
}
64+
65+
// model with a knowned flavor
66+
canSpawn = h.CanSpawn(context.TODO(), m, 1, nil)
67+
require.True(t, canSpawn)
68+
}

engine/hatchery/openstack/spawn.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ func (h *HatcheryOpenstack) SpawnWorker(ctx context.Context, spawnArgs hatchery.
4848
imgs := h.getImages(ctx)
4949
log.Debug("spawnWorker> call images.List on openstack took %fs, nbImages:%d", time.Since(start).Seconds(), len(imgs))
5050
for _, img := range imgs {
51-
workerModelName, _ := img.Metadata["worker_model_name"]
52-
workerModelLastModified, _ := img.Metadata["worker_model_last_modified"]
51+
workerModelName := img.Metadata["worker_model_name"]
52+
workerModelLastModified := img.Metadata["worker_model_last_modified"]
5353
if workerModelName == spawnArgs.Model.Name && fmt.Sprintf("%s", workerModelLastModified) == fmt.Sprintf("%d", spawnArgs.Model.UserLastModified.Unix()) {
5454
withExistingImage = true
5555
imageID = img.ID

engine/hatchery/openstack/types.go

-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ import (
66
"github.com/ovh/cds/engine/service"
77

88
"github.com/gophercloud/gophercloud"
9-
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
109
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
11-
"github.com/gophercloud/gophercloud/openstack/compute/v2/images"
1210

1311
hatcheryCommon "github.com/ovh/cds/engine/hatchery"
1412
)
@@ -57,8 +55,6 @@ type HatcheryOpenstack struct {
5755
hatcheryCommon.Common
5856
Config HatcheryConfiguration
5957
flavors []flavors.Flavor
60-
networks []tenantnetworks.Network
61-
images []images.Image
6258
openstackClient *gophercloud.ServiceClient
6359

6460
networkID string // computed from networkString

0 commit comments

Comments
 (0)