Skip to content
This repository was archived by the owner on Jul 2, 2025. It is now read-only.

Commit d4d623f

Browse files
committed
first draft of vmop support
1 parent ad65793 commit d4d623f

File tree

857 files changed

+87680
-13879
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

857 files changed

+87680
-13879
lines changed

.ci/check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ go install -mod=vendor golang.org/x/lint/golint
2323
export GOFLAGS=-mod=vendor
2424

2525
###############################################################################
26-
PACKAGES="$(go list -e ./... | grep -vE '/vendor/|/internal/flags')"
26+
PACKAGES="$(go list -e ./... | grep -vE '/vendor/|/internal/vmomi/flags')"
2727
PACKAGES_DIRS="$(echo ${PACKAGES} | sed "s|github.com/gardener/machine-controller-manager-provider-vsphere|.|g")"
2828

2929
# Execute static code checks.

go.mod

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,28 @@ go 1.15
44

55
require (
66
github.com/gardener/machine-controller-manager v0.39.0
7-
github.com/onsi/ginkgo v1.15.2
8-
github.com/onsi/gomega v1.11.0
7+
github.com/onsi/ginkgo v1.16.4
8+
github.com/onsi/gomega v1.13.0
99
github.com/pkg/errors v0.9.1
10-
github.com/prometheus/client_golang v1.5.1 // indirect
1110
github.com/spf13/pflag v1.0.5
12-
github.com/stretchr/testify v1.5.1 // indirect
11+
github.com/vmware-tanzu/vm-operator-api v0.1.4-0.20210722184632-99fee0b6197e
1312
github.com/vmware/govmomi v0.22.1
14-
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f
15-
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb
16-
k8s.io/api v0.16.8
17-
k8s.io/component-base v0.16.8
18-
k8s.io/klog v1.0.0
13+
golang.org/x/lint v0.0.0-20200302205851-738671d3881b
14+
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
15+
k8s.io/api v0.17.11
16+
k8s.io/apimachinery v0.17.11
17+
k8s.io/client-go v0.17.11
18+
k8s.io/component-base v0.17.11
19+
k8s.io/klog/v2 v2.9.0
20+
sigs.k8s.io/controller-runtime v0.5.10
1921
sigs.k8s.io/yaml v1.2.0
2022
)
2123

2224
replace (
23-
github.com/prometheus/client_golang => github.com/prometheus/client_golang v0.9.2
24-
k8s.io/api => k8s.io/api v0.16.8 // v0.16.8
25-
k8s.io/apimachinery => k8s.io/apimachinery v0.16.8 // v0.16.8
26-
k8s.io/apiserver => k8s.io/apiserver v0.16.8 // v0.16.8
27-
k8s.io/client-go => k8s.io/client-go v0.16.8 // v0.16.8
28-
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.16.8 // v0.16.8
29-
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf
25+
github.com/prometheus/client_golang => github.com/prometheus/client_golang v0.9.2 // keep this value in sync with sigs.k8s.io/controller-runtime k8s.io/api => k8s.io/api v0.17.11
26+
k8s.io/apimachinery => k8s.io/apimachinery v0.17.11
27+
k8s.io/apiserver => k8s.io/apiserver v0.17.11
28+
k8s.io/client-go => k8s.io/client-go v0.17.11
29+
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.17.11
30+
k8s.io/kube-openapi => github.com/gardener/kube-openapi v0.0.0-20200807191151-9232ec702af2
3031
)

go.sum

Lines changed: 239 additions & 60 deletions
Large diffs are not rendered by default.

pkg/vsphere/apis/provider_spec.go

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,22 @@ const (
2323
TagMCMClusterName = "mcm.gardener.cloud/cluster"
2424
// TagMCMRole is the tag key for tagging a VM with its role (e.g 'node')
2525
TagMCMRole = "mcm.gardener.cloud/role"
26+
27+
// LabelMCMVSphere is the tag key for labeling a VM as a managed machine
28+
LabelMCMVSphere = "mcm.gardener.cloud/machine"
29+
30+
// VSphereKubeconfig is the key for the kubeconfig in the credentials secret
31+
VSphereKubeconfig = "vsphereKubeconfig"
2632
)
2733

28-
// VsphereProviderSpec contains the fields of
34+
// VsphereProviderSpec is an interface to hide the concrete spec version
35+
type VsphereProviderSpec interface {
36+
SpecVersion() int
37+
}
38+
39+
// VsphereProviderSpec1 contains the fields of
2940
// provider spec that the plugin expects
30-
type VsphereProviderSpec struct {
41+
type VsphereProviderSpec1 struct {
3142
// Region is the vSphere region
3243
Region string `json:"region"`
3344

@@ -98,6 +109,62 @@ type VsphereProviderSpec struct {
98109
Tags map[string]string `json:"tags,omitempty"`
99110
}
100111

112+
// SpecVersion returns spec version
113+
func (s *VsphereProviderSpec1) SpecVersion() int { return 1 }
114+
115+
// VsphereProviderSpec2 contains the fields of
116+
// provider spec that the plugin expects
117+
type VsphereProviderSpec2 struct {
118+
// Namespace is the vSphere workload namespace
119+
Namespace string `json:"namespace"`
120+
121+
// ImageName describes the name of a VirtualMachineImage that is to be used as the base Operating System image of
122+
// the desired VirtualMachine instances. The VirtualMachineImage resources can be introspected to discover identifying
123+
// attributes that may help users to identify the desired image to use.
124+
ImageName string `json:"imageName"`
125+
126+
// ClassName describes the name of a VirtualMachineClass that is to be used as the overlaid resource configuration
127+
// of VirtualMachine. A VirtualMachineClass is used to further customize the attributes of the VirtualMachine
128+
// instance. See VirtualMachineClass for more description.
129+
ClassName string `json:"className"`
130+
131+
// NetworkName is the name of the network for the virtualmachines.vmoperator.vmware.com resource
132+
NetworkName string `json:"networkName"`
133+
// NetworkType is the type of the network for the virtualmachines.vmoperator.vmware.com resource
134+
NetworkType string `json:"networkType"`
135+
136+
// StorageClass describes the name of a StorageClass that should be used to configure storage-related attributes of the VirtualMachine
137+
// instance.
138+
// +optional
139+
StorageClass *string `json:"storageClass,omitempty"`
140+
141+
// ResourcePolicyName describes the name of a VirtualMachineSetResourcePolicy to be used when creating the
142+
// VirtualMachine instance.
143+
// +optional
144+
ResourcePolicyName *string `json:"resourcePolicyName,omitempty"`
145+
146+
// TODO
147+
// SystemDisk specifies the system disk
148+
// +optional
149+
//SystemDisk *VSphereSystemDisk `json:"systemDisk,omitempty"`
150+
151+
// TODO
152+
// ExtraConfig allows to specify additional VM options.
153+
// e.g. sched.swap.vmxSwapEnabled=false to disable the VMX process swap file
154+
// +optional
155+
//ExtraConfig map[string]string `json:"extraConfig,omitempty"`
156+
157+
// SSHKeys is an optional array of ssh public keys to deploy to VM (may already be included in UserData)
158+
// +optional
159+
SSHKeys []string `json:"sshKeys,omitempty"`
160+
// Tags to be placed on the VM
161+
// +optional
162+
Tags map[string]string `json:"tags,omitempty"`
163+
}
164+
165+
// SpecVersion returns spec version
166+
func (s *VsphereProviderSpec2) SpecVersion() int { return 2 }
167+
101168
// VSphereSystemDisk specifies system disk of a machine
102169
type VSphereSystemDisk struct {
103170
// Size is disk size in GB

pkg/vsphere/apis/validation/validation.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import (
2525
corev1 "k8s.io/api/core/v1"
2626
)
2727

28-
// ValidateVsphereProviderSpec validates Vsphere provider spec
29-
func ValidateVsphereProviderSpec(spec *api.VsphereProviderSpec, secrets *corev1.Secret) []error {
28+
// ValidateVsphereProviderSpec1 validates Vsphere provider spec
29+
func ValidateVsphereProviderSpec1(spec *api.VsphereProviderSpec1, secrets *corev1.Secret) []error {
3030
var allErrs []error
3131

3232
if "" == spec.Datastore && "" == spec.DatastoreCluster {
@@ -76,3 +76,50 @@ func validateSecrets(secret *corev1.Secret) []error {
7676

7777
return allErrs
7878
}
79+
80+
// ValidateVsphereProviderSpec2 validates Vsphere provider spec2
81+
func ValidateVsphereProviderSpec2(spec *api.VsphereProviderSpec2, secrets *corev1.Secret) []error {
82+
var allErrs []error
83+
84+
if "" == spec.Namespace {
85+
allErrs = append(allErrs, fmt.Errorf("namespace is a required field"))
86+
}
87+
if "" == spec.ImageName {
88+
allErrs = append(allErrs, fmt.Errorf("imageName is a required field"))
89+
}
90+
if "" == spec.NetworkType {
91+
allErrs = append(allErrs, fmt.Errorf("networkType is a required field"))
92+
}
93+
if "" == spec.NetworkName {
94+
allErrs = append(allErrs, fmt.Errorf("networkName is a required field"))
95+
}
96+
if "" == spec.ClassName {
97+
allErrs = append(allErrs, fmt.Errorf("className is a required field"))
98+
}
99+
100+
allErrs = append(allErrs, validateSecrets2(secrets)...)
101+
_, tagErrs := tags.NewRelevantTags(spec.Tags)
102+
allErrs = append(allErrs, tagErrs...)
103+
104+
return allErrs
105+
}
106+
107+
func validateSecrets2(secret *corev1.Secret) []error {
108+
var allErrs []error
109+
110+
if secret == nil {
111+
allErrs = append(allErrs, fmt.Errorf("Secret object that has been passed by the MCM is nil"))
112+
} else {
113+
_, kubeconfigExists := secret.Data[api.VSphereKubeconfig]
114+
_, userDataExists := secret.Data["userData"]
115+
116+
if !kubeconfigExists {
117+
allErrs = append(allErrs, fmt.Errorf("Secret %s is required field", api.VSphereKubeconfig))
118+
}
119+
if !userDataExists {
120+
allErrs = append(allErrs, fmt.Errorf("Secret userData is required field"))
121+
}
122+
}
123+
124+
return allErrs
125+
}

pkg/vsphere/errors/errors.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,15 @@ import "fmt"
2323
type MachineNotFoundError struct {
2424
// Name is the machine name
2525
Name string
26-
// MachineID is the machine uuid
26+
// MachineID is the machine uuid (only used for spec1)
2727
MachineID string
28+
// Namespace is namespace (only used for spec2)
29+
Namespace string
2830
}
2931

3032
func (e *MachineNotFoundError) Error() string {
33+
if e.Namespace != "" {
34+
return fmt.Sprintf("machine %s/%s not found", e.Namespace, e.Name)
35+
}
3136
return fmt.Sprintf("machine name=%s, uuid=%s not found", e.Name, e.MachineID)
3237
}

pkg/vsphere/fake/plugin_spi_impl.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,26 @@ import (
3131
type PluginSPIImpl struct{}
3232

3333
// CreateMachine creates a VM by cloning from a template
34-
func (spi *PluginSPIImpl) CreateMachine(ctx context.Context, machineName string, providerSpec *api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
34+
func (spi *PluginSPIImpl) CreateMachine(ctx context.Context, machineName string, providerSpec api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
3535
return "", fmt.Errorf("fake not implemented yet")
3636
}
3737

3838
// DeleteMachine deletes a VM by name
39-
func (spi *PluginSPIImpl) DeleteMachine(ctx context.Context, machineName string, providerID string, providerSpec *api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
39+
func (spi *PluginSPIImpl) DeleteMachine(ctx context.Context, machineName string, providerID string, providerSpec api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
4040
return "", fmt.Errorf("fake not implemented yet")
4141
}
4242

4343
// ShutDownMachine shuts down a machine by name
44-
func (spi *PluginSPIImpl) ShutDownMachine(ctx context.Context, machineName string, providerID string, providerSpec *api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
44+
func (spi *PluginSPIImpl) ShutDownMachine(ctx context.Context, machineName string, providerID string, providerSpec api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
4545
return "", fmt.Errorf("fake not implemented yet")
4646
}
4747

4848
// GetMachineStatus checks for existence of VM by name
49-
func (spi *PluginSPIImpl) GetMachineStatus(ctx context.Context, machineName string, providerID string, providerSpec *api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
49+
func (spi *PluginSPIImpl) GetMachineStatus(ctx context.Context, machineName string, providerID string, providerSpec api.VsphereProviderSpec, secrets *corev1.Secret) (string, error) {
5050
return "", fmt.Errorf("fake not implemented yet")
5151
}
5252

5353
// ListMachines lists all VMs in the DC or folder
54-
func (spi *PluginSPIImpl) ListMachines(ctx context.Context, providerSpec *api.VsphereProviderSpec, secrets *corev1.Secret) (map[string]string, error) {
54+
func (spi *PluginSPIImpl) ListMachines(ctx context.Context, providerSpec api.VsphereProviderSpec, secrets *corev1.Secret) (map[string]string, error) {
5555
return nil, fmt.Errorf("fake not implemented yet")
5656
}

pkg/vsphere/integration/integration_test.go

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ import (
3333
// TODO: Update secret field from api.Secrets to corev1.Secret in integration tests
3434

3535
type integrationConfig struct {
36-
MachineName string `json:"machineName"`
37-
ProviderSpec *api.VsphereProviderSpec `json:"providerSpec"`
38-
Secrets *corev1.Secret `json:"secrets"`
36+
MachineName string `json:"machineName"`
37+
ProviderSpec *api.VsphereProviderSpec1 `json:"providerSpec"`
38+
ProviderSpec2 *api.VsphereProviderSpec2 `json:"providerSpec2"`
39+
Secrets *corev1.Secret `json:"secrets"`
3940
}
4041

4142
// TestPluginSPIImpl tests creation and deleting of a VM via vSphere API.
@@ -60,10 +61,20 @@ func TestPluginSPIImpl(t *testing.T) {
6061
return
6162
}
6263

63-
spi := &internal.PluginSPIImpl{}
64+
var providerSpec api.VsphereProviderSpec
65+
if cfg.ProviderSpec != nil {
66+
providerSpec = cfg.ProviderSpec
67+
} else if cfg.ProviderSpec2 != nil {
68+
providerSpec = cfg.ProviderSpec2
69+
} else {
70+
t.Errorf("neither field 'providerSpec' nor 'providerSpec2' set in integrationConfig from %s", configPath)
71+
return
72+
}
73+
74+
spi := &internal.PluginSPISwitch{}
6475
ctx := context.TODO()
6576

66-
providerID, err := spi.GetMachineStatus(ctx, cfg.MachineName, "", cfg.ProviderSpec, cfg.Secrets)
77+
providerID, err := spi.GetMachineStatus(ctx, cfg.MachineName, "", providerSpec, cfg.Secrets)
6778
if err == nil {
6879
t.Errorf("Machine name %s already existing", cfg.MachineName)
6980
return
@@ -76,7 +87,7 @@ func TestPluginSPIImpl(t *testing.T) {
7687
return
7788
}
7889

79-
providerID, err = spi.DeleteMachine(ctx, cfg.MachineName, providerID, cfg.ProviderSpec, cfg.Secrets)
90+
providerID, err = spi.DeleteMachine(ctx, cfg.MachineName, providerID, providerSpec, cfg.Secrets)
8091
switch err.(type) {
8192
case *errors.MachineNotFoundError:
8293
// expected
@@ -85,13 +96,13 @@ func TestPluginSPIImpl(t *testing.T) {
8596
return
8697
}
8798

88-
providerID, err = spi.CreateMachine(ctx, cfg.MachineName, cfg.ProviderSpec, cfg.Secrets)
99+
providerID, err = spi.CreateMachine(ctx, cfg.MachineName, providerSpec, cfg.Secrets)
89100
if err != nil {
90101
t.Errorf("CreateMachine failed with %s", err)
91102
return
92103
}
93104

94-
providerID2, err := spi.GetMachineStatus(ctx, cfg.MachineName, "", cfg.ProviderSpec, cfg.Secrets)
105+
providerID2, err := spi.GetMachineStatus(ctx, cfg.MachineName, "", providerSpec, cfg.Secrets)
95106
if err != nil {
96107
t.Errorf("GetMachineStatus by machine name failed with %s", err)
97108
return
@@ -100,7 +111,7 @@ func TestPluginSPIImpl(t *testing.T) {
100111
t.Errorf("ProviderID mismatch %s != %s", providerID, providerID2)
101112
}
102113

103-
providerID2, err = spi.GetMachineStatus(ctx, cfg.MachineName, providerID, cfg.ProviderSpec, cfg.Secrets)
114+
providerID2, err = spi.GetMachineStatus(ctx, cfg.MachineName, providerID, providerSpec, cfg.Secrets)
104115
if err != nil {
105116
t.Errorf("GetMachineStatus by providerID failed with %s", err)
106117
return
@@ -109,7 +120,7 @@ func TestPluginSPIImpl(t *testing.T) {
109120
t.Errorf("ProviderID mismatch %s != %s", providerID, providerID2)
110121
}
111122

112-
providerIDList, err := spi.ListMachines(ctx, cfg.ProviderSpec, cfg.Secrets)
123+
providerIDList, err := spi.ListMachines(ctx, providerSpec, cfg.Secrets)
113124
if err != nil {
114125
t.Errorf("ListMachines failed with %s", err)
115126
}
@@ -127,15 +138,15 @@ func TestPluginSPIImpl(t *testing.T) {
127138
t.Errorf("Created machine with ID %s not found", providerID)
128139
}
129140

130-
providerID2, err = spi.ShutDownMachine(ctx, cfg.MachineName, providerID, cfg.ProviderSpec, cfg.Secrets)
141+
providerID2, err = spi.ShutDownMachine(ctx, cfg.MachineName, providerID, providerSpec, cfg.Secrets)
131142
if err != nil {
132143
t.Errorf("ShutDownMachine failed with %s", err)
133144
}
134145
if providerID != providerID2 {
135146
t.Errorf("ProviderID mismatch %s != %s", providerID, providerID2)
136147
}
137148

138-
providerID2, err = spi.DeleteMachine(ctx, cfg.MachineName, providerID, cfg.ProviderSpec, cfg.Secrets)
149+
providerID2, err = spi.DeleteMachine(ctx, cfg.MachineName, providerID, providerSpec, cfg.Secrets)
139150
if err != nil {
140151
t.Errorf("DeleteMachine failed with %s", err)
141152
}

0 commit comments

Comments
 (0)