diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index b9039439a..0f750d3fe 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -378,22 +378,21 @@ type OscVm struct { } type OscBastion struct { - Name string `json:"name,omitempty"` - ImageId string `json:"imageId,omitempty"` - ImageName string `json:"imageName,omitempty"` - KeypairName string `json:"keypairName,omitempty"` - VmType string `json:"vmType,omitempty"` - DeviceName string `json:"deviceName,omitempty"` - SubnetName string `json:"subnetName,omitempty"` - RootDisk OscRootDisk `json:"rootDisk,omitempty"` - PublicIpName string `json:"publicIpName,omitempty"` - SubregionName string `json:"subregionName,omitempty"` - PrivateIps []OscPrivateIpElement `json:"privateIps,omitempty"` - SecurityGroupNames []OscSecurityGroupElement `json:"securityGroupNames,omitempty"` - ResourceId string `json:"resourceId,omitempty"` - ClusterName string `json:"clusterName,omitempty"` - Enable bool `json:"enable,omitempty"` - PublicIpNameAfterBastion bool `json:"publicIpNameAfterBastion,omitempty"` + Name string `json:"name,omitempty"` + ImageId string `json:"imageId,omitempty"` + ImageName string `json:"imageName,omitempty"` + KeypairName string `json:"keypairName,omitempty"` + VmType string `json:"vmType,omitempty"` + DeviceName string `json:"deviceName,omitempty"` + SubnetName string `json:"subnetName,omitempty"` + RootDisk OscRootDisk `json:"rootDisk,omitempty"` + PublicIpName string `json:"publicIpName,omitempty"` + SubregionName string `json:"subregionName,omitempty"` + PrivateIps []OscPrivateIpElement `json:"privateIps,omitempty"` + SecurityGroupNames []OscSecurityGroupElement `json:"securityGroupNames,omitempty"` + ResourceId string `json:"resourceId,omitempty"` + ClusterName string `json:"clusterName,omitempty"` + Enable bool `json:"enable,omitempty"` } type OscRootDisk struct { diff --git a/cloud/scope/cluster.go b/cloud/scope/cluster.go index 20cd115d9..095ed224a 100644 --- a/cloud/scope/cluster.go +++ b/cloud/scope/cluster.go @@ -190,16 +190,6 @@ func (s *ClusterScope) SetExtraSecurityGroupRule(extraSecurityGroupRule bool) { s.OscCluster.Spec.Network.ExtraSecurityGroupRule = extraSecurityGroupRule } -// GetPublicIpNameAfterBastion return publicIpNameAfterBastion -func (s *ClusterScope) GetPublicIpNameAfterBastion() bool { - return s.OscCluster.Spec.Network.Bastion.PublicIpNameAfterBastion -} - -// SetPublicIpNameAfterBastion set the publicIpNameAfterBastion -func (s *ClusterScope) SetPublicIpNameAfterBastion(publicIpNameAfterBastion bool) { - s.OscCluster.Spec.Network.Bastion.PublicIpNameAfterBastion = publicIpNameAfterBastion -} - // GetNetwork return the network of the cluster func (s *ClusterScope) GetNetwork() *infrastructurev1beta1.OscNetwork { return &s.OscCluster.Spec.Network @@ -336,6 +326,11 @@ func (s *ClusterScope) GetControlPlaneEndpointPort() int32 { return s.OscCluster.Spec.ControlPlaneEndpoint.Port } +// GetReady get ready status +func (s *ClusterScope) GetReady() bool { + return s.OscCluster.Status.Ready +} + // SetNotReady set not ready status func (s *ClusterScope) SetNotReady() { s.OscCluster.Status.Ready = false @@ -386,6 +381,11 @@ func (s *ClusterScope) SetVmState(v infrastructurev1beta1.VmState) { s.OscCluster.Status.VmState = &v } +// SetVmState set vmstate +func (s *ClusterScope) GetVmState() *infrastructurev1beta1.VmState { + return s.OscCluster.Status.VmState +} + // PatchObject keep the cluster configuration and status func (s *ClusterScope) PatchObject() error { setConditions := []clusterv1.ConditionType{ diff --git a/cloud/scope/machine.go b/cloud/scope/machine.go index c07e88e5a..ebabb3e28 100644 --- a/cloud/scope/machine.go +++ b/cloud/scope/machine.go @@ -273,6 +273,11 @@ func (m *MachineScope) SetProviderID(subregionName string, vmId string) { m.OscMachine.Spec.ProviderID = pointer.StringPtr(pid) } +// SetVmID set the instanceID +func (m *MachineScope) SetVmID(vmId string) { + m.OscMachine.Spec.Node.Vm.ResourceId = vmId +} + // GetVmState return the vmState func (m *MachineScope) GetVmState() *infrastructurev1beta1.VmState { return m.OscMachine.Status.VmState diff --git a/cloud/services/compute/mock_compute/vm_mock.go b/cloud/services/compute/mock_compute/vm_mock.go index b5452422f..4a0819b02 100644 --- a/cloud/services/compute/mock_compute/vm_mock.go +++ b/cloud/services/compute/mock_compute/vm_mock.go @@ -6,7 +6,6 @@ package mock_compute import ( reflect "reflect" - time "time" gomock "github.com/golang/mock/gomock" v1beta1 "github.com/outscale-dev/cluster-api-provider-outscale.git/api/v1beta1" @@ -52,20 +51,6 @@ func (mr *MockOscVmInterfaceMockRecorder) AddCcmTag(clusterName, hostname, vmId return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCcmTag", reflect.TypeOf((*MockOscVmInterface)(nil).AddCcmTag), clusterName, hostname, vmId) } -// CheckVmState mocks base method. -func (m *MockOscVmInterface) CheckVmState(clockInsideLoop, clockLoop time.Duration, state, vmId string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CheckVmState", clockInsideLoop, clockLoop, state, vmId) - ret0, _ := ret[0].(error) - return ret0 -} - -// CheckVmState indicates an expected call of CheckVmState. -func (mr *MockOscVmInterfaceMockRecorder) CheckVmState(clockInsideLoop, clockLoop, state, vmId interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckVmState", reflect.TypeOf((*MockOscVmInterface)(nil).CheckVmState), clockInsideLoop, clockLoop, state, vmId) -} - // CreateVm mocks base method. func (m *MockOscVmInterface) CreateVm(machineScope *scope.MachineScope, spec *v1beta1.OscVm, subnetId string, securityGroupIds, privateIps []string, vmName string, tags map[string]string) (*osc.Vm, error) { m.ctrl.T.Helper() @@ -125,6 +110,15 @@ func (mr *MockOscVmInterfaceMockRecorder) GetCapacity(tagKey, tagValue, vmType i return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCapacity", reflect.TypeOf((*MockOscVmInterface)(nil).GetCapacity), tagKey, tagValue, vmType) } +// GetVmListFromTag mocks base method. +func (m *MockOscVmInterface) GetVmListFromTag(tagKey string, tagValue string) ([]osc.Vm, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetVmListFromTag", tagKey, tagValue) + ret0, _ := ret[0].([]osc.Vm) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + // GetVm mocks base method. func (m *MockOscVmInterface) GetVm(vmId string) (*osc.Vm, error) { m.ctrl.T.Helper() diff --git a/cloud/services/compute/vm.go b/cloud/services/compute/vm.go index 61f3b829f..53ab1bdae 100644 --- a/cloud/services/compute/vm.go +++ b/cloud/services/compute/vm.go @@ -23,11 +23,9 @@ import ( "net" "strconv" "strings" - "time" _nethttp "net/http" - "github.com/benbjohnson/clock" infrastructurev1beta1 "github.com/outscale-dev/cluster-api-provider-outscale.git/api/v1beta1" "github.com/outscale-dev/cluster-api-provider-outscale.git/cloud/scope" tag "github.com/outscale-dev/cluster-api-provider-outscale.git/cloud/tag" @@ -45,8 +43,8 @@ type OscVmInterface interface { CreateVmUserData(userData string, spec *infrastructurev1beta1.OscBastion, subnetId string, securityGroupIds []string, privateIps []string, vmName string, imageId string) (*osc.Vm, error) DeleteVm(vmId string) error GetVm(vmId string) (*osc.Vm, error) + GetVmListFromTag(tagKey string, tagName string) ([]osc.Vm, error) GetVmState(vmId string) (string, error) - CheckVmState(clockInsideLoop time.Duration, clockLoop time.Duration, state string, vmId string) error AddCcmTag(clusterName string, hostname string, vmId string) error GetCapacity(tagKey string, tagValue string, vmType string) (corev1.ResourceList, error) } @@ -413,32 +411,6 @@ func (s *Service) GetCapacity(tagKey string, tagValue string, vmType string) (co return capacity, nil } -// CheckVmState check the vm state -func (s *Service) CheckVmState(clockInsideLoop time.Duration, clockLoop time.Duration, state string, vmId string) error { - clock_time := clock.New() - currentTimeout := clock_time.Now().Add(time.Second * clockLoop) - var getVmState = false - for !getVmState { - time.Sleep(clockInsideLoop * time.Second) - vm, err := s.GetVm(vmId) - if err != nil { - return err - } - vmState, ok := vm.GetStateOk() - if !ok { - return errors.New("Can not get vm state") - } - if *vmState == state { - break - } - - if clock_time.Now().After(currentTimeout) { - return errors.New("Vm still not running") - } - } - return nil -} - // GetVmState return vm state func (s *Service) GetVmState(vmId string) (string, error) { vm, err := s.GetVm(vmId) @@ -447,7 +419,7 @@ func (s *Service) GetVmState(vmId string) (string, error) { } vmState, ok := vm.GetStateOk() if !ok { - return "", errors.New("Can not get vm state") + return "", errors.New("cannot get vm state") } return *vmState, nil } diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclusters.yaml index f3816e0f4..08057636f 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclusters.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: oscclusters.infrastructure.cluster.x-k8s.io spec: group: infrastructure.cluster.x-k8s.io @@ -85,8 +85,6 @@ spec: type: array publicIpName: type: string - publicIpNameAfterBastion: - type: boolean resourceId: type: string rootDisk: diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclustertemplates.yaml index b8c2140b0..e11b7b0f5 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscclustertemplates.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: oscclustertemplates.infrastructure.cluster.x-k8s.io spec: group: infrastructure.cluster.x-k8s.io @@ -49,26 +49,22 @@ spec: ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create. This is a copy of customizable fields from metav1.ObjectMeta. - ObjectMeta is embedded in `Machine.Spec`, `MachineDeployment.Template` and `MachineSet.Template`, which are not top-level Kubernetes objects. Given that metav1.ObjectMeta has lots of special cases and read-only fields which end up in the generated CRD validation, having it as a subset simplifies the API and some issues that can impact user experience. - During the [upgrade to controller-tools@v2](https://github.com/kubernetes-sigs/cluster-api/pull/1054) for v1alpha2, we noticed a failure would occur running Cluster API test suite against the new CRDs, specifically `spec.metadata.creationTimestamp in body must be of type string: "null"`. The investigation showed that `controller-tools@v2` behaves differently than its previous version when handling types from [metav1](k8s.io/apimachinery/pkg/apis/meta/v1) package. - In more details, we found that embedded (non-top level) types that embedded `metav1.ObjectMeta` had validation properties, including for `creationTimestamp` (metav1.Time). The `metav1.Time` type specifies a custom json marshaller that, when IsZero() is true, returns `null` which breaks validation because the field isn't marked as nullable. - In future versions, controller-tools@v2 might allow overriding the type and validation for embedded types. When that happens, this hack should be revisited. properties: @@ -141,8 +137,6 @@ spec: type: array publicIpName: type: string - publicIpNameAfterBastion: - type: boolean resourceId: type: string rootDisk: diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachines.yaml index cfabece85..ce0c58800 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachines.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: oscmachines.infrastructure.cluster.x-k8s.io spec: group: infrastructure.cluster.x-k8s.io diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachinetemplates.yaml index 4c71d4260..ed321481d 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_oscmachinetemplates.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.15.0 + controller-gen.kubebuilder.io/version: v0.16.2 name: oscmachinetemplates.infrastructure.cluster.x-k8s.io spec: group: infrastructure.cluster.x-k8s.io @@ -50,26 +50,22 @@ spec: ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create. This is a copy of customizable fields from metav1.ObjectMeta. - ObjectMeta is embedded in `Machine.Spec`, `MachineDeployment.Template` and `MachineSet.Template`, which are not top-level Kubernetes objects. Given that metav1.ObjectMeta has lots of special cases and read-only fields which end up in the generated CRD validation, having it as a subset simplifies the API and some issues that can impact user experience. - During the [upgrade to controller-tools@v2](https://github.com/kubernetes-sigs/cluster-api/pull/1054) for v1alpha2, we noticed a failure would occur running Cluster API test suite against the new CRDs, specifically `spec.metadata.creationTimestamp in body must be of type string: "null"`. The investigation showed that `controller-tools@v2` behaves differently than its previous version when handling types from [metav1](k8s.io/apimachinery/pkg/apis/meta/v1) package. - In more details, we found that embedded (non-top level) types that embedded `metav1.ObjectMeta` had validation properties, including for `creationTimestamp` (metav1.Time). The `metav1.Time` type specifies a custom json marshaller that, when IsZero() is true, returns `null` which breaks validation because the field isn't marked as nullable. - In future versions, controller-tools@v2 might allow overriding the type and validation for embedded types. When that happens, this hack should be revisited. properties: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 4b210e48e..0d134a7ad 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -27,29 +27,8 @@ rules: - cluster.x-k8s.io resources: - clusters - verbs: - - get - - list - - watch -- apiGroups: - - cluster.x-k8s.io - resources: - clusters/status - verbs: - - get - - list - - watch -- apiGroups: - - cluster.x-k8s.io - resources: - machines - verbs: - - get - - list - - watch -- apiGroups: - - cluster.x-k8s.io - resources: - machines/status verbs: - get @@ -59,32 +38,8 @@ rules: - infrastructure.cluster.x-k8s.io resources: - oscclusters - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - infrastructure.cluster.x-k8s.io - resources: - - oscclusters/finalizers - verbs: - - update -- apiGroups: - - infrastructure.cluster.x-k8s.io - resources: - - oscclusters/status - verbs: - - get - - patch - - update -- apiGroups: - - infrastructure.cluster.x-k8s.io - resources: - oscmachines + - oscmachinetemplates verbs: - create - delete @@ -96,32 +51,15 @@ rules: - apiGroups: - infrastructure.cluster.x-k8s.io resources: + - oscclusters/finalizers - oscmachines/finalizers verbs: - update - apiGroups: - infrastructure.cluster.x-k8s.io resources: + - oscclusters/status - oscmachines/status - verbs: - - get - - patch - - update -- apiGroups: - - infrastructure.cluster.x-k8s.io - resources: - - oscmachinetemplates - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - infrastructure.cluster.x-k8s.io - resources: - oscmachinetemplates/status verbs: - get diff --git a/controllers/osccluster_bastion_controller.go b/controllers/osccluster_bastion_controller.go index 26e70916f..925746b11 100644 --- a/controllers/osccluster_bastion_controller.go +++ b/controllers/osccluster_bastion_controller.go @@ -18,6 +18,7 @@ package controllers import ( "context" + "time" "fmt" @@ -251,86 +252,85 @@ func reconcileBastion(ctx context.Context, clusterScope *scope.ClusterScope, vmS } securityGroupIds = append(securityGroupIds, securityGroupId) } - var bastion *osc.Vm - var vmID string + var vm *osc.Vm + var vmId string if len(bastionRef.ResourceMap) == 0 { bastionRef.ResourceMap = make(map[string]string) } - publicIpNameAfterBastion := clusterScope.GetPublicIpNameAfterBastion() clusterScope.V(4).Info("Get ResourceId", "resourceId", bastionSpec.ResourceId) - tagKey := "Name" - tagValue := bastionName - tag, err := tagSvc.ReadTag(tagKey, tagValue) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get tag for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) - } - if bastionSpec.ResourceId != "" { - bastionRef.ResourceMap[bastionName] = bastionSpec.ResourceId - vmId := bastionSpec.ResourceId - clusterScope.V(4).Info("Get vmId", "bastion", bastionRef.ResourceMap) - bastion, err = vmSvc.GetVm(vmId) + bastionState := clusterScope.GetVmState() + + if bastionState == nil { + vms, err := vmSvc.GetVmListFromTag("Name", bastionName) if err != nil { - return reconcile.Result{}, err + return reconcile.Result{}, fmt.Errorf("%w Could not list vms for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) } - clusterScope.V(2).Info("Get VmState") - vmState, err := vmSvc.GetVmState(vmId) - if err != nil { - clusterScope.SetVmState(infrastructurev1beta1.VmState("unknown")) - return reconcile.Result{}, fmt.Errorf("%w Can not get bastion %s state for OscCluster %s/%s", err, vmId, clusterScope.GetNamespace(), clusterScope.GetName()) + if len(vms) > 0 { + if bastionSpec.ResourceId != "" { + clusterScope.SetVmState(infrastructurev1beta1.VmStatePending) + bastionRef.ResourceMap[bastionName] = bastionSpec.ResourceId + return reconcile.Result{RequeueAfter: 30 * time.Second}, nil + } + return reconcile.Result{}, fmt.Errorf("%w Bastion Vm with Name %s already exists for OscCluster %s/%s", err, bastionName, clusterScope.GetNamespace(), clusterScope.GetName()) } - clusterScope.SetVmState(infrastructurev1beta1.VmState(vmState)) - clusterScope.V(4).Info("Get bastion state", "vmState", vmState) - } - if (bastion == nil && tag == nil) || (bastionSpec.ResourceId == "" && tag == nil) { + clusterScope.V(4).Info("Create the desired bastion", "bastionName", bastionName) keypairName := bastionSpec.KeypairName clusterScope.V(4).Info("Get keypairName", "keypairName", keypairName) vmType := bastionSpec.VmType clusterScope.V(4).Info("Get vmType", "vmType", vmType) - vm, err := vmSvc.CreateVmUserData("", bastionSpec, subnetId, securityGroupIds, privateIps, bastionName, imageId) + vm, err = vmSvc.CreateVmUserData("", bastionSpec, subnetId, securityGroupIds, privateIps, bastionName, imageId) if err != nil { return reconcile.Result{}, fmt.Errorf("%w Can not create bastion for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) } - vmID = vm.GetVmId() - err = vmSvc.CheckVmState(5, 120, "running", vmID) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s running for OscCluster %s/%s", err, vmID, clusterScope.GetNamespace(), clusterScope.GetName()) - } - clusterScope.V(4).Info("Bastion is running", "vmID", vmID) - clusterScope.SetVmState(infrastructurev1beta1.VmState("pending")) - if bastionSpec.PublicIpName != "" { - linkPublicIpId, err := publicIpSvc.LinkPublicIp(publicIpId, vmID) + vmId = vm.GetVmId() + clusterScope.SetVmState(infrastructurev1beta1.VmStatePending) + bastionState = &infrastructurev1beta1.VmStatePending + bastionRef.ResourceMap[bastionName] = vmId + bastionSpec.ResourceId = vmId + clusterScope.V(4).Info("Bastion Created", "bastionId", vmId) + } + + if bastionState != nil { + if *bastionState != infrastructurev1beta1.VmStateRunning { + vmId := bastionSpec.ResourceId + clusterScope.V(4).Info("Get vmId", "vmId", vmId) + _, err = vmSvc.GetVm(vmId) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not link publicIp %s with %s for OscCluster %s/%s", err, publicIpId, vmID, clusterScope.GetNamespace(), clusterScope.GetName()) + return reconcile.Result{}, err } - err = vmSvc.CheckVmState(5, 120, "running", vmID) + clusterScope.V(2).Info("Get currentVmState") + currentVmState, err := vmSvc.GetVmState(vmId) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s running for OscCluster %s/%s", err, vmID, clusterScope.GetNamespace(), clusterScope.GetName()) + clusterScope.SetVmState(infrastructurev1beta1.VmState("unknown")) + return reconcile.Result{}, fmt.Errorf("%w Can not get bastion %s state for OscCluster %s/%s", err, vmId, clusterScope.GetNamespace(), clusterScope.GetName()) } - clusterScope.V(4).Info("Get bastionPublicIpName", "bastionPublicIpName", bastionPublicIpName) - linkPublicIpRef.ResourceMap[bastionPublicIpName] = linkPublicIpId + clusterScope.SetVmState(infrastructurev1beta1.VmState(currentVmState)) + clusterScope.V(4).Info("Bastion state", "vmState", currentVmState) + if infrastructurev1beta1.VmState(currentVmState) != infrastructurev1beta1.VmStateRunning { + clusterScope.V(4).Info("Bastion vm is not yet running", "vmId", vmId) + return reconcile.Result{RequeueAfter: 30 * time.Second}, fmt.Errorf("bastion %s is not yet running for OscCluster %s/%s", vmId, clusterScope.GetNamespace(), clusterScope.GetName()) + } + bastionState = &infrastructurev1beta1.VmStateRunning + clusterScope.V(4).Info("Bastion is running", "vmId", vmId) } - bastionRef.ResourceMap[bastionName] = vmID - bastionSpec.ResourceId = vmID - } - if publicIpNameAfterBastion && bastionSpec.PublicIpName != "" && bastionSpec.ResourceId != "" { - linkPublicIpId, err := publicIpSvc.LinkPublicIp(publicIpId, bastionSpec.ResourceId) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not link publicIp %s with %s for OscCluster %s/%s", err, publicIpId, vmID, clusterScope.GetNamespace(), clusterScope.GetName()) - } - err = vmSvc.CheckVmState(5, 120, "running", bastionSpec.ResourceId) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s running for OscCluster %s/%s", err, vmID, clusterScope.GetNamespace(), clusterScope.GetName()) - } - bastionPublicIpName := bastionSpec.PublicIpName + "-" + clusterScope.GetUID() - clusterScope.V(4).Info("Get bastionPublicIpName", "bastionPublicIpName", bastionPublicIpName) - linkPublicIpRef.ResourceMap[bastionPublicIpName] = linkPublicIpId - bastionRef.ResourceMap[bastionName] = bastionSpec.ResourceId - } + if *bastionState == infrastructurev1beta1.VmStateRunning { + vmId := bastionSpec.ResourceId + if bastionSpec.PublicIpName != "" && linkPublicIpRef.ResourceMap[bastionPublicIpName] == "" { + linkPublicIpId, err := publicIpSvc.LinkPublicIp(publicIpId, vmId) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not link publicIp %s with %s for OscCluster %s/%s", err, publicIpId, vmId, clusterScope.GetNamespace(), clusterScope.GetName()) + } + clusterScope.V(4).Info("Get bastionPublicIpName", "bastionPublicIpName", bastionPublicIpName) + linkPublicIpRef.ResourceMap[bastionPublicIpName] = linkPublicIpId + } + } + } + clusterScope.V(4).Info("Bastion is reconciled") return reconcile.Result{}, nil } @@ -340,7 +340,7 @@ func reconcileDeleteBastion(ctx context.Context, clusterScope *scope.ClusterScop bastionSpec := clusterScope.GetBastion() bastionSpec.SetDefaultValue() vmId := bastionSpec.ResourceId - clusterScope.V(4).Info("Get VmID", "vmId", vmId) + clusterScope.V(4).Info("Get vmId", "vmId", vmId) bastionName := bastionSpec.Name if bastionSpec.ResourceId == "" { clusterScope.V(2).Info("The desired bastion is currently destroyed", "bastionName", bastionName) @@ -351,15 +351,13 @@ func reconcileDeleteBastion(ctx context.Context, clusterScope *scope.ClusterScop return reconcile.Result{}, err } - var securityGroupIds []string bastionSecurityGroups := clusterScope.GetBastionSecurityGroups() for _, bastionSecurityGroup := range *bastionSecurityGroups { securityGroupName := bastionSecurityGroup.Name + "-" + clusterScope.GetUID() - securityGroupId, err := getSecurityGroupResourceId(securityGroupName, clusterScope) + _, err := getSecurityGroupResourceId(securityGroupName, clusterScope) if err != nil { return reconcile.Result{}, err } - securityGroupIds = append(securityGroupIds, securityGroupId) } if bastion == nil { clusterScope.V(2).Info("The desired bastion does not exist anymore", "bastionName", bastionName) diff --git a/controllers/osccluster_bastion_controller_unit_test.go b/controllers/osccluster_bastion_controller_unit_test.go index 4d95b3b5f..7fe04d12b 100644 --- a/controllers/osccluster_bastion_controller_unit_test.go +++ b/controllers/osccluster_bastion_controller_unit_test.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "testing" - "time" "github.com/golang/mock/gomock" infrastructurev1beta1 "github.com/outscale-dev/cluster-api-provider-outscale.git/api/v1beta1" @@ -180,85 +179,6 @@ var ( }, } - defaultPublicIpNameAfterBastionReconcile = infrastructurev1beta1.OscClusterSpec{ - Network: infrastructurev1beta1.OscNetwork{ - Net: infrastructurev1beta1.OscNet{ - Name: "test-net", - IpRange: "10.0.0.0/16", - ClusterName: "test-cluster", - ResourceId: "vpc-test-net-uid", - }, - Subnets: []*infrastructurev1beta1.OscSubnet{ - { - Name: "test-subnet", - IpSubnetRange: "10.0.0.0/24", - SubregionName: "eu-west-2a", - ResourceId: "subnet-test-subnet-uid", - }, - }, - SecurityGroups: []*infrastructurev1beta1.OscSecurityGroup{ - { - Name: "test-securitygroup", - Description: "test securitygroup", - ResourceId: "sg-test-securitygroup-uid", - SecurityGroupRules: []infrastructurev1beta1.OscSecurityGroupRule{ - { - Name: "test-securitygrouprule", - Flow: "Inbound", - IpProtocol: "tcp", - IpRange: "0.0.0.0/0", - FromPortRange: 6443, - ToPortRange: 6443, - }, - }, - }, - }, - LoadBalancer: infrastructurev1beta1.OscLoadBalancer{ - LoadBalancerName: "test-loadbalancer", - LoadBalancerType: "internet-facing", - SubnetName: "test-subnet", - SecurityGroupName: "test-securitygroup", - }, - PublicIps: []*infrastructurev1beta1.OscPublicIp{ - { - Name: "test-publicip", - ResourceId: "test-publicip-uid", - }, - }, - Bastion: infrastructurev1beta1.OscBastion{ - Enable: true, - ClusterName: "test-cluster", - Name: "test-bastion", - ImageId: "ami-00000000", - DeviceName: "/dev/xvdb", - KeypairName: "rke", - RootDisk: infrastructurev1beta1.OscRootDisk{ - - RootDiskSize: 30, - RootDiskIops: 1500, - RootDiskType: "io1", - }, - SubregionName: "eu-west-2a", - SubnetName: "test-subnet", - VmType: "tinav3.c2r4p2", - ResourceId: "i-test-bastion-uid", - PublicIpName: "test-publicip", - PublicIpNameAfterBastion: true, - SecurityGroupNames: []infrastructurev1beta1.OscSecurityGroupElement{ - { - Name: "test-securitygroup", - }, - }, - PrivateIps: []infrastructurev1beta1.OscPrivateIpElement{ - { - Name: "test-privateip", - PrivateIp: "10.0.0.17", - }, - }, - }, - }, - } - defaultBastionReconcile = infrastructurev1beta1.OscClusterSpec{ Network: infrastructurev1beta1.OscNetwork{ Net: infrastructurev1beta1.OscNet{ @@ -1835,7 +1755,6 @@ func TestReconcileBastion(t *testing.T) { clusterScope, ctx, mockOscVmInterface, mockOscPublicIpInterface, mockOscSecurityGroupInterface, mockOscImageInterface, mockOscTagInterface := SetupWithBastionMock(t, btc.name, btc.clusterSpec) bastionName := btc.clusterSpec.Network.Bastion.Name + "-uid" vmId := "i-" + bastionName - vmState := "running" subnetName := btc.clusterSpec.Network.Bastion.SubnetName + "-uid" subnetId := "subnet-" + subnetName @@ -1877,8 +1796,6 @@ func TestReconcileBastion(t *testing.T) { } bastionSpec := btc.clusterSpec.Network.Bastion - var clockInsideLoop time.Duration = 5 - var firstClockLoop time.Duration = 120 createVms := osc.CreateVmsResponse{ Vms: &[]osc.Vm{ { @@ -1918,12 +1835,6 @@ func TestReconcileBastion(t *testing.T) { CreateVmUserData(gomock.Eq(""), gomock.Eq(&bastionSpec), gomock.Eq(subnetId), gomock.Eq(securityGroupIds), gomock.Eq(privateIps), gomock.Eq(bastionName), gomock.Eq(imageId)). Return(nil, btc.expCreateVmErr) } - if btc.expCheckVmStateBootFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(firstClockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(btc.expCheckVmStateBootErr) - } if btc.expLinkPublicIpFound { mockOscPublicIpInterface. @@ -1931,12 +1842,6 @@ func TestReconcileBastion(t *testing.T) { LinkPublicIp(gomock.Eq(publicIpId), gomock.Eq(vmId)). Return(*linkPublicIp.LinkPublicIpId, btc.expLinkPublicIpErr) } - if btc.expCheckVmStatePublicIpFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(firstClockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(btc.expCheckVmStatePublicIpErr) - } reconcileBastion, err := reconcileBastion(ctx, clusterScope, mockOscVmInterface, mockOscPublicIpInterface, mockOscSecurityGroupInterface, mockOscImageInterface, mockOscTagInterface) if err != nil { @@ -2134,7 +2039,6 @@ func TestReconcileLinkBastion(t *testing.T) { clusterScope, ctx, mockOscVmInterface, mockOscPublicIpInterface, mockOscSecurityGroupInterface, mockOscImageInterface, mockOscTagInterface := SetupWithBastionMock(t, btc.name, btc.clusterSpec) bastionName := btc.clusterSpec.Network.Bastion.Name + "-uid" vmId := "i-" + bastionName - vmState := "running" subnetName := btc.clusterSpec.Network.Bastion.SubnetName + "-uid" subnetId := "subnet-" + subnetName @@ -2177,9 +2081,6 @@ func TestReconcileLinkBastion(t *testing.T) { } bastionSpec := btc.clusterSpec.Network.Bastion - var clockInsideLoop time.Duration = 5 - var clockLoop time.Duration = 120 - var firstClockLoop time.Duration = 120 createVms := osc.CreateVmsResponse{ Vms: &[]osc.Vm{ { @@ -2208,12 +2109,6 @@ func TestReconcileLinkBastion(t *testing.T) { } bastion := &createVm[0] - if btc.expCheckVmStateBootFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(firstClockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(btc.expCheckVmStateBootErr) - } if btc.expCreateVmFound { mockOscVmInterface. EXPECT(). @@ -2232,12 +2127,6 @@ func TestReconcileLinkBastion(t *testing.T) { LinkPublicIp(gomock.Eq(publicIpId), gomock.Eq(vmId)). Return(*linkPublicIp.LinkPublicIpId, btc.expLinkPublicIpErr) } - if btc.expCheckVmStatePublicIpFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(btc.expCheckVmStatePublicIpErr) - } reconcileBastion, err := reconcileBastion(ctx, clusterScope, mockOscVmInterface, mockOscPublicIpInterface, mockOscSecurityGroupInterface, mockOscImageInterface, mockOscTagInterface) if err != nil { @@ -2283,21 +2172,6 @@ func TestReconcileBastionGet(t *testing.T) { expLinkPublicIpErr: nil, expReconcileBastionErr: nil, }, - { - name: "get bastion with publicIpNameAfterBastion", - clusterSpec: defaultPublicIpNameAfterBastionReconcile, - expLinkPublicIpFound: true, - expGetVmFound: true, - expGetVmStateFound: true, - expTagFound: false, - expCheckVmStatePublicIpFound: true, - expGetVmErr: nil, - expGetVmStateErr: nil, - expReadTagErr: nil, - expCheckVmStatePublicIpErr: nil, - expLinkPublicIpErr: nil, - expReconcileBastionErr: nil, - }, { name: "failed to get bastion", clusterSpec: defaultBastionReconcile, @@ -2373,8 +2247,6 @@ func TestReconcileBastionGet(t *testing.T) { securityGroupsRef.ResourceMap[securityGroupName] = securityGroupId securityGroupIds = append(securityGroupIds, securityGroupId) } - var clockInsideLoop time.Duration = 5 - var clockLoop time.Duration = 120 readVms := osc.ReadVmsResponse{ Vms: &[]osc.Vm{ { @@ -2424,12 +2296,6 @@ func TestReconcileBastionGet(t *testing.T) { LinkPublicIp(gomock.Eq(publicIpId), gomock.Eq(vmId)). Return(*linkPublicIp.LinkPublicIpId, btc.expLinkPublicIpErr) } - if btc.expCheckVmStatePublicIpFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(btc.expCheckVmStatePublicIpErr) - } reconcileBastion, err := reconcileBastion(ctx, clusterScope, mockOscVmInterface, mockOscPublicIpInterface, mockOscSecurityGroupInterface, mockOscImageInterface, mockOscTagInterface) if err != nil { diff --git a/controllers/osccluster_controller.go b/controllers/osccluster_controller.go index 1b2035dfb..b87d69ff7 100644 --- a/controllers/osccluster_controller.go +++ b/controllers/osccluster_controller.go @@ -322,8 +322,7 @@ func (r *OscClusterReconciler) reconcile(ctx context.Context, clusterScope *scop return reconcile.Result{}, fmt.Errorf("%w Can not create bastion %s for OscCluster %s/%s", err, bastionName, clusterScope.GetNamespace(), clusterScope.GetName()) } } - clusterScope.V(2).Info("Set OscCluster status to not ready") - clusterScope.SetNotReady() + // Reconcile each element of the cluster netSvc := r.getNetSvc(ctx, *clusterScope) tagSvc := r.getTagSvc(ctx, *clusterScope) @@ -411,16 +410,20 @@ func (r *OscClusterReconciler) reconcile(ctx context.Context, clusterScope *scop conditions.MarkFalse(osccluster, infrastructurev1beta1.LoadBalancerReadyCondition, infrastructurev1beta1.LoadBalancerFailedReason, clusterv1.ConditionSeverityWarning, err.Error()) return reconcileLoadBalancer, err } + if clusterScope.OscCluster.Spec.Network.Bastion.Enable { + clusterScope.V(4).Info("Reconciling bastion Vm") vmSvc := r.getVmSvc(ctx, *clusterScope) imageSvc := r.getImageSvc(ctx, *clusterScope) reconcileBastion, err := reconcileBastion(ctx, clusterScope, vmSvc, publicIpSvc, securityGroupSvc, imageSvc, tagSvc) if err != nil { clusterScope.Error(err, "failed to reconcile bastion") - conditions.MarkFalse(osccluster, infrastructurev1beta1.VmReadyCondition, infrastructurev1beta1.VmNotReadyReason, clusterv1.ConditionSeverityWarning, err.Error()) + conditions.MarkFalse(osccluster, infrastructurev1beta1.VmReadyCondition, infrastructurev1beta1.VmNotReadyReason, clusterv1.ConditionSeverityWarning, "%s", err.Error()) return reconcileBastion, err } } + conditions.MarkTrue(osccluster, infrastructurev1beta1.VmReadyCondition) + clusterScope.V(2).Info("Set OscCluster status to ready") clusterScope.SetReady() return reconcile.Result{}, nil diff --git a/controllers/oscmachine_controller.go b/controllers/oscmachine_controller.go index 22abb5c8d..c7344771d 100644 --- a/controllers/oscmachine_controller.go +++ b/controllers/oscmachine_controller.go @@ -200,8 +200,6 @@ func (r *OscMachineReconciler) reconcile(ctx context.Context, machineScope *scop controllerutil.AddFinalizer(oscmachine, "oscmachine.infrastructure.cluster.x-k8s.io") - machineScope.V(2).Info("Set OscMachine status to not ready") - machineScope.SetNotReady() if !machineScope.Cluster.Status.InfrastructureReady { machineScope.V(2).Info("Cluster infrastructure is not ready yet") conditions.MarkFalse(oscmachine, infrastructurev1beta1.VmReadyCondition, infrastructurev1beta1.WaitingForClusterInfrastructureReason, clusterv1.ConditionSeverityInfo, "") @@ -308,6 +306,7 @@ func (r *OscMachineReconciler) reconcile(ctx context.Context, machineScope *scop return reconcileVolume, err } } + conditions.MarkTrue(oscmachine, infrastructurev1beta1.VolumeReadyCondition) keypairSvc := r.getKeyPairSvc(ctx, *clusterScope) reconcileKeypair, err := reconcileKeypair(ctx, machineScope, keypairSvc) @@ -320,20 +319,16 @@ func (r *OscMachineReconciler) reconcile(ctx context.Context, machineScope *scop vmSvc := r.getVmSvc(ctx, *clusterScope) loadBalancerSvc := r.getLoadBalancerSvc(ctx, *clusterScope) securityGroupSvc := r.getSecurityGroupSvc(ctx, *clusterScope) + + machineScope.V(4).Info("Reconciling Vm") reconcileVm, err := reconcileVm(ctx, clusterScope, machineScope, vmSvc, volumeSvc, publicIpSvc, loadBalancerSvc, securityGroupSvc, tagSvc) if err != nil { machineScope.Error(err, "failed to reconcile vm") - conditions.MarkFalse(oscmachine, infrastructurev1beta1.VmReadyCondition, infrastructurev1beta1.VmNotReadyReason, clusterv1.ConditionSeverityWarning, err.Error()) + conditions.MarkFalse(oscmachine, infrastructurev1beta1.VmReadyCondition, infrastructurev1beta1.VmNotReadyReason, clusterv1.ConditionSeverityWarning, "%s", err.Error()) return reconcileVm, err } - conditions.MarkTrue(oscmachine, infrastructurev1beta1.VolumeReadyCondition) vmState := machineScope.GetVmState() - if vmState == nil { - machineScope.V(2).Info("VmState is not yet availablle") - return ctrl.Result{}, nil - } - switch *vmState { case infrastructurev1beta1.VmStatePending: machineScope.SetNotReady() diff --git a/controllers/oscmachine_vm_controller.go b/controllers/oscmachine_vm_controller.go index 24519b834..b01d5560d 100644 --- a/controllers/oscmachine_vm_controller.go +++ b/controllers/oscmachine_vm_controller.go @@ -32,7 +32,6 @@ import ( osc "github.com/outscale/osc-sdk-go/v2" corev1 "k8s.io/api/core/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -382,6 +381,13 @@ func reconcileVm(ctx context.Context, clusterScope *scope.ClusterScope, machineS } } + if vmSpec.KeypairName != "" { + _, err = getKeyPairResourceId(vmSpec.KeypairName, machineScope) + if err != nil { + return reconcile.Result{}, err + } + } + var securityGroupIds []string vmSecurityGroups := machineScope.GetVmSecurityGroups() for _, vmSecurityGroup := range *vmSecurityGroups { @@ -400,64 +406,31 @@ func reconcileVm(ctx context.Context, clusterScope *scope.ClusterScope, machineS vmVolumeDeviceName = vmSpec.VolumeDeviceName } var vm *osc.Vm - var vmID string + var vmId string if len(vmRef.ResourceMap) == 0 { vmRef.ResourceMap = make(map[string]string) } - tagKey := "Name" - tagValue := vmName - tag, err := tagSvc.ReadTag(tagKey, tagValue) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get tag for OscMachine %s/%s", err, machineScope.GetNamespace(), machineScope.GetName()) - } - machineScope.V(4).Info("Get ResourceId", "resourceId", vmSpec.ResourceId) - machineScope.V(4).Info("Get ResourceMap", "resourceMap", vmRef.ResourceMap) - if vmSpec.ResourceId != "" { - vmRef.ResourceMap[vmName] = vmSpec.ResourceId - vmId := vmSpec.ResourceId - machineScope.V(4).Info("Check if the desired vm exist", "vmName", vmName) - vm, err = vmSvc.GetVm(vmId) - if err != nil { - return reconcile.Result{}, err - } - clusterName := vmSpec.ClusterName + "-" + clusterScope.GetUID() - privateDnsName, ok := vm.GetPrivateDnsNameOk() - if !ok { - return reconcile.Result{}, fmt.Errorf("Can not found privateDnsName %s/%s", machineScope.GetNamespace(), machineScope.GetName()) - } - privateIp, ok := vm.GetPrivateIpOk() - if !ok { - return reconcile.Result{}, fmt.Errorf("Can not found privateIp %s/%s", machineScope.GetNamespace(), machineScope.GetName()) - } - addresses := []corev1.NodeAddress{} - addresses = append( - addresses, - corev1.NodeAddress{ - Type: corev1.NodeInternalIP, - Address: *privateIp, - }, - ) - // Expose Public IP if one is set - if publicIp, ok := vm.GetPublicIpOk(); ok { - addresses = append(addresses, corev1.NodeAddress{ - Type: corev1.NodeExternalIP, - Address: *publicIp, - }) - } - machineScope.SetAddresses(addresses) - err = vmSvc.AddCcmTag(clusterName, *privateDnsName, vmId) + vmState := machineScope.GetVmState() + + if vmState == nil { + vms, err := vmSvc.GetVmListFromTag("Name", vmName) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w can not add ccm tag %s/%s", err, machineScope.GetNamespace(), machineScope.GetName()) + return reconcile.Result{}, fmt.Errorf("%w Could not list vms for OscCluster %s/%s", err, machineScope.GetNamespace(), machineScope.GetName()) } - vmState, err := vmSvc.GetVmState(vmId) - if err != nil { - machineScope.SetVmState(infrastructurev1beta1.VmState("unknown")) - return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s state for OscMachine %s/%s", err, vmId, machineScope.GetNamespace(), machineScope.GetName()) + if len(vms) > 0 { + if vmSpec.ResourceId != "" || vmRef.ResourceMap[vmName] != "" { // We should not get in this situation but we sometimes do (To be investigated) + machineScope.SetVmState(infrastructurev1beta1.VmStatePending) + if vmSpec.ResourceId != "" { + vmRef.ResourceMap[vmName] = vmSpec.ResourceId + } + if vmRef.ResourceMap[vmName] != "" { + machineScope.SetVmID(vmRef.ResourceMap[vmName]) + } + return reconcile.Result{RequeueAfter: 30 * time.Second}, fmt.Errorf("%w Vm with Name %s is already created for OscCluster %s/%s", err, vmName, machineScope.GetNamespace(), machineScope.GetName()) + } + return reconcile.Result{}, fmt.Errorf("%w Vm with Name %s already exists for OscCluster %s/%s", err, vmName, machineScope.GetNamespace(), machineScope.GetName()) } - machineScope.SetVmState(infrastructurev1beta1.VmState(vmState)) - machineScope.V(4).Info("Get vm state", "vmState", vmState) - } - if (vm == nil && tag == nil) || (vmSpec.ResourceId == "" && tag == nil) { + machineScope.V(4).Info("Create the desired vm", "vmName", vmName) imageId := vmSpec.ImageId machineScope.V(4).Info("Info ImageId", "imageId", imageId) @@ -473,122 +446,198 @@ func reconcileVm(ctx context.Context, clusterScope *scope.ClusterScope, machineS return reconcile.Result{}, fmt.Errorf("%w Can not create vm for OscMachine %s/%s", err, machineScope.GetNamespace(), machineScope.GetName()) } - vmID = vm.GetVmId() - err = vmSvc.CheckVmState(20, 240, "running", vmID) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s running for OscMachine %s/%s", err, vmID, machineScope.GetNamespace(), machineScope.GetName()) - } - machineScope.V(4).Info("Vm is running", "vmId", vmID) - machineScope.SetVmState(infrastructurev1beta1.VmState("pending")) - if vmSpec.VolumeName != "" { - err = volumeSvc.CheckVolumeState(20, 240, "available", volumeId) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get volume %s available for OscMachine %s/%s", err, volumeId, machineScope.GetNamespace(), machineScope.GetName()) + vmId = vm.GetVmId() + machineScope.SetVmState(infrastructurev1beta1.VmStatePending) + vmState = &infrastructurev1beta1.VmStatePending + vmRef.ResourceMap[vmName] = vmId + machineScope.SetVmID(vmId) + subregionName := vmSpec.SubregionName + machineScope.SetProviderID(subregionName, vmId) + machineScope.V(4).Info("Vm created", "vmId", vmId) + } + + if vmState != nil { + if *vmState != infrastructurev1beta1.VmStateRunning { + vmId := vmSpec.ResourceId + if vmId == "" { // We should not get in this situation but we sometimes do (To be investigated) + vmId = vmRef.ResourceMap[vmName] + machineScope.SetVmID(vmId) + subregionName := vmSpec.SubregionName + machineScope.SetProviderID(subregionName, vmId) } - machineScope.V(4).Info("Volume is available", "volumeId", volumeId) - err = volumeSvc.LinkVolume(volumeId, vmID, vmVolumeDeviceName) + machineScope.V(4).Info("Get vmId", "vmId", vmId) + _, err = vmSvc.GetVm(vmId) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not link volume %s with vm %s for OscMachine %s/%s", err, volumeId, vmID, machineScope.GetNamespace(), machineScope.GetName()) + return reconcile.Result{}, err } - machineScope.V(4).Info("Volume is linked", "volumeId", volumeId) - err = volumeSvc.CheckVolumeState(20, 240, "in-use", volumeId) - machineScope.V(4).Info("Volume is in-use", "volumeId", volumeId) + machineScope.V(2).Info("Get currentVmState") + currentVmState, err := vmSvc.GetVmState(vmId) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get volume %s in use for OscMachine %s/%s", err, volumeId, machineScope.GetNamespace(), machineScope.GetName()) + machineScope.SetVmState(infrastructurev1beta1.VmState("unknown")) + return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s state for OscCluster %s/%s", err, vmId, machineScope.GetNamespace(), machineScope.GetName()) } - } - err = vmSvc.CheckVmState(20, 240, "running", vmID) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s running for OscMachine %s/%s", err, vmID, machineScope.GetNamespace(), machineScope.GetName()) - } - machineScope.V(4).Info("Vm is running again", "vmId", vmID) + machineScope.SetVmState(infrastructurev1beta1.VmState(currentVmState)) + machineScope.V(4).Info("Vm state", "vmState", currentVmState) - if vmSpec.PublicIpName != "" { - linkPublicIpId, err := publicIpSvc.LinkPublicIp(publicIpId, vmID) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not link publicIp %s with %s for OscCluster %s/%s", err, publicIpId, vmID, machineScope.GetNamespace(), machineScope.GetName()) + if infrastructurev1beta1.VmState(currentVmState) != infrastructurev1beta1.VmStateRunning { + machineScope.V(4).Info("Vm is not yet running", "vmId", vmId) + return reconcile.Result{RequeueAfter: 30 * time.Second}, fmt.Errorf("vm %s is not yet running for OscCluster %s/%s", vmId, machineScope.GetNamespace(), machineScope.GetName()) } - machineScope.V(4).Info("Link public ip", "linkPublicIpId", linkPublicIpId) - linkPublicIpRef.ResourceMap[vmPublicIpName] = linkPublicIpId + vmState = &infrastructurev1beta1.VmStateRunning + machineScope.V(4).Info("Vm is running", "vmId", vmId) + } - err = vmSvc.CheckVmState(20, 240, "running", vmID) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get vm %s running for OscMachine %s/%s", err, vmID, machineScope.GetNamespace(), machineScope.GetName()) + if *vmState == infrastructurev1beta1.VmStateRunning { + vmId := vmSpec.ResourceId + if vmId == "" { // We should not get in this situation but we sometimes do (To be investigated) + vmId = vmRef.ResourceMap[vmName] + machineScope.SetVmID(vmId) + subregionName := vmSpec.SubregionName + machineScope.SetProviderID(subregionName, vmId) } - } - if vmSpec.LoadBalancerName != "" { - loadBalancerName := vmSpec.LoadBalancerName - vmIds := []string{vmID} - err := loadBalancerSvc.LinkLoadBalancerBackendMachines(vmIds, loadBalancerName) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not link vm %s with loadBalancerName %s for OscCluster %s/%s", err, loadBalancerName, vmID, machineScope.GetNamespace(), machineScope.GetName()) + if vmSpec.VolumeName != "" { + err = volumeSvc.CheckVolumeState(20, 240, "available", volumeId) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not get volume %s available for OscMachine %s/%s", err, volumeId, machineScope.GetNamespace(), machineScope.GetName()) + } + machineScope.V(4).Info("Volume is available", "volumeId", volumeId) + err = volumeSvc.LinkVolume(volumeId, vmId, vmVolumeDeviceName) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not link volume %s with vm %s for OscMachine %s/%s", err, volumeId, vmId, machineScope.GetNamespace(), machineScope.GetName()) + } + machineScope.V(4).Info("Volume is linked", "volumeId", volumeId) + err = volumeSvc.CheckVolumeState(20, 240, "in-use", volumeId) + machineScope.V(4).Info("Volume is in-use", "volumeId", volumeId) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not get volume %s in use for OscMachine %s/%s", err, volumeId, machineScope.GetNamespace(), machineScope.GetName()) + } } - securityGroupsRef := clusterScope.GetSecurityGroupsRef() - loadBalancerSpec := clusterScope.GetLoadBalancer() - loadBalancerSpec.SetDefaultValue() - loadBalancerSecurityGroupName := loadBalancerSpec.SecurityGroupName - ipProtocol := strings.ToLower(loadBalancerSpec.Listener.BackendProtocol) - machineScope.V(4).Info("Get IpProtocol", "IpProtocol", ipProtocol) - fromPortRange := loadBalancerSpec.Listener.BackendPort - machineScope.V(4).Info("Get fromPortRange", "fromPortRange", fromPortRange) - toPortRange := loadBalancerSpec.Listener.BackendPort - machineScope.V(4).Info("Get ToPortRange", "ToPortRange", toPortRange) - loadBalancerSecurityGroupClusterScopeName := loadBalancerSecurityGroupName + "-" + clusterScope.GetUID() - associateSecurityGroupId := securityGroupsRef.ResourceMap[loadBalancerSecurityGroupClusterScopeName] - machineScope.V(4).Info("Get sg", "associateSecurityGroupId", associateSecurityGroupId) - securityGroupFromSecurityGroupOutboundRule, err := securityGroupSvc.GetSecurityGroupFromSecurityGroupRule(associateSecurityGroupId, "Outbound", ipProtocol, "", securityGroupIds[0], fromPortRange, toPortRange) - if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get outbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) + + if vmSpec.PublicIpName != "" && linkPublicIpRef.ResourceMap[vmPublicIpName] == "" { + linkPublicIpId, err := publicIpSvc.LinkPublicIp(publicIpId, vmId) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not link publicIp %s with %s for OscCluster %s/%s", err, publicIpId, vmId, machineScope.GetNamespace(), machineScope.GetName()) + } + machineScope.V(4).Info("Link public ip", "linkPublicIpId", linkPublicIpId) + linkPublicIpRef.ResourceMap[vmPublicIpName] = linkPublicIpId } - if securityGroupFromSecurityGroupOutboundRule == nil { - _, err = securityGroupSvc.CreateSecurityGroupRule(associateSecurityGroupId, "Outbound", ipProtocol, "", securityGroupIds[0], fromPortRange, toPortRange) + if vmSpec.LoadBalancerName != "" { + loadBalancerName := vmSpec.LoadBalancerName + vmIds := []string{vmId} + err := loadBalancerSvc.LinkLoadBalancerBackendMachines(vmIds, loadBalancerName) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not link vm %s with loadBalancerName %s for OscCluster %s/%s", err, vmId, loadBalancerName, machineScope.GetNamespace(), machineScope.GetName()) + } + securityGroupsRef := clusterScope.GetSecurityGroupsRef() + loadBalancerSpec := clusterScope.GetLoadBalancer() + loadBalancerSpec.SetDefaultValue() + loadBalancerSecurityGroupName := loadBalancerSpec.SecurityGroupName + ipProtocol := strings.ToLower(loadBalancerSpec.Listener.BackendProtocol) + machineScope.V(4).Info("Get IpProtocol", "IpProtocol", ipProtocol) + fromPortRange := loadBalancerSpec.Listener.BackendPort + machineScope.V(4).Info("Get fromPortRange", "fromPortRange", fromPortRange) + toPortRange := loadBalancerSpec.Listener.BackendPort + machineScope.V(4).Info("Get ToPortRange", "ToPortRange", toPortRange) + loadBalancerSecurityGroupClusterScopeName := loadBalancerSecurityGroupName + "-" + clusterScope.GetUID() + associateSecurityGroupId := securityGroupsRef.ResourceMap[loadBalancerSecurityGroupClusterScopeName] + machineScope.V(4).Info("Get sg", "associateSecurityGroupId", associateSecurityGroupId) + securityGroupFromSecurityGroupOutboundRule, err := securityGroupSvc.GetSecurityGroupFromSecurityGroupRule(associateSecurityGroupId, "Outbound", ipProtocol, "", securityGroupIds[0], fromPortRange, toPortRange) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not get outbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) + } + if securityGroupFromSecurityGroupOutboundRule == nil { + _, err = securityGroupSvc.CreateSecurityGroupRule(associateSecurityGroupId, "Outbound", ipProtocol, "", securityGroupIds[0], fromPortRange, toPortRange) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not create outbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) + } + } + securityGroupFromSecurityGroupInboundRule, err := securityGroupSvc.GetSecurityGroupFromSecurityGroupRule(securityGroupIds[0], "Inbound", ipProtocol, "", associateSecurityGroupId, fromPortRange, toPortRange) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not create outbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) + return reconcile.Result{}, fmt.Errorf("%w Can not get inbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) } + if securityGroupFromSecurityGroupInboundRule == nil { + _, err = securityGroupSvc.CreateSecurityGroupRule(securityGroupIds[0], "Inbound", ipProtocol, "", associateSecurityGroupId, fromPortRange, toPortRange) + if err != nil { + return reconcile.Result{}, fmt.Errorf("%w Can not create inbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) + } + } + } + + clusterName := vmSpec.ClusterName + "-" + clusterScope.GetUID() + vm, err = vmSvc.GetVm(vmId) + if err != nil { + return reconcile.Result{}, err } - securityGroupFromSecurityGroupInboundRule, err := securityGroupSvc.GetSecurityGroupFromSecurityGroupRule(securityGroupIds[0], "Inbound", ipProtocol, "", associateSecurityGroupId, fromPortRange, toPortRange) + + privateDnsName, ok := vm.GetPrivateDnsNameOk() + if !ok { + return reconcile.Result{}, fmt.Errorf("cannot find privateDnsName %s/%s", machineScope.GetNamespace(), machineScope.GetName()) + } + privateIp, ok := vm.GetPrivateIpOk() + if !ok { + return reconcile.Result{}, fmt.Errorf("cannot find privateIp %s/%s", machineScope.GetNamespace(), machineScope.GetName()) + } + addresses := []corev1.NodeAddress{} + addresses = append( + addresses, + corev1.NodeAddress{ + Type: corev1.NodeInternalIP, + Address: *privateIp, + }, + ) + // Expose Public IP if one is set + if publicIp, ok := vm.GetPublicIpOk(); ok { + addresses = append(addresses, corev1.NodeAddress{ + Type: corev1.NodeExternalIP, + Address: *publicIp, + }) + } + machineScope.SetAddresses(addresses) + + tag, err := tagSvc.ReadTag("OscK8sNodeName", *privateDnsName) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not get inbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) + return reconcile.Result{}, fmt.Errorf("%w Can not get tag for OscMachine %s/%s", err, machineScope.GetNamespace(), machineScope.GetName()) } - if securityGroupFromSecurityGroupInboundRule == nil { - _, err = securityGroupSvc.CreateSecurityGroupRule(securityGroupIds[0], "Inbound", ipProtocol, "", associateSecurityGroupId, fromPortRange, toPortRange) + if tag == nil { + err = vmSvc.AddCcmTag(clusterName, *privateDnsName, vmId) if err != nil { - return reconcile.Result{}, fmt.Errorf("%w Can not create inbound securityGroupRule for OscCluster %s/%s", err, clusterScope.GetNamespace(), clusterScope.GetName()) + return reconcile.Result{}, fmt.Errorf("%w can not add ccm tag %s/%s", err, machineScope.GetNamespace(), machineScope.GetName()) } } - } - - machineScope.V(2).Info("Get Vm", "vm", vm) - vmRef.ResourceMap[vmName] = vmID - vmSpec.ResourceId = vmID - subregionName := vmSpec.SubregionName - machineScope.SetProviderID(subregionName, vmID) } + machineScope.V(4).Info("Vm is reconciled") return reconcile.Result{}, nil } // reconcileDeleteVm reconcile the destruction of the vm of the machine func reconcileDeleteVm(ctx context.Context, clusterScope *scope.ClusterScope, machineScope *scope.MachineScope, vmSvc compute.OscVmInterface, publicIpSvc security.OscPublicIpInterface, loadBalancerSvc service.OscLoadBalancerInterface, securityGroupSvc security.OscSecurityGroupInterface) (reconcile.Result, error) { - oscmachine := machineScope.OscMachine vmSpec := machineScope.GetVm() + vmRef := machineScope.GetVmRef() + vmName := vmSpec.Name + "-" + machineScope.GetUID() vmSpec.SetDefaultValue() vmId := vmSpec.ResourceId - machineScope.V(4).Info("Get VmID", "vmId", vmId) - vmName := vmSpec.Name - if vmSpec.ResourceId == "" { - machineScope.V(2).Info("The desired vm is currently destroyed", "vmName", vmName) - controllerutil.RemoveFinalizer(oscmachine, "") + if vmId == "" { // We should not get in this situation but we sometimes do (To be investigated) + vmId = vmRef.ResourceMap[vmName] + machineScope.SetVmID(vmId) + } + if vmId == "" { + machineScope.V(2).Info("The desired vm is already destroyed", "vmName", vmName) return reconcile.Result{}, nil } - keypairSpec := machineScope.GetKeypair() - machineScope.V(4).Info("Check keypair", "keypair", keypairSpec.Name) - deleteKeypair := machineScope.GetDeleteKeypair() - + machineScope.V(4).Info("Get vmId", "vmId", vmId) vm, err := vmSvc.GetVm(vmId) if err != nil { return reconcile.Result{}, err } + if vm == nil { + machineScope.V(2).Info("The desired vm is already destroyed", "vmName", vmName) + return reconcile.Result{}, nil + } + + keypairSpec := machineScope.GetKeypair() + machineScope.V(4).Info("Check keypair", "keypair", keypairSpec.Name) + deleteKeypair := machineScope.GetDeleteKeypair() var securityGroupIds []string vmSecurityGroups := machineScope.GetVmSecurityGroups() @@ -600,6 +649,7 @@ func reconcileDeleteVm(ctx context.Context, clusterScope *scope.ClusterScope, ma } securityGroupIds = append(securityGroupIds, securityGroupId) } + if vmSpec.PublicIpName != "" { linkPublicIpRef := machineScope.GetLinkPublicIpRef() publicIpName := vmSpec.PublicIpName + "-" + clusterScope.GetUID() @@ -707,15 +757,13 @@ func reconcileDeleteVm(ctx context.Context, clusterScope *scope.ClusterScope, ma if vm == nil { machineScope.V(2).Info("The desired vm does not exist anymore", "vmName", vmName) - controllerutil.RemoveFinalizer(oscmachine, "") return reconcile.Result{}, nil } - err = vmSvc.DeleteVm(vmId) - vmSpec.ResourceId = "" machineScope.V(2).Info("Delete the desired vm", "vmName", vmName) + err = vmSvc.DeleteVm(vmId) if err != nil { return reconcile.Result{RequeueAfter: 30 * time.Second}, fmt.Errorf("%w Can not delete vm for OscMachine %s/%s", err, machineScope.GetNamespace(), machineScope.GetName()) } - return reconcile.Result{RequeueAfter: 30 * time.Second}, nil + return reconcile.Result{}, nil } diff --git a/controllers/oscmachine_vm_controller_unit_test.go b/controllers/oscmachine_vm_controller_unit_test.go index 788e1f841..86d1ec8bf 100644 --- a/controllers/oscmachine_vm_controller_unit_test.go +++ b/controllers/oscmachine_vm_controller_unit_test.go @@ -2269,7 +2269,6 @@ func TestReconcileVm(t *testing.T) { clusterScope, machineScope, ctx, mockOscVmInterface, mockOscVolumeInterface, mockOscPublicIpInterface, mockOscLoadBalancerInterface, mockOscSecurityGroupInterface, mockOscTagInterface := SetupWithVmMock(t, vtc.name, vtc.clusterSpec, vtc.machineSpec) vmName := vtc.machineSpec.Node.Vm.Name + "-uid" vmId := "i-" + vmName - vmState := "running" vmTags := vtc.machineSpec.Node.Vm.Tags volumeName := vtc.machineSpec.Node.Vm.VolumeName + "-uid" @@ -2321,9 +2320,7 @@ func TestReconcileVm(t *testing.T) { deviceName := vtc.machineSpec.Node.Vm.DeviceName vmSpec := vtc.machineSpec.Node.Vm var clockInsideLoop time.Duration = 20 - var firstClockInsideLoop time.Duration = 20 var clockLoop time.Duration = 240 - var firstClockLoop time.Duration = 240 loadBalancerName := vtc.machineSpec.Node.Vm.LoadBalancerName loadBalancerSpec := clusterScope.GetLoadBalancer() loadBalancerSpec.SetDefaultValue() @@ -2386,11 +2383,6 @@ func TestReconcileVm(t *testing.T) { Return(nil, vtc.expCreateVmErr) } - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(firstClockInsideLoop), gomock.Eq(firstClockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStateBootErr) - if vtc.machineSpec.Node.Vm.VolumeName != "" { mockOscVolumeInterface. EXPECT(). @@ -2408,11 +2400,6 @@ func TestReconcileVm(t *testing.T) { } - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStateVolumeErr) - if vtc.expLinkPublicIpFound { mockOscPublicIpInterface. EXPECT(). @@ -2425,11 +2412,6 @@ func TestReconcileVm(t *testing.T) { Return("", vtc.expLinkPublicIpErr) } - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStatePublicIpErr) - vmIds := []string{vmId} mockOscLoadBalancerInterface. EXPECT(). @@ -2692,7 +2674,6 @@ func TestReconcileVmLink(t *testing.T) { clusterScope, machineScope, ctx, mockOscVmInterface, mockOscVolumeInterface, mockOscPublicIpInterface, mockOscLoadBalancerInterface, mockOscSecurityGroupInterface, mockOscTagInterface := SetupWithVmMock(t, vtc.name, vtc.clusterSpec, vtc.machineSpec) vmName := vtc.machineSpec.Node.Vm.Name + "-uid" vmId := "i-" + vmName - vmState := "running" volumeName := vtc.machineSpec.Node.Vm.VolumeName + "-uid" volumeId := "vol-" + volumeName @@ -2763,9 +2744,7 @@ func TestReconcileVmLink(t *testing.T) { volumeDeviceName := vtc.machineSpec.Node.Vm.VolumeDeviceName var clockInsideLoop time.Duration = 20 - var firstClockInsideLoop time.Duration = 20 var clockLoop time.Duration = 240 - var firstClockLoop time.Duration = 240 if vtc.expCreateVmFound { mockOscVmInterface. EXPECT(). @@ -2778,13 +2757,6 @@ func TestReconcileVmLink(t *testing.T) { Return(nil, vtc.expCreateVmErr) } - if vtc.expCheckVmStateBootFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(firstClockInsideLoop), gomock.Eq(firstClockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStateBootErr) - } - if vtc.expCheckVolumeStateAvailableFound { mockOscVolumeInterface. EXPECT(). @@ -2923,7 +2895,6 @@ func TestReconcileVmLinkPubicIp(t *testing.T) { clusterScope, machineScope, ctx, mockOscVmInterface, mockOscVolumeInterface, mockOscPublicIpInterface, mockOscLoadBalancerInterface, mockOscSecurityGroupInterface, mockOscTagInterface := SetupWithVmMock(t, vtc.name, vtc.clusterSpec, vtc.machineSpec) vmName := vtc.machineSpec.Node.Vm.Name + "-uid" vmId := "i-" + vmName - vmState := "running" volumeName := vtc.machineSpec.Node.Vm.VolumeName + "-uid" volumeId := "vol-" + volumeName @@ -2971,9 +2942,7 @@ func TestReconcileVmLinkPubicIp(t *testing.T) { vmSpec := vtc.machineSpec.Node.Vm var clockInsideLoop time.Duration = 20 - var firstClockInsideLoop time.Duration = 20 var clockLoop time.Duration = 240 - var firstClockLoop time.Duration = 240 createVms := osc.CreateVmsResponse{ Vms: &[]osc.Vm{ @@ -3013,11 +2982,6 @@ func TestReconcileVmLinkPubicIp(t *testing.T) { Return(nil, vtc.expCreateVmErr) } - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(firstClockInsideLoop), gomock.Eq(firstClockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStateBootErr) - if vtc.machineSpec.Node.Vm.VolumeName != "" { mockOscVolumeInterface. EXPECT(). @@ -3036,12 +3000,6 @@ func TestReconcileVmLinkPubicIp(t *testing.T) { CheckVolumeState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(volumeStateUse), gomock.Eq(volumeId)). Return(vtc.expCheckVolumeStateUseErr) } - if vtc.expCheckVmStateVolumeFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStateVolumeErr) - } if vtc.expLinkPublicIpFound { mockOscPublicIpInterface. @@ -3049,12 +3007,6 @@ func TestReconcileVmLinkPubicIp(t *testing.T) { LinkPublicIp(gomock.Eq(publicIpId), gomock.Eq(vmId)). Return("", vtc.expLinkPublicIpErr) } - if vtc.expCheckVmStatePublicIpFound { - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStatePublicIpErr) - } reconcileVm, err := reconcileVm(ctx, clusterScope, machineScope, mockOscVmInterface, mockOscVolumeInterface, mockOscPublicIpInterface, mockOscLoadBalancerInterface, mockOscSecurityGroupInterface, mockOscTagInterface) if err != nil { @@ -3116,7 +3068,6 @@ func TestReconcileVmSecurityGroup(t *testing.T) { clusterScope, machineScope, ctx, mockOscVmInterface, mockOscVolumeInterface, mockOscPublicIpInterface, mockOscLoadBalancerInterface, mockOscSecurityGroupInterface, mockOscTagInterface := SetupWithVmMock(t, vtc.name, vtc.clusterSpec, vtc.machineSpec) vmName := vtc.machineSpec.Node.Vm.Name + "-uid" vmId := "i-" + vmName - vmState := "running" tag := osc.Tag{ ResourceId: &vmId, @@ -3179,9 +3130,7 @@ func TestReconcileVmSecurityGroup(t *testing.T) { deviceName := vtc.machineSpec.Node.Vm.DeviceName vmSpec := vtc.machineSpec.Node.Vm var clockInsideLoop time.Duration = 20 - var firstClockInsideLoop time.Duration = 20 var clockLoop time.Duration = 240 - var firstClockLoop time.Duration = 240 loadBalancerName := vtc.machineSpec.Node.Vm.LoadBalancerName createVms := osc.CreateVmsResponse{ @@ -3209,10 +3158,6 @@ func TestReconcileVmSecurityGroup(t *testing.T) { Return(nil, vtc.expCreateVmErr) } - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(firstClockInsideLoop), gomock.Eq(firstClockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStateBootErr) if vtc.machineSpec.Node.Vm.VolumeName != "" { mockOscVolumeInterface. @@ -3230,10 +3175,6 @@ func TestReconcileVmSecurityGroup(t *testing.T) { CheckVolumeState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(volumeStateUse), gomock.Eq(volumeId)). Return(vtc.expCheckVolumeStateUseErr) } - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStateVolumeErr) if vtc.expLinkPublicIpFound { mockOscPublicIpInterface. @@ -3247,11 +3188,6 @@ func TestReconcileVmSecurityGroup(t *testing.T) { Return("", vtc.expLinkPublicIpErr) } - mockOscVmInterface. - EXPECT(). - CheckVmState(gomock.Eq(clockInsideLoop), gomock.Eq(clockLoop), gomock.Eq(vmState), gomock.Eq(vmId)). - Return(vtc.expCheckVmStatePublicIpErr) - vmIds := []string{vmId} mockOscLoadBalancerInterface. EXPECT(). diff --git a/docs/src/topics/get-started-with-clusterctl.md b/docs/src/topics/get-started-with-clusterctl.md index 0db384a1f..b14a03ee2 100644 --- a/docs/src/topics/get-started-with-clusterctl.md +++ b/docs/src/topics/get-started-with-clusterctl.md @@ -113,25 +113,6 @@ spec: ``` -## Add a public ip after bastion is created - -You can add a public ip if you set publicIpNameAfterBastion = true after you have already create a cluster with a bastion. - -```yaml -apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 -kind: OscCluster -metadata: - name: cluster-api - namespace: default -spec: - network: - ... - bastion: - .. - publicIpNameAfterBastion: true -``` - - ### Get Kubeconfig You can then get the status: ```