Skip to content

Commit cbb0954

Browse files
authored
feat: add support for MachinePool (#89)
1 parent 713d002 commit cbb0954

29 files changed

+2159
-18
lines changed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ COPY main.go main.go
1515
COPY api/ api/
1616
COPY controllers/ controllers/
1717
COPY cloud/ cloud/
18+
COPY exp/ exp/
19+
COPY feature/ feature/
1820
COPY vendor/ vendor/
1921

2022
# Build

Makefile

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ IMG ?= controller:latest
5454
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
5555
CRD_OPTIONS ?= "crd"
5656

57+
# enable machine pool feature
58+
EXP_MACHINE_POOL ?= false
59+
5760
# Set build time variables including version details
5861
LDFLAGS := $(shell source ./hack/version.sh; version::ldflags)
5962

@@ -91,10 +94,14 @@ help: ## Display this help.
9194
##@ Development
9295

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

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

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

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

120127
## --------------------------------------
121128
## Linting

api/v1beta1/ocicluster_types.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ type OCIClusterStatus struct {
7171
// +optional
7272
FailureDomains clusterv1.FailureDomains `json:"failureDomains,omitempty"`
7373

74+
// AvailabilityDomains encapsulates the clusters Availability Domain (AD) information in a map
75+
// where the map key is the AD name and the struct is details about the AD.
76+
// +optional
77+
AvailabilityDomains map[string]OCIAvailabilityDomain `json:"availabilityDomains,omitempty"`
78+
7479
// +optional
7580
Ready bool `json:"ready"`
7681
// NetworkSpec encapsulates all things related to OCI network.
@@ -99,6 +104,16 @@ type OCIClusterList struct {
99104
Items []OCICluster `json:"items"`
100105
}
101106

107+
// OCIAvailabilityDomain contains information about an Availability Domain (AD).
108+
type OCIAvailabilityDomain struct {
109+
110+
// Name is the AD's full name. Example: Uocm:PHX-AD-1
111+
Name string `json:"name,omitempty"`
112+
113+
// FaultDomains a list of fault domain (FD) names. Example: ["FAULT-DOMAIN-1"]
114+
FaultDomains []string `json:"faultDomains,omitempty"`
115+
}
116+
102117
// GetConditions returns the list of conditions for an OCICluster API object.
103118
func (c *OCICluster) GetConditions() clusterv1.Conditions {
104119
return c.Status.Conditions

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloud/ociutil/ociutil.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,16 @@ func GetBaseLineOcpuOptimizationEnum(baseLineOcpuOptmimizationString string) (co
103103
return "", errors.New("invalid baseline cpu optimization parameter")
104104
}
105105

106+
// GetInstanceConfigBaseLineOcpuOptimizationEnum iterates over the valid baseline OCPUs to validate the passed in value
107+
func GetInstanceConfigBaseLineOcpuOptimizationEnum(baseLineOcpuOptmimizationString string) (core.InstanceConfigurationLaunchInstanceShapeConfigDetailsBaselineOcpuUtilizationEnum, error) {
108+
for _, e := range core.GetInstanceConfigurationLaunchInstanceShapeConfigDetailsBaselineOcpuUtilizationEnumValues() {
109+
if string(e) == baseLineOcpuOptmimizationString {
110+
return e, nil
111+
}
112+
}
113+
return "", errors.New("invalid baseline cpu optimization parameter")
114+
}
115+
106116
// GetDefaultClusterTags creates and returns a map of the default tags for all clusters
107117
func GetDefaultClusterTags() map[string]string {
108118
tags := make(map[string]string)

cloud/scope/clients.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/go-logr/logr"
2323
"github.com/oracle/cluster-api-provider-oci/cloud/services/compute"
24+
"github.com/oracle/cluster-api-provider-oci/cloud/services/computemanagement"
2425
identityClient "github.com/oracle/cluster-api-provider-oci/cloud/services/identity"
2526
nlb "github.com/oracle/cluster-api-provider-oci/cloud/services/networkloadbalancer"
2627
"github.com/oracle/cluster-api-provider-oci/cloud/services/vcn"
@@ -34,10 +35,11 @@ import (
3435

3536
// OCIClients is the struct of all the needed OCI clients
3637
type OCIClients struct {
37-
ComputeClient compute.ComputeClient
38-
VCNClient vcn.Client
39-
LoadBalancerClient nlb.NetworkLoadBalancerClient
40-
IdentityClient identityClient.Client
38+
ComputeClient compute.ComputeClient
39+
ComputeManagementClient computemanagement.Client
40+
VCNClient vcn.Client
41+
LoadBalancerClient nlb.NetworkLoadBalancerClient
42+
IdentityClient identityClient.Client
4143
}
4244

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

100103
if err != nil {
101104
return OCIClients{}, err
102105
}
103106

104107
return OCIClients{
105-
VCNClient: vcnClient,
106-
LoadBalancerClient: lbClient,
107-
IdentityClient: identityClient,
108-
ComputeClient: computeClient,
108+
VCNClient: vcnClient,
109+
LoadBalancerClient: lbClient,
110+
IdentityClient: identityClient,
111+
ComputeClient: computeClient,
112+
ComputeManagementClient: computeManagementClient,
109113
}, err
110114
}
111115

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

153157
return &computeClient, nil
154158
}
159+
160+
func createComputeManagementClient(region string, ociAuthConfigProvider common.ConfigurationProvider, logger *logr.Logger) (*core.ComputeManagementClient, error) {
161+
computeManagementClient, err := core.NewComputeManagementClientWithConfigurationProvider(ociAuthConfigProvider)
162+
if err != nil {
163+
logger.Error(err, "unable to create OCI Compute Management Client")
164+
return nil, err
165+
}
166+
computeManagementClient.SetRegion(region)
167+
168+
return &computeManagementClient, nil
169+
}

cloud/scope/cluster.go

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222
"reflect"
23+
"sigs.k8s.io/cluster-api/util/conditions"
2324
"strconv"
2425

2526
"github.com/oracle/cluster-api-provider-oci/cloud/services/vcn"
@@ -108,6 +109,7 @@ func NewClusterScope(params ClusterScopeParams) (*ClusterScope, error) {
108109

109110
// PatchObject persists the cluster configuration and status.
110111
func (s *ClusterScope) PatchObject(ctx context.Context) error {
112+
conditions.SetSummary(s.OCICluster)
111113
return s.patchHelper.Patch(ctx, s.OCICluster)
112114
}
113115

@@ -137,23 +139,29 @@ func (s *ClusterScope) IsResourceCreatedByClusterAPI(resourceFreeFormTags map[st
137139
// in case of single AD regions, the failure domain will be fault domain, in case of multi Ad regions, it will
138140
// be AD
139141
func (s *ClusterScope) setFailureDomains(ctx context.Context) error {
140-
req := identity.ListAvailabilityDomainsRequest{CompartmentId: common.String(s.GetCompartmentId())}
142+
reqAd := identity.ListAvailabilityDomainsRequest{CompartmentId: common.String(s.GetCompartmentId())}
141143

142-
resp, err := s.IdentityClient.ListAvailabilityDomains(ctx, req)
144+
respAd, err := s.IdentityClient.ListAvailabilityDomains(ctx, reqAd)
143145
if err != nil {
144146
s.Logger.Error(err, "failed to list identity domains")
145147
return err
146148
}
147149

148-
numOfAds := len(resp.Items)
150+
// build the AD list for cluster
151+
err = s.setAvailabiltyDomainStatus(ctx, respAd.Items)
152+
if err != nil {
153+
return err
154+
}
155+
156+
numOfAds := len(respAd.Items)
149157
if numOfAds != 1 && numOfAds != 3 {
150158
err := errors.New(fmt.Sprintf("invalid number of Availability Domains, should be either 1 or 3, but got %d", numOfAds))
151159
s.Logger.Error(err, "invalid number of Availability Domains")
152160
return err
153161
}
154162

155163
if numOfAds == 3 {
156-
for i, ad := range resp.Items {
164+
for i, ad := range respAd.Items {
157165
s.SetFailureDomain(strconv.Itoa(i+1), clusterv1.FailureDomainSpec{
158166
ControlPlane: true,
159167
Attributes: map[string]string{AvailabilityDomain: *ad.Name},
@@ -162,7 +170,7 @@ func (s *ClusterScope) setFailureDomains(ctx context.Context) error {
162170
} else {
163171
req := identity.ListFaultDomainsRequest{
164172
CompartmentId: common.String(s.GetCompartmentId()),
165-
AvailabilityDomain: resp.Items[0].Name,
173+
AvailabilityDomain: respAd.Items[0].Name,
166174
}
167175
resp, err := s.IdentityClient.ListFaultDomains(ctx, req)
168176
if err != nil {
@@ -191,6 +199,38 @@ func (s *ClusterScope) SetFailureDomain(id string, spec clusterv1.FailureDomainS
191199
s.OCICluster.Status.FailureDomains[id] = spec
192200
}
193201

202+
// setAvailabiltyDomainStatus builds the OCIAvailabilityDomain list and sets the OCICluster's status with this list
203+
// so that other parts of the provider have access to ADs and FDs without having to make multiple calls to identity.
204+
func (s *ClusterScope) setAvailabiltyDomainStatus(ctx context.Context, ads []identity.AvailabilityDomain) error {
205+
clusterAds := make(map[string]infrastructurev1beta1.OCIAvailabilityDomain)
206+
for _, ad := range ads {
207+
reqFd := identity.ListFaultDomainsRequest{
208+
CompartmentId: common.String(s.GetCompartmentId()),
209+
AvailabilityDomain: ad.Name,
210+
}
211+
respFd, err := s.IdentityClient.ListFaultDomains(ctx, reqFd)
212+
if err != nil {
213+
s.Logger.Error(err, "failed to list fault domains")
214+
return err
215+
}
216+
217+
var faultDomains []string
218+
for _, fd := range respFd.Items {
219+
faultDomains = append(faultDomains, *fd.Name)
220+
}
221+
222+
adName := *ad.Name
223+
clusterAds[adName] = infrastructurev1beta1.OCIAvailabilityDomain{
224+
Name: adName,
225+
FaultDomains: faultDomains,
226+
}
227+
}
228+
229+
s.OCICluster.Status.AvailabilityDomains = clusterAds
230+
231+
return nil
232+
}
233+
194234
func (s *ClusterScope) IsTagsEqual(freeFromTags map[string]string, definedTags map[string]map[string]interface{}) bool {
195235
if reflect.DeepEqual(freeFromTags, s.GetFreeFormTags()) && reflect.DeepEqual(definedTags, s.GetDefinedTags()) {
196236
return true

0 commit comments

Comments
 (0)