diff --git a/Gopkg.lock b/Gopkg.lock index 3c339cba762..ab9db620cd5 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -734,9 +734,12 @@ [[projects]] branch = "master" - digest = "1:03edd2a5dd0223f295350eb81a0111ec3418b19c2d0ea8a6bb48537d80ceb2f5" + digest = "1:ddd6281b2d1c35d02c87ec192bec901a40bb93608eab3eef52c3a0a703dbed7b" name = "github.com/openshift/machine-api-operator" - packages = ["pkg/apis/vsphereprovider/v1alpha1"] + packages = [ + "pkg/apis/vsphereprovider", + "pkg/apis/vsphereprovider/v1alpha1", + ] pruneopts = "NUT" revision = "463c63d746da60d953060af0f9846d89d9521105" source = "github.com/openshift/machine-api-operator" @@ -1473,6 +1476,7 @@ "github.com/openshift/cluster-api-provider-ovirt/pkg/apis/ovirtprovider/v1beta1", "github.com/openshift/cluster-api/pkg/apis/machine/v1beta1", "github.com/openshift/library-go/pkg/config/clusteroperator/v1helpers", + "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider", "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1", "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1", "github.com/ovirt/go-ovirt", diff --git a/pkg/asset/cluster/tfvars.go b/pkg/asset/cluster/tfvars.go index b62baca535d..1be19723e61 100644 --- a/pkg/asset/cluster/tfvars.go +++ b/pkg/asset/cluster/tfvars.go @@ -9,6 +9,7 @@ import ( igntypes "github.com/coreos/ignition/config/v2_2/types" gcpprovider "github.com/openshift/cluster-api-provider-gcp/pkg/apis/gcpprovider/v1beta1" libvirtprovider "github.com/openshift/cluster-api-provider-libvirt/pkg/apis/libvirtproviderconfig/v1beta1" + vsphereprovider "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1" "github.com/pkg/errors" "github.com/sirupsen/logrus" awsprovider "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsproviderconfig/v1beta1" @@ -33,6 +34,7 @@ import ( libvirttfvars "github.com/openshift/installer/pkg/tfvars/libvirt" openstacktfvars "github.com/openshift/installer/pkg/tfvars/openstack" ovirttfvars "github.com/openshift/installer/pkg/tfvars/ovirt" + vspheretfvars "github.com/openshift/installer/pkg/tfvars/vsphere" "github.com/openshift/installer/pkg/types" "github.com/openshift/installer/pkg/types/aws" "github.com/openshift/installer/pkg/types/azure" @@ -102,7 +104,7 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { platform := installConfig.Config.Platform.Name() switch platform { - case none.Name, vsphere.Name: + case none.Name: return errors.Errorf("cannot create the cluster because %q is a UPI platform", platform) } @@ -387,6 +389,30 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error { Filename: fmt.Sprintf(TfPlatformVarsFileName, platform), Data: data, }) + case vsphere.Name: + controlPlanes, err := mastersAsset.Machines() + if err != nil { + return err + } + controlPlaneConfigs := make([]*vsphereprovider.VSphereMachineProviderSpec, len(controlPlanes)) + for i, c := range controlPlanes { + controlPlaneConfigs[i] = c.Spec.ProviderSpec.Value.Object.(*vsphereprovider.VSphereMachineProviderSpec) + } + data, err = vspheretfvars.TFVars( + vspheretfvars.TFVarsSources{ + ControlPlaneConfigs: controlPlaneConfigs, + Username: installConfig.Config.VSphere.Username, + Password: installConfig.Config.VSphere.Password, + Cluster: installConfig.Config.VSphere.Cluster, + }, + ) + if err != nil { + return errors.Wrapf(err, "failed to get %s Terraform variables", platform) + } + t.FileList = append(t.FileList, &asset.File{ + Filename: fmt.Sprintf(TfPlatformVarsFileName, platform), + Data: data, + }) default: logrus.Warnf("unrecognized platform %s", platform) } diff --git a/pkg/asset/machines/master.go b/pkg/asset/machines/master.go index e35f33bf410..902d72ab7ae 100644 --- a/pkg/asset/machines/master.go +++ b/pkg/asset/machines/master.go @@ -15,6 +15,8 @@ import ( libvirtprovider "github.com/openshift/cluster-api-provider-libvirt/pkg/apis/libvirtproviderconfig/v1beta1" ovirtprovider "github.com/openshift/cluster-api-provider-ovirt/pkg/apis" machineapi "github.com/openshift/cluster-api/pkg/apis/machine/v1beta1" + vsphereapi "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider" + vsphereprovider "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1" mcfgv1 "github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.openshift.io/v1" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/runtime" @@ -37,6 +39,7 @@ import ( "github.com/openshift/installer/pkg/asset/machines/machineconfig" "github.com/openshift/installer/pkg/asset/machines/openstack" "github.com/openshift/installer/pkg/asset/machines/ovirt" + "github.com/openshift/installer/pkg/asset/machines/vsphere" "github.com/openshift/installer/pkg/asset/rhcos" rhcosutils "github.com/openshift/installer/pkg/rhcos" "github.com/openshift/installer/pkg/types" @@ -304,8 +307,18 @@ func (m *Master) Generate(dependencies asset.Parents) error { if err != nil { return errors.Wrap(err, "failed to create master machine objects for ovirt provider") } + case vspheretypes.Name: + mpool := defaultVSphereMachinePoolPlatform() + mpool.Set(ic.Platform.VSphere.DefaultMachinePlatform) + mpool.Set(pool.Platform.VSphere) + pool.Platform.VSphere = &mpool - case nonetypes.Name, vspheretypes.Name: + machines, err = vsphere.Machines(clusterID.InfraID, ic, pool, string(*rhcosImage), "master", "master-user-data") + if err != nil { + return errors.Wrap(err, "failed to create master machine objects") + } + vsphere.ConfigMasters(machines, clusterID.InfraID) + case nonetypes.Name: default: return fmt.Errorf("invalid Platform") } @@ -420,6 +433,7 @@ func (m *Master) Machines() ([]machineapi.Machine, error) { libvirtapi.AddToScheme(scheme) openstackapi.AddToScheme(scheme) ovirtprovider.AddToScheme(scheme) + vsphereapi.AddToScheme(scheme) decoder := serializer.NewCodecFactory(scheme).UniversalDecoder( awsprovider.SchemeGroupVersion, azureprovider.SchemeGroupVersion, @@ -427,6 +441,7 @@ func (m *Master) Machines() ([]machineapi.Machine, error) { gcpprovider.SchemeGroupVersion, libvirtprovider.SchemeGroupVersion, openstackprovider.SchemeGroupVersion, + vsphereprovider.SchemeGroupVersion, ) machines := []machineapi.Machine{} diff --git a/pkg/asset/machines/vsphere/machines.go b/pkg/asset/machines/vsphere/machines.go new file mode 100644 index 00000000000..d09df4d55fc --- /dev/null +++ b/pkg/asset/machines/vsphere/machines.go @@ -0,0 +1,94 @@ +// Package vsphere generates Machine objects for vsphere. +package vsphere + +import ( + "fmt" + + machineapi "github.com/openshift/cluster-api/pkg/apis/machine/v1beta1" + vsphereapis "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/openshift/installer/pkg/types" + "github.com/openshift/installer/pkg/types/vsphere" +) + +// Machines returns a list of machines for a machinepool. +func Machines(clusterID string, config *types.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string) ([]machineapi.Machine, error) { + if configPlatform := config.Platform.Name(); configPlatform != vsphere.Name { + return nil, fmt.Errorf("non vsphere configuration: %q", configPlatform) + } + if poolPlatform := pool.Platform.Name(); poolPlatform != vsphere.Name { + return nil, fmt.Errorf("non-VSphere machine-pool: %q", poolPlatform) + } + platform := config.Platform.VSphere + mpool := pool.Platform.VSphere + + total := int64(1) + if pool.Replicas != nil { + total = *pool.Replicas + } + var machines []machineapi.Machine + for idx := int64(0); idx < total; idx++ { + provider, err := provider(clusterID, platform, mpool, osImage, userDataSecret) + if err != nil { + return nil, errors.Wrap(err, "failed to create provider") + } + + machine := machineapi.Machine{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "machine.openshift.io/v1beta1", + Kind: "Machine", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "openshift-machine-api", + Name: fmt.Sprintf("%s-%s-%d", clusterID, pool.Name, idx), + Labels: map[string]string{ + "machine.openshift.io/cluster-api-cluster": clusterID, + "machine.openshift.io/cluster-api-machine-role": role, + "machine.openshift.io/cluster-api-machine-type": role, + }, + }, + Spec: machineapi.MachineSpec{ + ProviderSpec: machineapi.ProviderSpec{ + Value: &runtime.RawExtension{Object: provider}, + }, + // we don't need to set Versions, because we control those via operators. + }, + } + machines = append(machines, machine) + } + return machines, nil +} + +func provider(clusterID string, platform *vsphere.Platform, mpool *vsphere.MachinePool, osImage string, userDataSecret string) (*vsphereapis.VSphereMachineProviderSpec, error) { + return &vsphereapis.VSphereMachineProviderSpec{ + TypeMeta: metav1.TypeMeta{ + APIVersion: vsphereapis.SchemeGroupVersion.String(), + Kind: "VSphereMachineProviderSpec", + }, + UserDataSecret: &corev1.LocalObjectReference{Name: userDataSecret}, + CredentialsSecret: &corev1.LocalObjectReference{Name: "vsphere-cloud-credentials"}, + Template: osImage, + Network: vsphereapis.NetworkSpec{ + Devices: []vsphereapis.NetworkDeviceSpec{ + { + NetworkName: platform.Network, + }, + }, + }, + Workspace: &vsphereapis.Workspace{ + Server: platform.VCenter, + Datacenter: platform.Datacenter, + Datastore: platform.DefaultDatastore, + Folder: clusterID, + }, + DiskGiB: mpool.OSDisk.DiskSizeGB, + }, nil +} + +// ConfigMasters sets the PublicIP flag and assigns a set of load balancers to the given machines +func ConfigMasters(machines []machineapi.Machine, clusterID string) { +} diff --git a/pkg/asset/machines/vsphere/machinesets.go b/pkg/asset/machines/vsphere/machinesets.go new file mode 100644 index 00000000000..2ab2b2c93df --- /dev/null +++ b/pkg/asset/machines/vsphere/machinesets.go @@ -0,0 +1,80 @@ +//Package vsphere generates Machine objects for vsphere.package vsphere +package vsphere + +import ( + "fmt" + + machineapi "github.com/openshift/cluster-api/pkg/apis/machine/v1beta1" + "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + + "github.com/openshift/installer/pkg/types" + "github.com/openshift/installer/pkg/types/vsphere" +) + +// MachineSets returns a list of machinesets for a machinepool. +func MachineSets(clusterID string, config *types.InstallConfig, pool *types.MachinePool, osImage, role, userDataSecret string) ([]*machineapi.MachineSet, error) { + if configPlatform := config.Platform.Name(); configPlatform != vsphere.Name { + return nil, fmt.Errorf("non vsphere configuration: %q", configPlatform) + } + if poolPlatform := pool.Platform.Name(); poolPlatform != vsphere.Name { + return nil, fmt.Errorf("non-VSphere machine-pool: %q", poolPlatform) + } + + platform := config.Platform.VSphere + mpool := pool.Platform.VSphere + + total := int32(0) + if pool.Replicas != nil { + total = int32(*pool.Replicas) + } + var machinesets []*machineapi.MachineSet + provider, err := provider(clusterID, platform, mpool, osImage, userDataSecret) + if err != nil { + return nil, errors.Wrap(err, "failed to create provider") + } + + name := fmt.Sprintf("%s-%s", clusterID, pool.Name) + mset := &machineapi.MachineSet{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "machine.openshift.io/v1beta1", + Kind: "MachineSet", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "openshift-machine-api", + Name: name, + Labels: map[string]string{ + "machine.openshift.io/cluster-api-cluster": clusterID, + }, + }, + Spec: machineapi.MachineSetSpec{ + Replicas: &total, + Selector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "machine.openshift.io/cluster-api-machineset": name, + "machine.openshift.io/cluster-api-cluster": clusterID, + }, + }, + Template: machineapi.MachineTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "machine.openshift.io/cluster-api-machineset": name, + "machine.openshift.io/cluster-api-cluster": clusterID, + "machine.openshift.io/cluster-api-machine-role": role, + "machine.openshift.io/cluster-api-machine-type": role, + }, + }, + Spec: machineapi.MachineSpec{ + ProviderSpec: machineapi.ProviderSpec{ + Value: &runtime.RawExtension{Object: provider}, + }, + // we don't need to set Versions, because we control those via cluster operators. + }, + }, + }, + } + machinesets = append(machinesets, mset) + + return machinesets, nil +} diff --git a/pkg/asset/machines/worker.go b/pkg/asset/machines/worker.go index d5a36fb6350..9e8d7696a6d 100644 --- a/pkg/asset/machines/worker.go +++ b/pkg/asset/machines/worker.go @@ -37,6 +37,7 @@ import ( "github.com/openshift/installer/pkg/asset/machines/machineconfig" "github.com/openshift/installer/pkg/asset/machines/openstack" "github.com/openshift/installer/pkg/asset/machines/ovirt" + "github.com/openshift/installer/pkg/asset/machines/vsphere" "github.com/openshift/installer/pkg/asset/rhcos" rhcosutils "github.com/openshift/installer/pkg/rhcos" "github.com/openshift/installer/pkg/types" @@ -108,6 +109,14 @@ func defaultOvirtMachinePoolPlatform() ovirttypes.MachinePool { return ovirttypes.MachinePool{} } +func defaultVSphereMachinePoolPlatform() vspheretypes.MachinePool { + return vspheretypes.MachinePool{ + OSDisk: vspheretypes.OSDisk{ + DiskSizeGB: 120, + }, + } +} + // Worker generates the machinesets for `worker` machine pool. type Worker struct { UserDataFile *asset.File @@ -289,7 +298,20 @@ func (w *Worker) Generate(dependencies asset.Parents) error { sets, err := openstack.MachineSets(clusterID.InfraID, ic, &pool, imageName, "worker", "worker-user-data") if err != nil { - return errors.Wrap(err, "failed to create master machine objects") + return errors.Wrap(err, "failed to create worker machine objects") + } + for _, set := range sets { + machineSets = append(machineSets, set) + } + case vspheretypes.Name: + mpool := defaultVSphereMachinePoolPlatform() + mpool.Set(ic.Platform.VSphere.DefaultMachinePlatform) + mpool.Set(pool.Platform.VSphere) + pool.Platform.VSphere = &mpool + + sets, err := vsphere.MachineSets(clusterID.InfraID, ic, &pool, string(*rhcosImage), "worker", "worker-user-data") + if err != nil { + return errors.Wrap(err, "failed to create worker machine objects") } for _, set := range sets { machineSets = append(machineSets, set) @@ -304,7 +326,7 @@ func (w *Worker) Generate(dependencies asset.Parents) error { for _, set := range sets { machineSets = append(machineSets, set) } - case nonetypes.Name, vspheretypes.Name: + case nonetypes.Name: default: return fmt.Errorf("invalid Platform") } diff --git a/pkg/types/vsphere/machinepool.go b/pkg/types/vsphere/machinepool.go index a2b0363f331..2904b4bb6ed 100644 --- a/pkg/types/vsphere/machinepool.go +++ b/pkg/types/vsphere/machinepool.go @@ -3,6 +3,14 @@ package vsphere // MachinePool stores the configuration for a machine pool installed // on vSphere. type MachinePool struct { + // OSDisk defines the storage for instance. + OSDisk `json:"osDisk"` +} + +// OSDisk defines the disk for a virtual machine. +type OSDisk struct { + // DiskSizeGB defines the size of disk in GB. + DiskSizeGB int32 `json:"diskSizeGB"` } // Set sets the values from `required` to `p`. @@ -10,4 +18,8 @@ func (p *MachinePool) Set(required *MachinePool) { if required == nil || p == nil { return } + + if required.OSDisk.DiskSizeGB != 0 { + p.OSDisk.DiskSizeGB = required.OSDisk.DiskSizeGB + } } diff --git a/pkg/types/vsphere/platform.go b/pkg/types/vsphere/platform.go index b365899d6ff..1c09d2a65a4 100644 --- a/pkg/types/vsphere/platform.go +++ b/pkg/types/vsphere/platform.go @@ -4,25 +4,44 @@ package vsphere type Platform struct { // VCenter is the domain name or IP address of the vCenter. VCenter string `json:"vCenter"` + // Username is the name of the user to use to connect to the vCenter. Username string `json:"username"` + // Password is the password for the user to use to connect to the vCenter. Password string `json:"password"` + // Datacenter is the name of the datacenter to use in the vCenter. Datacenter string `json:"datacenter"` + // DefaultDatastore is the default datastore to use for provisioning volumes. DefaultDatastore string `json:"defaultDatastore"` + // Folder is the name of the folder that will be used and/or created for // virtual machines. Folder string `json:"folder,omitempty"` + // Cluster is the name of the cluster virtual machines will be cloned into. Cluster string `json:"cluster,omitempty"` + // ClusterOSImage overrides the url provided in rhcos.json to download the RHCOS OVA ClusterOSImage string `json:"clusterOSImage,omitempty"` + // APIVIP is the virtual IP address for the api endpoint APIVIP string `json:"apiVIP,omitempty"` + // IngressVIP is the virtual IP address for ingress IngressVIP string `json:"ingressVIP,omitempty"` + // DNSVIP is the virtual IP address for DNS DNSVIP string `json:"dnsVIP,omitempty"` + + // DefaultMachinePlatform is the default configuration used when + // installing on VSphere for machine pools which do not define their own + // platform configuration. + // +optional + DefaultMachinePlatform *MachinePool `json:"defaultMachinePlatform,omitempty"` + + // Network specifies the name of the network to be used by the cluster. + Network string `json:"network,omitempty"` //TODO: determine if this should be omitempty or required } diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/addtoscheme_vsphereprovider_v1alpha1.go b/vendor/github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/addtoscheme_vsphereprovider_v1alpha1.go new file mode 100644 index 00000000000..afc0de9b367 --- /dev/null +++ b/vendor/github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/addtoscheme_vsphereprovider_v1alpha1.go @@ -0,0 +1,10 @@ +package apis + +import ( + "github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/v1alpha1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) +} diff --git a/vendor/github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/apis.go b/vendor/github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/apis.go new file mode 100644 index 00000000000..609a8391cb6 --- /dev/null +++ b/vendor/github.com/openshift/machine-api-operator/pkg/apis/vsphereprovider/apis.go @@ -0,0 +1,17 @@ +// Generate deepcopy for apis +//go:generate go run ../../../vendor/sigs.k8s.io/controller-tools/cmd/controller-gen paths=./... object:headerFile=../../../hack/boilerplate.go.txt,year=2019 + +// Package apis contains Kubernetes API groups. +package apis + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +// AddToSchemes may be used to add all resources defined in the project to a Scheme +var AddToSchemes runtime.SchemeBuilder + +// AddToScheme adds all Resources to the Scheme +func AddToScheme(s *runtime.Scheme) error { + return AddToSchemes.AddToScheme(s) +}