Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add experemental support for Machinepool #89

Merged
merged 1 commit into from
May 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
joekr marked this conversation as resolved.
Show resolved Hide resolved
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)
joekr marked this conversation as resolved.
Show resolved Hide resolved
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