diff --git a/api/v1beta1/ocicluster_types.go b/api/v1beta1/ocicluster_types.go index 2dfcdfd73..0359ab3bc 100644 --- a/api/v1beta1/ocicluster_types.go +++ b/api/v1beta1/ocicluster_types.go @@ -71,6 +71,11 @@ type OCIClusterStatus struct { // +optional FailureDomains clusterv1.FailureDomains `json:"failureDomains,omitempty"` + // AvailabilityDomains encapsulates the clusters Availability Domain (AD) information in a map + // where the map key is the AD name and the struct is details about the AD. + // +optional + AvailabilityDomains map[string]OCIAvailabilityDomain `json:"availabilityDomains,omitempty"` + // +optional Ready bool `json:"ready"` // NetworkSpec encapsulates all things related to OCI network. @@ -99,6 +104,16 @@ type OCIClusterList struct { Items []OCICluster `json:"items"` } +// OCIAvailabilityDomain contains information about an Availability Domain (AD). +type OCIAvailabilityDomain struct { + + // Name is the AD's full name. Example: Uocm:PHX-AD-1 + Name string `json:"name,omitempty"` + + // FaultDomains a list of fault domain (FD) names. Example: ["FAULT-DOMAIN-1"] + FaultDomains []string `json:"faultDomains,omitempty"` +} + // GetConditions returns the list of conditions for an OCICluster API object. func (c *OCICluster) GetConditions() clusterv1.Conditions { return c.Status.Conditions diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 5afe11ab2..bdae014be 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -320,6 +320,26 @@ func (in *NetworkSpec) DeepCopy() *NetworkSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCIAvailabilityDomain) DeepCopyInto(out *OCIAvailabilityDomain) { + *out = *in + if in.FaultDomains != nil { + in, out := &in.FaultDomains, &out.FaultDomains + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIAvailabilityDomain. +func (in *OCIAvailabilityDomain) DeepCopy() *OCIAvailabilityDomain { + if in == nil { + return nil + } + out := new(OCIAvailabilityDomain) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OCICluster) DeepCopyInto(out *OCICluster) { *out = *in @@ -430,6 +450,13 @@ func (in *OCIClusterStatus) DeepCopyInto(out *OCIClusterStatus) { (*out)[key] = *val.DeepCopy() } } + if in.AvailabilityDomains != nil { + in, out := &in.AvailabilityDomains, &out.AvailabilityDomains + *out = make(map[string]OCIAvailabilityDomain, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions *out = make(apiv1beta1.Conditions, len(*in)) diff --git a/cloud/scope/clients.go b/cloud/scope/clients.go index 9c96b345d..9d481fae3 100644 --- a/cloud/scope/clients.go +++ b/cloud/scope/clients.go @@ -17,7 +17,6 @@ limitations under the License. package scope import ( - "fmt" "sync" "github.com/go-logr/logr" @@ -90,7 +89,6 @@ func (c *ClientProvider) GetOrBuildClient(region string) (OCIClients, error) { return regionalClient, err } c.ociClients[region] = regionalClient - fmt.Println("------ regional client", regionalClient.ComputeManagementClient) return regionalClient, nil } @@ -106,7 +104,6 @@ func createClients(region string, oCIAuthConfigProvider common.ConfigurationProv return OCIClients{}, err } - fmt.Println("------ computeManagementClient", computeManagementClient) return OCIClients{ VCNClient: vcnClient, LoadBalancerClient: lbClient, diff --git a/cloud/scope/cluster.go b/cloud/scope/cluster.go index 79c823bb1..0c9aa27d8 100644 --- a/cloud/scope/cluster.go +++ b/cloud/scope/cluster.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "reflect" + "sigs.k8s.io/cluster-api/util/conditions" "strconv" "github.com/oracle/cluster-api-provider-oci/cloud/services/vcn" @@ -108,6 +109,7 @@ func NewClusterScope(params ClusterScopeParams) (*ClusterScope, error) { // PatchObject persists the cluster configuration and status. func (s *ClusterScope) PatchObject(ctx context.Context) error { + conditions.SetSummary(s.OCICluster) return s.patchHelper.Patch(ctx, s.OCICluster) } @@ -137,15 +139,21 @@ func (s *ClusterScope) IsResourceCreatedByClusterAPI(resourceFreeFormTags map[st // in case of single AD regions, the failure domain will be fault domain, in case of multi Ad regions, it will // be AD func (s *ClusterScope) setFailureDomains(ctx context.Context) error { - req := identity.ListAvailabilityDomainsRequest{CompartmentId: common.String(s.GetCompartmentId())} + reqAd := identity.ListAvailabilityDomainsRequest{CompartmentId: common.String(s.GetCompartmentId())} - resp, err := s.IdentityClient.ListAvailabilityDomains(ctx, req) + respAd, err := s.IdentityClient.ListAvailabilityDomains(ctx, reqAd) if err != nil { s.Logger.Error(err, "failed to list identity domains") return err } - numOfAds := len(resp.Items) + // build the AD list for cluster + err = s.setAvailabiltyDomainStatus(ctx, respAd.Items) + if err != nil { + return err + } + + numOfAds := len(respAd.Items) if numOfAds != 1 && numOfAds != 3 { err := errors.New(fmt.Sprintf("invalid number of Availability Domains, should be either 1 or 3, but got %d", numOfAds)) s.Logger.Error(err, "invalid number of Availability Domains") @@ -153,7 +161,7 @@ func (s *ClusterScope) setFailureDomains(ctx context.Context) error { } if numOfAds == 3 { - for i, ad := range resp.Items { + for i, ad := range respAd.Items { s.SetFailureDomain(strconv.Itoa(i+1), clusterv1.FailureDomainSpec{ ControlPlane: true, Attributes: map[string]string{AvailabilityDomain: *ad.Name}, @@ -162,7 +170,7 @@ func (s *ClusterScope) setFailureDomains(ctx context.Context) error { } else { req := identity.ListFaultDomainsRequest{ CompartmentId: common.String(s.GetCompartmentId()), - AvailabilityDomain: resp.Items[0].Name, + AvailabilityDomain: respAd.Items[0].Name, } resp, err := s.IdentityClient.ListFaultDomains(ctx, req) if err != nil { @@ -191,6 +199,38 @@ func (s *ClusterScope) SetFailureDomain(id string, spec clusterv1.FailureDomainS s.OCICluster.Status.FailureDomains[id] = spec } +// setAvailabiltyDomainStatus builds the OCIAvailabilityDomain list and sets the OCICluster's status with this list +// so that other parts of the provider have access to ADs and FDs without having to make multiple calls to identity. +func (s *ClusterScope) setAvailabiltyDomainStatus(ctx context.Context, ads []identity.AvailabilityDomain) error { + clusterAds := make(map[string]infrastructurev1beta1.OCIAvailabilityDomain) + for _, ad := range ads { + reqFd := identity.ListFaultDomainsRequest{ + CompartmentId: common.String(s.GetCompartmentId()), + AvailabilityDomain: ad.Name, + } + respFd, err := s.IdentityClient.ListFaultDomains(ctx, reqFd) + if err != nil { + s.Logger.Error(err, "failed to list fault domains") + return err + } + + var faultDomains []string + for _, fd := range respFd.Items { + faultDomains = append(faultDomains, *fd.Name) + } + + adName := *ad.Name + clusterAds[adName] = infrastructurev1beta1.OCIAvailabilityDomain{ + Name: adName, + FaultDomains: faultDomains, + } + } + + s.OCICluster.Status.AvailabilityDomains = clusterAds + + return nil +} + func (s *ClusterScope) IsTagsEqual(freeFromTags map[string]string, definedTags map[string]map[string]interface{}) bool { if reflect.DeepEqual(freeFromTags, s.GetFreeFormTags()) && reflect.DeepEqual(definedTags, s.GetDefinedTags()) { return true diff --git a/cloud/scope/machine.go b/cloud/scope/machine.go index 5d5e3f3d1..da00c3468 100644 --- a/cloud/scope/machine.go +++ b/cloud/scope/machine.go @@ -21,6 +21,7 @@ import ( "encoding/base64" "fmt" "math/rand" + "sigs.k8s.io/cluster-api/util/conditions" "strconv" "time" @@ -330,6 +331,7 @@ func (m *MachineScope) GetMachineByDisplayName(ctx context.Context, name string) // PatchObject persists the cluster configuration and status. func (m *MachineScope) PatchObject(ctx context.Context) error { + conditions.SetSummary(m.OCIMachine) return m.patchHelper.Patch(ctx, m.OCIMachine) } diff --git a/cloud/scope/machine_pool.go b/cloud/scope/machine_pool.go index 273869961..8545b46d9 100644 --- a/cloud/scope/machine_pool.go +++ b/cloud/scope/machine_pool.go @@ -1,5 +1,5 @@ /* - Copyright (c) 2021, 2022 Oracle and/or its affiliates. + Copyright (c) 2022 Oracle and/or its affiliates. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -19,7 +19,9 @@ package scope import ( "context" "fmt" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "strconv" + "strings" "github.com/oracle/cluster-api-provider-oci/cloud/ociutil" expinfra1 "github.com/oracle/cluster-api-provider-oci/exp/api/v1beta1" @@ -35,12 +37,8 @@ import ( "github.com/go-logr/logr" infrastructurev1beta1 "github.com/oracle/cluster-api-provider-oci/api/v1beta1" - "github.com/oracle/cluster-api-provider-oci/cloud/services/compute" "github.com/oracle/cluster-api-provider-oci/cloud/services/computemanagement" - nlb "github.com/oracle/cluster-api-provider-oci/cloud/services/networkloadbalancer" - "github.com/oracle/cluster-api-provider-oci/cloud/services/vcn" "github.com/pkg/errors" - clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -48,34 +46,26 @@ const OCIMachinePoolKind = "OCIMachinePool" // MachineScopeParams defines the params need to create a new MachineScope type MachinePoolScopeParams struct { - Logger *logr.Logger - Cluster *clusterv1.Cluster - MachinePool *expclusterv1.MachinePool - Client client.Client - ComputeClient compute.ComputeClient - ComputeManagementClient computemanagement.Client - OCICluster *infrastructurev1beta1.OCICluster - OCIMachinePool *expinfra1.OCIMachinePool - VCNClient vcn.Client - NetworkLoadBalancerClient nlb.NetworkLoadBalancerClient - Machine *clusterv1.Machine - OCIMachine *infrastructurev1beta1.OCIMachine + Logger *logr.Logger + Cluster *clusterv1.Cluster + MachinePool *expclusterv1.MachinePool + Client client.Client + ComputeManagementClient computemanagement.Client + OCICluster *infrastructurev1beta1.OCICluster + OCIMachinePool *expinfra1.OCIMachinePool + OCIMachine *infrastructurev1beta1.OCIMachine } type MachinePoolScope struct { *logr.Logger - Client client.Client - patchHelper *patch.Helper - Cluster *clusterv1.Cluster - MachinePool *expclusterv1.MachinePool - ComputeClient compute.ComputeClient - ComputeManagementClient computemanagement.Client - OCICluster *infrastructurev1beta1.OCICluster - OCIMachinePool *expinfra1.OCIMachinePool - VCNClient vcn.Client - NetworkLoadBalancerClient nlb.NetworkLoadBalancerClient - Machine *clusterv1.Machine - OCIMachine *infrastructurev1beta1.OCIMachine + Client client.Client + patchHelper *patch.Helper + Cluster *clusterv1.Cluster + MachinePool *expclusterv1.MachinePool + ComputeManagementClient computemanagement.Client + OCICluster *infrastructurev1beta1.OCICluster + OCIMachinePool *expinfra1.OCIMachinePool + OCIMachine *infrastructurev1beta1.OCIMachine } // NewMachinePoolScope creates a MachinePoolScope given the MachinePoolScopeParams @@ -97,18 +87,14 @@ func NewMachinePoolScope(params MachinePoolScopeParams) (*MachinePoolScope, erro } return &MachinePoolScope{ - Logger: params.Logger, - Client: params.Client, - ComputeClient: params.ComputeClient, - ComputeManagementClient: params.ComputeManagementClient, - Cluster: params.Cluster, - OCICluster: params.OCICluster, - patchHelper: helper, - MachinePool: params.MachinePool, - OCIMachinePool: params.OCIMachinePool, - VCNClient: params.VCNClient, - NetworkLoadBalancerClient: params.NetworkLoadBalancerClient, - Machine: params.Machine, + Logger: params.Logger, + Client: params.Client, + ComputeManagementClient: params.ComputeManagementClient, + Cluster: params.Cluster, + OCICluster: params.OCICluster, + patchHelper: helper, + MachinePool: params.MachinePool, + OCIMachinePool: params.OCIMachinePool, }, nil } @@ -152,11 +138,10 @@ func (m *MachinePoolScope) SetReady() { m.OCIMachinePool.Status.Ready = true } +// GetWorkerMachineSubnet returns the WorkerRole core.Subnet id for the cluster func (m *MachinePoolScope) GetWorkerMachineSubnet() *string { for _, subnet := range m.OCICluster.Spec.NetworkSpec.Vcn.Subnets { - fmt.Println("---- subnet", subnet.Name) if subnet.Role == infrastructurev1beta1.WorkerRole { - // if a subnet name is defined, use the correct subnet return subnet.ID } } @@ -182,17 +167,19 @@ func (m *MachinePoolScope) GetBootstrapData() (string, error) { return string(value), nil } +// GetWorkerMachineNSG returns the worker role core.NetworkSecurityGroup id for the cluster func (m *MachinePoolScope) GetWorkerMachineNSG() *string { for _, nsg := range m.OCICluster.Spec.NetworkSpec.Vcn.NetworkSecurityGroups { if nsg.Role == infrastructurev1beta1.WorkerRole { - // if an NSG name is defined, use the correct NSG return nsg.ID } } return nil } -func (m *MachinePoolScope) BuildInstanceConfirgurationShapeConfig() (core.InstanceConfigurationLaunchInstanceShapeConfigDetails, error) { +// BuildInstanceConfigurationShapeConfig builds the core.InstanceConfigurationLaunchInstanceShapeConfigDetails based +// on the MachinePoolScope +func (m *MachinePoolScope) BuildInstanceConfigurationShapeConfig() (core.InstanceConfigurationLaunchInstanceShapeConfigDetails, error) { shapeConfig := core.InstanceConfigurationLaunchInstanceShapeConfigDetails{} if (m.OCIMachinePool.Spec.ShapeConfig != expinfra1.ShapeConfig{}) { ocpuString := m.OCIMachinePool.Spec.ShapeConfig.Ocpus @@ -227,7 +214,57 @@ func (m *MachinePoolScope) BuildInstanceConfirgurationShapeConfig() (core.Instan return shapeConfig, nil } -// TODO: pull the following funcs out into different file +func (s *MachinePoolScope) BuildInstancePoolPlacement() ([]core.CreateInstancePoolPlacementConfigurationDetails, error) { + var placements []core.CreateInstancePoolPlacementConfigurationDetails + + failureDomains := s.OCICluster.Status.FailureDomains + ads := s.OCICluster.Status.AvailabilityDomains + + var adNames []string + for _, fd := range failureDomains { + ad := fd.Attributes[AvailabilityDomain] + if len(ad) >= 0 { + adNames = append(adNames, ad) + } + } + + specPlacementDetails := s.OCIMachinePool.Spec.PlacementDetails + + // make sure user doesn't specify 3 ads when there is only one available + if len(specPlacementDetails) > len(ads) { + errMsg := fmt.Sprintf("Cluster has %d ADs specified and the machine pools spec has %d", len(ads), len(specPlacementDetails)) + return nil, errors.New(errMsg) + } + + // build placements from the user spec + for _, ad := range ads { + for _, specPlacment := range specPlacementDetails { + if strings.HasSuffix(ad.Name, strconv.Itoa(specPlacment.AvailabilityDomain)) { + placement := core.CreateInstancePoolPlacementConfigurationDetails{ + AvailabilityDomain: common.String(ad.Name), + PrimarySubnetId: s.GetWorkerMachineSubnet(), + FaultDomains: ad.FaultDomains, + } + s.Info("Adding machine placement for AD", "AD", ad.Name) + placements = append(placements, placement) + } + } + } + + // build placements if the user hasn't specified any + if len(placements) <= 0 { + for _, ad := range ads { + placement := core.CreateInstancePoolPlacementConfigurationDetails{ + AvailabilityDomain: common.String(ad.Name), + PrimarySubnetId: s.GetWorkerMachineSubnet(), + FaultDomains: ad.FaultDomains, + } + placements = append(placements, placement) + } + } + + return placements, nil +} // IsResourceCreatedByClusterAPI determines if the instance was created by the cluster using the // tags created at instance launch. @@ -241,32 +278,9 @@ func (s *MachinePoolScope) IsResourceCreatedByClusterAPI(resourceFreeFormTags ma return true } -// GetInstanceConfigurationByDisplayName returns the existing LaunchTemplate or nothing if it doesn't exist. -// For now by name until we need the input to be something different. -func (m *MachinePoolScope) GetInstanceConfigurationIdBy(ctx context.Context) (string, error) { - req := core.ListInstanceConfigurationsRequest{ - SortBy: core.ListInstanceConfigurationsSortByDisplayname, - CompartmentId: common.String(m.OCICluster.Spec.CompartmentId)} - // TODO: will want to paginate to make sure we hit all the configurations (testing now assumes very few configs in compartment) - resp, err := m.ComputeManagementClient.ListInstanceConfigurations(ctx, req) - if err != nil { - return "", err - } - if len(resp.Items) == 0 { - return "", nil - } - for _, instance := range resp.Items { - if m.IsResourceCreatedByClusterAPI(instance.FreeformTags) { - return *instance.Id, nil - } - } - return "", nil -} - -// TODO: unexport this later +// GetFreeFormTags gets the free form tags for the MachinePoolScope cluster and returns them func (m *MachinePoolScope) GetFreeFormTags(ociCluster infrastructurev1beta1.OCICluster) map[string]string { tags := ociutil.BuildClusterTags(ociCluster.GetOCIResourceIdentifier()) - // first use cluster level tags, then override with machine level tags if ociCluster.Spec.FreeformTags != nil { for k, v := range ociCluster.Spec.FreeformTags { tags[k] = v diff --git a/cloud/services/computemanagement/client.go b/cloud/services/computemanagement/client.go index 3533d76b5..4b0b3a64a 100644 --- a/cloud/services/computemanagement/client.go +++ b/cloud/services/computemanagement/client.go @@ -19,6 +19,4 @@ type Client interface { GetInstanceConfiguration(ctx context.Context, request core.GetInstanceConfigurationRequest) (response core.GetInstanceConfigurationResponse, err error) ListInstanceConfigurations(ctx context.Context, request core.ListInstanceConfigurationsRequest) (response core.ListInstanceConfigurationsResponse, err error) DeleteInstanceConfiguration(ctx context.Context, request core.DeleteInstanceConfigurationRequest) (response core.DeleteInstanceConfigurationResponse, err error) - //UpdateInstanceConfiguration - //GetInstanceConfiguration } diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ociclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ociclusters.yaml index f53ecb43d..3393af5f6 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ociclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ociclusters.yaml @@ -946,6 +946,25 @@ spec: status: description: OCIClusterStatus defines the observed state of OCICluster properties: + availabilityDomains: + additionalProperties: + description: OCIAvailabilityDomain contains information about an + Availability Domain (AD). + properties: + faultDomains: + description: 'FaultDomains a list of fault domain (FD) names. + Example: ["FAULT-DOMAIN-1"]' + items: + type: string + type: array + name: + description: 'Name is the AD''s full name. Example: Uocm:PHX-AD-1' + type: string + type: object + description: AvailabilityDomains encapsulates the clusters Availability + Domain (AD) information in a map where the map key is the AD name + and the struct is details about the AD. + type: object conditions: description: NetworkSpec encapsulates all things related to OCI network. items: diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ocimachinepools.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ocimachinepools.yaml index fdf3997e0..76c4b0797 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ocimachinepools.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ocimachinepools.yaml @@ -41,60 +41,34 @@ spec: instanceConfiguration: properties: instanceConfigurationId: - description: displayName freeformTags type: string instanceDetails: properties: - launchDetails: - description: LaunchDetails Instance launch details for creating - an instance from an instance configuration https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/datatypes/InstanceConfigurationLaunchInstanceDetails - properties: - metadata: - additionalProperties: - type: string - description: Custom metadata key/value pairs that you - provide, such as the SSH public key required to connect - to the instance. - type: object - shape: - type: string - sourceDetails: - description: SourceDetails source details for instance - launched from instance configuration https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/datatypes/InstanceConfigurationInstanceSourceViaImageDetails - properties: - imageId: - description: OCID of the image to be used to launch - the instance - type: string - type: object - type: object shape: type: string type: object type: object - maxSize: - default: 1 - description: MaxSize defines the maximum size of the group. - format: int32 - minimum: 1 - type: integer metadata: additionalProperties: type: string description: Custom metadata key/value pairs that you provide, such as the SSH public key required to connect to the instance. type: object - minSize: - default: 1 - description: MinSize defines the minimum size of the group. - format: int32 - minimum: 1 - type: integer + placementDetails: + items: + properties: + availabilityDomain: + description: The availability domain to place instances. + type: integer + required: + - availabilityDomain + type: object + type: array providerID: description: ProviderID is the ARN of the associated InstancePool type: string shapeConfig: - description: The shape configuration of rhe instance, applicable for + description: The shape configuration of the instance, applicable for flex instances. properties: baselineOcpuUtilization: @@ -114,9 +88,6 @@ spec: description: The total number of OCPUs available to the instance. type: string type: object - required: - - maxSize - - minSize type: object status: description: OCIMachinePoolStatus defines the observed state of OCIMachinePool diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 22c7d4228..0e6ee9e9d 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -30,7 +30,6 @@ spec: args: - "--leader-elect" - "--feature-gates=MachinePool=${EXP_MACHINE_POOL:=false}" -# - "--v=${CAPA_LOGLEVEL:=8}" - "--metrics-bind-address=127.0.0.1:8080" image: controller:latest name: manager diff --git a/exp/api/v1beta1/conditions_consts.go b/exp/api/v1beta1/conditions_consts.go index 8c4aa57ab..8cb8d1a8a 100644 --- a/exp/api/v1beta1/conditions_consts.go +++ b/exp/api/v1beta1/conditions_consts.go @@ -1,3 +1,19 @@ +/* +Copyright (c) 2022 Oracle and/or its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package v1beta1 import clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" diff --git a/exp/api/v1beta1/groupversion_type.go b/exp/api/v1beta1/groupversion_type.go index beaa56ab4..90bce315c 100644 --- a/exp/api/v1beta1/groupversion_type.go +++ b/exp/api/v1beta1/groupversion_type.go @@ -1,3 +1,19 @@ +/* +Copyright (c) 2022 Oracle and/or its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package v1beta1 import ( diff --git a/exp/api/v1beta1/ocimachinepool_types.go b/exp/api/v1beta1/ocimachinepool_types.go index 753ce0a9b..8f7f5f4fe 100644 --- a/exp/api/v1beta1/ocimachinepool_types.go +++ b/exp/api/v1beta1/ocimachinepool_types.go @@ -1,21 +1,18 @@ /* - * - * Copyright (c) 2022, Oracle and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * / - * - */ +Copyright (c) 2022 Oracle and/or its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package v1beta1 @@ -43,60 +40,40 @@ type OCIMachinePoolSpec struct { // OCID of the image to be used to launch the instance. ImageId string `json:"imageId,omitempty"` - // MinSize defines the minimum size of the group. - // +kubebuilder:default=1 - // +kubebuilder:validation:Minimum=1 - MinSize int32 `json:"minSize"` - - // MaxSize defines the maximum size of the group. - // +kubebuilder:default=1 - // +kubebuilder:validation:Minimum=1 - MaxSize int32 `json:"maxSize"` - // Custom metadata key/value pairs that you provide, such as the SSH public key // required to connect to the instance. Metadata map[string]string `json:"metadata,omitempty"` - // The shape configuration of rhe instance, applicable for flex instances. + // The shape configuration of the instance, applicable for flex instances. ShapeConfig ShapeConfig `json:"shapeConfig,omitempty"` - //TODO Add - // Ad - // subnet - // tags - // MachineTemplateSpec - // MachineDeploymentStrategy - // ProviderIDList + PlacementDetails []PlacementDetails `json:"placementDetails,omitempty"` InstanceConfiguration InstanceConfiguration `json:"instanceConfiguration,omitempty"` } type InstanceConfiguration struct { - // displayName - //freeformTags InstanceConfigurationId *string `json:"instanceConfigurationId,omitempty"` InstanceDetails InstanceDetails `json:"instanceDetails,omitempty"` } +type PlacementDetails struct { + // The availability domain to place instances. + AvailabilityDomain int `mandatory:"true" json:"availabilityDomain"` +} + type InstanceDetails struct { - Shape string `json:"shape,omitempty"` - SourceDetails LaunchDetails `json:"launchDetails,omitempty"` + Shape string `json:"shape,omitempty"` } // LaunchDetails Instance launch details for creating an instance from an instance configuration // https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/datatypes/InstanceConfigurationLaunchInstanceDetails type LaunchDetails struct { - //availabilityDomain - //displayName - //freeformTags - //shapeConfig - // Custom metadata key/value pairs that you provide, such as the SSH public key // required to connect to the instance. Metadata map[string]string `json:"metadata,omitempty"` - Shape string `json:"shape,omitempty"` - SourceDetails SourceDetails `json:"sourceDetails,omitempty"` + Shape string `json:"shape,omitempty"` } // ShapeConfig defines the configuration options for the compute instance shape @@ -117,19 +94,6 @@ type ShapeConfig struct { BaselineOcpuUtilization string `json:"baselineOcpuUtilization,omitempty"` } -// https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/datatypes/InstanceConfigurationLaunchInstanceShapeConfigDetails -// type ShapeConfigDetails struct { -// } - -// SourceDetails source details for instance launched from instance configuration -// https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/datatypes/InstanceConfigurationInstanceSourceViaImageDetails -type SourceDetails struct { - // bootVolumeSizeInGBs - - // OCID of the image to be used to launch the instance - ImageId string `json:"imageId,omitempty"` -} - // OCIMachinePoolStatus defines the observed state of OCIMachinePool type OCIMachinePoolStatus struct { // Ready is true when the provider resource is ready. @@ -143,11 +107,6 @@ type OCIMachinePoolStatus struct { // The ID of the Instance Configuration InstanceConfigurationId string `json:"instanceConfigurationId,omitempty"` - // Todo - // ReadyReplicas - // UnavailableReplicas - // InfrastructureReady - // Conditions defines current service state of the OCIMachinePool. // +optional Conditions clusterv1.Conditions `json:"conditions,omitempty"` diff --git a/exp/api/v1beta1/zz_generated.deepcopy.go b/exp/api/v1beta1/zz_generated.deepcopy.go index 27d137377..c9dbd1e6a 100644 --- a/exp/api/v1beta1/zz_generated.deepcopy.go +++ b/exp/api/v1beta1/zz_generated.deepcopy.go @@ -35,7 +35,7 @@ func (in *InstanceConfiguration) DeepCopyInto(out *InstanceConfiguration) { *out = new(string) **out = **in } - in.InstanceDetails.DeepCopyInto(&out.InstanceDetails) + out.InstanceDetails = in.InstanceDetails } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceConfiguration. @@ -51,7 +51,6 @@ func (in *InstanceConfiguration) DeepCopy() *InstanceConfiguration { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InstanceDetails) DeepCopyInto(out *InstanceDetails) { *out = *in - in.SourceDetails.DeepCopyInto(&out.SourceDetails) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceDetails. @@ -74,7 +73,6 @@ func (in *LaunchDetails) DeepCopyInto(out *LaunchDetails) { (*out)[key] = val } } - out.SourceDetails = in.SourceDetails } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LaunchDetails. @@ -162,6 +160,11 @@ func (in *OCIMachinePoolSpec) DeepCopyInto(out *OCIMachinePoolSpec) { } } out.ShapeConfig = in.ShapeConfig + if in.PlacementDetails != nil { + in, out := &in.PlacementDetails, &out.PlacementDetails + *out = make([]PlacementDetails, len(*in)) + copy(*out, *in) + } in.InstanceConfiguration.DeepCopyInto(&out.InstanceConfiguration) } @@ -208,31 +211,31 @@ func (in *OCIMachinePoolStatus) DeepCopy() *OCIMachinePoolStatus { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ShapeConfig) DeepCopyInto(out *ShapeConfig) { +func (in *PlacementDetails) DeepCopyInto(out *PlacementDetails) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShapeConfig. -func (in *ShapeConfig) DeepCopy() *ShapeConfig { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementDetails. +func (in *PlacementDetails) DeepCopy() *PlacementDetails { if in == nil { return nil } - out := new(ShapeConfig) + out := new(PlacementDetails) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SourceDetails) DeepCopyInto(out *SourceDetails) { +func (in *ShapeConfig) DeepCopyInto(out *ShapeConfig) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceDetails. -func (in *SourceDetails) DeepCopy() *SourceDetails { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ShapeConfig. +func (in *ShapeConfig) DeepCopy() *ShapeConfig { if in == nil { return nil } - out := new(SourceDetails) + out := new(ShapeConfig) in.DeepCopyInto(out) return out } diff --git a/exp/controllers/ocimachinepool_controller.go b/exp/controllers/ocimachinepool_controller.go index 93788fb54..174e8784f 100644 --- a/exp/controllers/ocimachinepool_controller.go +++ b/exp/controllers/ocimachinepool_controller.go @@ -23,6 +23,8 @@ import ( "context" "encoding/base64" "fmt" + "time" + "github.com/go-logr/logr" infrav1exp "github.com/oracle/cluster-api-provider-oci/exp/api/v1beta1" "github.com/oracle/oci-go-sdk/v63/common" @@ -39,7 +41,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" - "time" infrastructurev1beta1 "github.com/oracle/cluster-api-provider-oci/api/v1beta1" "github.com/oracle/cluster-api-provider-oci/cloud/scope" @@ -141,16 +142,13 @@ func (r *OCIMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Reque // Create the machine pool scope machinePoolScope, err := scope.NewMachinePoolScope(scope.MachinePoolScopeParams{ - Client: r.Client, - ComputeClient: clients.ComputeClient, - ComputeManagementClient: clients.ComputeManagementClient, - Logger: &logger, - Cluster: cluster, - OCICluster: ociCluster, - MachinePool: machinePool, - OCIMachinePool: ociMachinePool, - VCNClient: clients.VCNClient, - NetworkLoadBalancerClient: clients.LoadBalancerClient, + Client: r.Client, + ComputeManagementClient: clients.ComputeManagementClient, + Logger: &logger, + Cluster: cluster, + OCICluster: ociCluster, + MachinePool: machinePool, + OCIMachinePool: ociMachinePool, }) if err != nil { return ctrl.Result{}, errors.Errorf("failed to create scope: %+v", err) @@ -158,7 +156,6 @@ func (r *OCIMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Reque // Always close the scope when exiting this function so we can persist any GCPMachine changes. defer func() { - logger.Info("---- closing scope") if err := machinePoolScope.Close(ctx); err != nil && reterr == nil { reterr = err } @@ -259,10 +256,10 @@ func (r *OCIMachinePoolReconciler) reconcileNormal(ctx context.Context, logger l return reconcile.Result{}, err } - //if !machinePoolScope.Cluster.Status.InfrastructureReady { - // logger.Info("Cluster infrastructure is not ready yet") - // return reconcile.Result{}, nil - //} + if !machinePoolScope.Cluster.Status.InfrastructureReady { + logger.Info("Cluster infrastructure is not ready yet") + return reconcile.Result{}, nil + } // Make sure bootstrap data is available and populated. if machinePoolScope.MachinePool.Spec.Template.Spec.Bootstrap.DataSecretName == nil { @@ -274,14 +271,12 @@ func (r *OCIMachinePoolReconciler) reconcileNormal(ctx context.Context, logger l // get or create the InstanceConfiguration // https://docs.oracle.com/en-us/iaas/api/#/en/iaas/20160918/InstanceConfiguration/ - if err := r.reconcileLaunchTemplate(ctx, machinePoolScope); err != nil { + if err := r.reconcileInstanceConfiguration(ctx, machinePoolScope); err != nil { r.Recorder.Eventf(machinePoolScope.OCIMachinePool, corev1.EventTypeWarning, "FailedLaunchTemplateReconcile", "Failed to reconcile launch template: %v", err) machinePoolScope.Error(err, "failed to reconcile launch template") return ctrl.Result{}, err } - logger.Info("---- after reconcileLaunchTemplate", "id", machinePoolScope.OCIMachinePool.Status.InstanceConfigurationId) - // set the LaunchTemplateReady condition conditions.MarkTrue(machinePoolScope.OCIMachinePool, infrav1exp.LaunchTemplateReadyCondition) @@ -293,7 +288,6 @@ func (r *OCIMachinePoolReconciler) reconcileNormal(ctx context.Context, logger l } if instancePool == nil { - // Create new ASG if _, err := r.createInstancePool(ctx, machinePoolScope); err != nil { conditions.MarkFalse(machinePoolScope.OCIMachinePool, infrav1exp.InstancePoolReadyCondition, infrav1exp.InstancePoolProvisionFailedReason, clusterv1.ConditionSeverityError, err.Error()) return ctrl.Result{}, err @@ -309,7 +303,6 @@ func (r *OCIMachinePoolReconciler) reconcileNormal(ctx context.Context, logger l machinePoolScope.Info("OCI Compute Instance Pool found", "InstancePoolID", *instancePool.Id) machinePoolScope.OCIMachinePool.Spec.ProviderID = common.String(fmt.Sprintf("oci://%s", *instancePool.Id)) - // TODO: handle update? or only when running? switch instancePool.LifecycleState { case core.InstancePoolLifecycleStateProvisioning, core.InstancePoolLifecycleStateStarting: machinePoolScope.Info("Instance Pool is pending") @@ -380,12 +373,9 @@ func (r *OCIMachinePoolReconciler) reconcileDelete(ctx context.Context, machineP req := core.DeleteInstanceConfigurationRequest{InstanceConfigurationId: common.String(instanceConfigurationId)} if _, err := machinePoolScope.ComputeManagementClient.DeleteInstanceConfiguration(ctx, req); err != nil { r.Recorder.Eventf(machinePoolScope.OCIMachinePool, corev1.EventTypeWarning, "FailedDelete", "Failed to delete instance configuration %q: %v", instanceConfigurationId, err) - return ctrl.Result{}, errors.Wrap(err, "failed to delete ASG") + return ctrl.Result{}, errors.Wrap(err, "failed to delete instance pool") } - // TODO is this the right spot or should I move this to when InstancePoolLifecycleStateTerminated - // todo maybe need to check that all pool instances are deleted first - machinePoolScope.Info("successfully deleted instance pool and Launch Template") // remove finalizer @@ -394,11 +384,8 @@ func (r *OCIMachinePoolReconciler) reconcileDelete(ctx context.Context, machineP return ctrl.Result{}, nil } -func (r *OCIMachinePoolReconciler) reconcileLaunchTemplate(ctx context.Context, machinePoolScope *scope.MachinePoolScope) error { +func (r *OCIMachinePoolReconciler) reconcileInstanceConfiguration(ctx context.Context, machinePoolScope *scope.MachinePoolScope) error { var instanceConfiguration *core.InstanceConfiguration - machinePoolScope.Info("---- machinePoolScope.OCIMachinePool.Status.InstanceConfigurationId", "id", machinePoolScope.OCIMachinePool.Status.InstanceConfigurationId) - // If the IC exists try a get - //get by name or tag I think instanceConfigurationId := machinePoolScope.GetInstanceConfigurationId() if len(instanceConfigurationId) > 0 { @@ -408,28 +395,29 @@ func (r *OCIMachinePoolReconciler) reconcileLaunchTemplate(ctx context.Context, machinePoolScope.Info("instance configuration found", "InstanceConfigurationId", instanceConfiguration.Id) machinePoolScope.SetInstanceConfigurationIdStatus(instanceConfigurationId) return machinePoolScope.PatchObject(ctx) + } else { + return errors.Wrap(err, fmt.Sprintf("error getting instance configuration by id %s", instanceConfigurationId)) } - // TODO: handle get by ID 404 } - //else try to create - tags := machinePoolScope.GetFreeFormTags(*machinePoolScope.OCICluster) + //TODO do lots of checks on all the request data below - cloudInitData, err := machinePoolScope.GetBootstrapData() - if err != nil { - return err - } + if instanceConfiguration == nil { + machinePoolScope.Info("Create new instance configuration") - metadata := machinePoolScope.OCIMachinePool.Spec.Metadata - if metadata == nil { - metadata = make(map[string]string) - } - metadata["user_data"] = base64.StdEncoding.EncodeToString([]byte(cloudInitData)) + tags := machinePoolScope.GetFreeFormTags(*machinePoolScope.OCICluster) - //TODO do lots of checks on all the request data below + cloudInitData, err := machinePoolScope.GetBootstrapData() + if err != nil { + return err + } + + metadata := machinePoolScope.OCIMachinePool.Spec.Metadata + if metadata == nil { + metadata = make(map[string]string) + } + metadata["user_data"] = base64.StdEncoding.EncodeToString([]byte(cloudInitData)) - // if get fails maybe try to create - if instanceConfiguration == nil { subnetId := machinePoolScope.GetWorkerMachineSubnet() nsgId := machinePoolScope.GetWorkerMachineNSG() @@ -450,7 +438,7 @@ func (r *OCIMachinePoolReconciler) reconcileLaunchTemplate(ctx context.Context, }, } - shapeConfig, err := machinePoolScope.BuildInstanceConfirgurationShapeConfig() + shapeConfig, err := machinePoolScope.BuildInstanceConfigurationShapeConfig() if err != nil { conditions.MarkFalse(machinePoolScope.MachinePool, infrav1exp.LaunchTemplateReadyCondition, infrav1exp.LaunchTemplateCreateFailedReason, clusterv1.ConditionSeverityError, err.Error()) machinePoolScope.Info("failed to create instance configuration due to shape config") @@ -476,12 +464,7 @@ func (r *OCIMachinePoolReconciler) reconcileLaunchTemplate(ctx context.Context, return err } - //TODO: handle update - - fmt.Println(resp) - fmt.Println("----- id: ", *resp.Id) machinePoolScope.SetInstanceConfigurationIdStatus(*resp.Id) - machinePoolScope.Info("--- gonna patch") return machinePoolScope.PatchObject(ctx) } @@ -489,62 +472,63 @@ func (r *OCIMachinePoolReconciler) reconcileLaunchTemplate(ctx context.Context, } func (r *OCIMachinePoolReconciler) findInstancePool(ctx context.Context, machinePoolScope *scope.MachinePoolScope) (*core.InstancePool, error) { - // TODO: fix this I don't love having to list then get. There has to be a better way - //poolName := fmt.Sprintf("%s-%s", machinePoolScope.OCICluster.Name, machinePoolScope.MachinePool.Name) + // We have to first list the pools to get the instance pool. + // List returns InstancePoolSummary which lacks some details of InstancePool - // Query the instance using tags. - req := core.ListInstancePoolsRequest{ + reqList := core.ListInstancePoolsRequest{ CompartmentId: common.String(machinePoolScope.OCICluster.Spec.CompartmentId), DisplayName: common.String(machinePoolScope.OCIMachinePool.GetName()), } - resp, err := machinePoolScope.ComputeManagementClient.ListInstancePools(ctx, req) + respList, err := machinePoolScope.ComputeManagementClient.ListInstancePools(ctx, reqList) if err != nil { return nil, errors.Wrapf(err, "failed to query OCIMachinePool by name") } - if len(resp.Items) <= 0 { + if len(respList.Items) <= 0 { machinePoolScope.Info("No machine pool found", "machinepool-name", machinePoolScope.OCIMachinePool.GetName()) return nil, nil } - instancePool := resp.Items[0] - for _, i := range resp.Items { + var instancePoolSummary *core.InstancePoolSummary + for _, i := range respList.Items { if machinePoolScope.IsResourceCreatedByClusterAPI(i.FreeformTags) { - instancePool = i + instancePoolSummary = &i + break } } + if instancePoolSummary == nil { + machinePoolScope.Info("No machine pool found created by this cluster", "machinepool-name", machinePoolScope.OCIMachinePool.GetName()) + return nil, nil + } reqGet := core.GetInstancePoolRequest{ - InstancePoolId: instancePool.Id, + InstancePoolId: instancePoolSummary.Id, } respGet, err := machinePoolScope.ComputeManagementClient.GetInstancePool(ctx, reqGet) if err != nil { - return nil, errors.Wrapf(err, "failed to query OCIMachinePool by name") + return nil, errors.Wrapf(err, "failed to query OCIMachinePool with id %s", *instancePoolSummary.Id) } if !machinePoolScope.IsResourceCreatedByClusterAPI(respGet.InstancePool.FreeformTags) { - return nil, errors.Wrapf(err, "failed to query OCIMachinePool by name") + return nil, errors.Wrapf(err, "failed to query OCIMachinePool not created by this cluster.") } + machinePoolScope.Info("Found existing instance pool", "id", instancePoolSummary.Id, "machinepool-name", machinePoolScope.OCIMachinePool.GetName()) + return &respGet.InstancePool, nil } func (r *OCIMachinePoolReconciler) createInstancePool(ctx context.Context, machinePoolScope *scope.MachinePoolScope) (*core.InstancePool, error) { - //poolName := fmt.Sprintf("%s-%s", machinePoolScope.OCICluster.Name, machinePoolScope.MachinePool.Name) if machinePoolScope.OCIMachinePool.Status.InstanceConfigurationId == "" { return nil, errors.New("OCIMachinePool has no InstanceConfigurationId for some reason") } - availabilityDomain := machinePoolScope.OCICluster.Status.FailureDomains["1"].Attributes["AvailabilityDomain"] tags := machinePoolScope.GetFreeFormTags(*machinePoolScope.OCICluster) - // TODO: we will want to spread this across all ADs by creating more CreateInstancePoolPlacementConfigurationDetails - // for all ADs in a given region - placement := []core.CreateInstancePoolPlacementConfigurationDetails{ - { - AvailabilityDomain: common.String(availabilityDomain), - PrimarySubnetId: machinePoolScope.GetWorkerMachineSubnet(), - }, + // build placements + placements, err := machinePoolScope.BuildInstancePoolPlacement() + if err != nil { + return nil, errors.Wrapf(err, "unable to build instance pool placements") } replicas := int(1) @@ -560,7 +544,7 @@ func (r *OCIMachinePoolReconciler) createInstancePool(ctx context.Context, machi Size: common.Int(replicas), DisplayName: common.String(machinePoolScope.OCIMachinePool.GetName()), - PlacementConfigurations: placement, + PlacementConfigurations: placements, FreeformTags: tags, }, } @@ -574,51 +558,6 @@ func (r *OCIMachinePoolReconciler) createInstancePool(ctx context.Context, machi return &instancePool.InstancePool, nil } -func (r *OCIMachinePoolReconciler) OCIClusterToOCIMachinePools(ctx context.Context) handler.MapFunc { - log := ctrl.LoggerFrom(ctx) - fmt.Println("---- OCIClusterToOCIMachinePools outter func") - return func(o client.Object) []ctrl.Request { - result := []ctrl.Request{} - - fmt.Println("---- OCIClusterToOCIMachinePools inner func") - - c, ok := o.(*infrastructurev1beta1.OCICluster) - if !ok { - log.Error(errors.Errorf("expected a OCICluster but got a %T", o), "failed to get OCIMachinePool for OCICluster") - return nil - } - - cluster, err := util.GetOwnerCluster(ctx, r.Client, c.ObjectMeta) - switch { - case apierrors.IsNotFound(err) || cluster == nil: - return result - case err != nil: - log.Error(err, "failed to get owning cluster") - return result - } - - labels := map[string]string{clusterv1.ClusterLabelName: cluster.Name} - machinePoolList := &expclusterv1.MachinePoolList{} - if err := r.List(ctx, machinePoolList, client.InNamespace(c.Namespace), client.MatchingLabels(labels)); err != nil { - log.Error(err, "failed to list MachinePools") - return nil - } - - fmt.Println("---- pool list size ", len(machinePoolList.Items)) - //Maybe use machinePoolToInfrastructureMapFunc? - for _, m := range machinePoolList.Items { - if m.Spec.Template.Spec.InfrastructureRef.Name == "" { - continue - } - fmt.Println("---- Infra ref name ", m.Spec.Template.Spec.InfrastructureRef.Name) - name := client.ObjectKey{Namespace: m.Namespace, Name: m.Spec.Template.Spec.InfrastructureRef.Name} - result = append(result, ctrl.Request{NamespacedName: name}) - } - - return result - } -} - func (r *OCIMachinePoolReconciler) updatePool(ctx context.Context, machinePoolScope *scope.MachinePoolScope, instancePool *core.InstancePool) error { if instancePoolNeedsUpdates(machinePoolScope, instancePool) { diff --git a/feature/feature.go b/feature/feature.go index 585873393..f296625f4 100644 --- a/feature/feature.go +++ b/feature/feature.go @@ -1,3 +1,19 @@ +/* +Copyright (c) 2022 Oracle and/or its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package feature import ( @@ -7,17 +23,16 @@ import ( const ( // MachinePool is used to enable instance pool support - // alpha: v0.1 MachinePool featuregate.Feature = "MachinePool" ) func init() { - runtime.Must(MutableGates.Add(defaultCAPAFeatureGates)) + runtime.Must(MutableGates.Add(defaultCAPOCIFeatureGates)) } -// defaultCAPAFeatureGates consists of all known capa-specific feature keys. +// defaultCAPOCIFeatureGates consists of all known capa-specific feature keys. // To add a new feature, define a key for it above and add it here. -var defaultCAPAFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ +var defaultCAPOCIFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ // Every feature should be initiated here: MachinePool: {Default: false, PreRelease: featuregate.Alpha}, } diff --git a/feature/gates.go b/feature/gates.go index 45fa70002..831f09119 100644 --- a/feature/gates.go +++ b/feature/gates.go @@ -1,3 +1,19 @@ +/* +Copyright (c) 2022 Oracle and/or its affiliates. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package feature import ( diff --git a/main.go b/main.go index d50b10ca4..0e018d2dc 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,8 @@ package main import ( "flag" + "os" + infrastructurev1beta1 "github.com/oracle/cluster-api-provider-oci/api/v1beta1" "github.com/oracle/cluster-api-provider-oci/controllers" "github.com/oracle/cluster-api-provider-oci/feature" @@ -25,7 +27,6 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth" - "os" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" @@ -187,11 +188,11 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "OCICluster") os.Exit(1) } - // - //if err = (&infrastructurev1beta1.OCIMachineTemplate{}).SetupWebhookWithManager(mgr); err != nil { - // setupLog.Error(err, "unable to create webhook", "webhook", "OCIMachineTemplate") - // os.Exit(1) - //} + + if err = (&infrastructurev1beta1.OCIMachineTemplate{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "OCIMachineTemplate") + os.Exit(1) + } //+kubebuilder:scaffold:builder diff --git a/templates/cluster-template-machinepool.yaml b/templates/cluster-template-machinepool.yaml index a9f7bc6ab..d04a3c51a 100644 --- a/templates/cluster-template-machinepool.yaml +++ b/templates/cluster-template-machinepool.yaml @@ -32,8 +32,6 @@ metadata: cluster.x-k8s.io/cluster-name: "${CLUSTER_NAME}" name: "${CLUSTER_NAME}" spec: - # TODO fix had to do this for testing locally - ociResourceIdentifier: "1234-5678-9062" compartmentId: "${OCI_COMPARTMENT_ID}" networkSpec: vcn: @@ -141,17 +139,16 @@ metadata: namespace: default spec: imageId: "${OCI_IMAGE_ID}" - minSize: 1 - maxSize: 10 metadata: ssh_authorized_keys: "${OCI_SSH_KEY}" shapeConfig: ocpus: "${OCI_NODE_MACHINE_TYPE_OCPUS=1}" -# fix this so it isn't nested so deep instanceConfiguration: instanceDetails: shape: "${OCI_NODE_MACHINE_TYPE=VM.Standard.E4.Flex}" -# isPvEncryptionInTransitEnabled: ${OCI_NODE_PV_TRANSIT_ENCRYPTION=true} +# uncomment if you want to set a specific availability domain +# placementDetails: +# - availabilityDomain: 1 --- apiVersion: bootstrap.cluster.x-k8s.io/v1alpha4 kind: KubeadmConfig