Skip to content

Commit

Permalink
feat: add support for MachinePool
Browse files Browse the repository at this point in the history
  • Loading branch information
joekr committed May 19, 2022
1 parent 637e94e commit e6b1de3
Show file tree
Hide file tree
Showing 29 changed files with 2,159 additions and 25 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ COPY main.go main.go
COPY api/ api/
COPY controllers/ controllers/
COPY cloud/ cloud/
COPY exp/ exp/
COPY feature/ feature/
COPY vendor/ vendor/

# Build
Expand Down
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ IMG ?= controller:latest
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd"

# enable machine pool feature
EXP_MACHINE_POOL ?= false

# Set build time variables including version details
LDFLAGS := $(shell source ./hack/version.sh; version::ldflags)

Expand Down Expand Up @@ -91,10 +94,14 @@ help: ## Display this help.
##@ Development

manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./api/..." output:crd:artifacts:config=config/crd/bases
$(CONTROLLER_GEN) $(CRD_OPTIONS) \
rbac:roleName=manager-role webhook \
paths="./api/..." \
paths="./exp/api/..." \
output:crd:artifacts:config=config/crd/bases

generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./api/..."
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./api/..." paths="./exp/api/..."

fmt: ## Run go fmt against code.
go fmt ./...
Expand All @@ -115,7 +122,7 @@ build: generate fmt vet ## Build manager binary.
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "${LDFLAGS} -extldflags '-static'" -o bin/manager .

run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go
go run ./main.go --feature-gates=MachinePool=${EXP_MACHINE_POOL}

## --------------------------------------
## Linting
Expand Down
15 changes: 15 additions & 0 deletions api/v1beta1/ocicluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions cloud/ociutil/ociutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ func GetBaseLineOcpuOptimizationEnum(baseLineOcpuOptmimizationString string) (co
return "", errors.New("invalid baseline cpu optimization parameter")
}

// GetInstanceConfigBaseLineOcpuOptimizationEnum iterates over the valid baseline OCPUs to validate the passed in value
func GetInstanceConfigBaseLineOcpuOptimizationEnum(baseLineOcpuOptmimizationString string) (core.InstanceConfigurationLaunchInstanceShapeConfigDetailsBaselineOcpuUtilizationEnum, error) {
for _, e := range core.GetInstanceConfigurationLaunchInstanceShapeConfigDetailsBaselineOcpuUtilizationEnumValues() {
if string(e) == baseLineOcpuOptmimizationString {
return e, nil
}
}
return "", errors.New("invalid baseline cpu optimization parameter")
}

// GetDefaultClusterTags creates and returns a map of the default tags for all clusters
func GetDefaultClusterTags() map[string]string {
tags := make(map[string]string)
Expand Down
31 changes: 23 additions & 8 deletions cloud/scope/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/go-logr/logr"
"github.com/oracle/cluster-api-provider-oci/cloud/services/compute"
"github.com/oracle/cluster-api-provider-oci/cloud/services/computemanagement"
identityClient "github.com/oracle/cluster-api-provider-oci/cloud/services/identity"
nlb "github.com/oracle/cluster-api-provider-oci/cloud/services/networkloadbalancer"
"github.com/oracle/cluster-api-provider-oci/cloud/services/vcn"
Expand All @@ -34,10 +35,11 @@ import (

// OCIClients is the struct of all the needed OCI clients
type OCIClients struct {
ComputeClient compute.ComputeClient
VCNClient vcn.Client
LoadBalancerClient nlb.NetworkLoadBalancerClient
IdentityClient identityClient.Client
ComputeClient compute.ComputeClient
ComputeManagementClient computemanagement.Client
VCNClient vcn.Client
LoadBalancerClient nlb.NetworkLoadBalancerClient
IdentityClient identityClient.Client
}

// ClientProvider defines the regional clients
Expand Down Expand Up @@ -96,16 +98,18 @@ func createClients(region string, oCIAuthConfigProvider common.ConfigurationProv
lbClient, err := createLbClient(region, oCIAuthConfigProvider, logger)
identityClient, err := createIdentityClient(region, oCIAuthConfigProvider, logger)
computeClient, err := createComputeClient(region, oCIAuthConfigProvider, logger)
computeManagementClient, err := createComputeManagementClient(region, oCIAuthConfigProvider, logger)

if err != nil {
return OCIClients{}, err
}

return OCIClients{
VCNClient: vcnClient,
LoadBalancerClient: lbClient,
IdentityClient: identityClient,
ComputeClient: computeClient,
VCNClient: vcnClient,
LoadBalancerClient: lbClient,
IdentityClient: identityClient,
ComputeClient: computeClient,
ComputeManagementClient: computeManagementClient,
}, err
}

Expand Down Expand Up @@ -152,3 +156,14 @@ func createComputeClient(region string, ociAuthConfigProvider common.Configurati

return &computeClient, nil
}

func createComputeManagementClient(region string, ociAuthConfigProvider common.ConfigurationProvider, logger *logr.Logger) (*core.ComputeManagementClient, error) {
computeManagementClient, err := core.NewComputeManagementClientWithConfigurationProvider(ociAuthConfigProvider)
if err != nil {
logger.Error(err, "unable to create OCI Compute Management Client")
return nil, err
}
computeManagementClient.SetRegion(region)

return &computeManagementClient, nil
}
50 changes: 45 additions & 5 deletions cloud/scope/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
}

Expand Down Expand Up @@ -137,23 +139,29 @@ 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")
return err
}

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},
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit e6b1de3

Please sign in to comment.