Skip to content
This repository has been archived by the owner on Apr 11, 2024. It is now read-only.

Commit

Permalink
feat: Add support for CAPX (#6)
Browse files Browse the repository at this point in the history
* fix: added support for capx

* refactor: reuse existing CAPX types

* fix: set allowed enums for Nutanix resource types

* fix: set required for Nutanix node type

* fix: reuse resource.Quantity types

* fix: set defaults and validation

* fix: rename field to subnets

* refactor: fix handlers after API changes

* test: add new unit tests

* refactor: bring back host instead of address

* fix: examples with updated APIs

* fix: using latest capx private brach to test kube-vip fix

* fix: set namespace for credentialRef

The patch failed with the following error:
got failure response with message failed to apply JSON patches to input:
replace operation does not apply:
doc is missing key:
/spec/template/spec/prismCentral/credentialRef/namespace: missing value.

* docs: fix users example

* docs: deploying Calico for Nutanix

* fix: added basic docs for nutanix mutations

* fix: lint related fixes

* docs: minor changes

---------

Co-authored-by: Dimitri Koshkin <dimitri.koshkin@nutanix.com>
  • Loading branch information
2 people authored and jimmidyson committed Apr 11, 2024
1 parent e3262d7 commit 2fe9631
Show file tree
Hide file tree
Showing 51 changed files with 3,290 additions and 40 deletions.
12 changes: 12 additions & 0 deletions api/v1alpha1/clusterconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type ClusterConfigSpec struct {
AWS *AWSSpec `json:"aws,omitempty"`
// +optional
Docker *DockerSpec `json:"docker,omitempty"`
// +optional
Nutanix *NutanixSpec `json:"nutanix,omitempty"`

GenericClusterConfig `json:",inline"`

Expand Down Expand Up @@ -76,6 +78,16 @@ func (s ClusterConfigSpec) VariableSchema() clusterv1.VariableSchema { //nolint:
}.VariableSchema().OpenAPIV3Schema,
},
)
case s.Nutanix != nil:
maps.Copy(
clusterConfigProps.OpenAPIV3Schema.Properties,
map[string]clusterv1.JSONSchemaProps{
NutanixVariableName: NutanixSpec{}.VariableSchema().OpenAPIV3Schema,
"controlPlane": NodeConfigSpec{
Nutanix: &NutanixNodeSpec{},
}.VariableSchema().OpenAPIV3Schema,
},
)
}

return clusterConfigProps
Expand Down
37 changes: 37 additions & 0 deletions api/v1alpha1/common_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@

package v1alpha1

import (
"k8s.io/utils/ptr"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"

"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables"
)

const (
APIServerPort = 6443
)

// 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.
//
Expand All @@ -23,3 +34,29 @@ type ObjectMeta struct {
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
}

type ControlPlaneEndpointSpec clusterv1.APIEndpoint

func (ControlPlaneEndpointSpec) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Description: "Kubernetes control-plane endpoint configuration",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"host": {
Description: "host ip/fqdn for control plane API Server",
Type: "string",
MinLength: ptr.To[int64](1),
},
"port": {
Description: "port for control plane API Server",
Type: "integer",
Default: variables.MustMarshal(APIServerPort),
Minimum: ptr.To[int64](1),
Maximum: ptr.To[int64](65535),
},
},
Required: []string{"host", "port"},
},
}
}
2 changes: 2 additions & 0 deletions api/v1alpha1/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ const (
ClusterAutoscalerVariableName = "clusterAutoscaler"
// AWSVariableName is the AWS config patch variable name.
AWSVariableName = "aws"
// NutanixVariableName is the Nutanix config patch variable name.
NutanixVariableName = "nutanix"
)
9 changes: 9 additions & 0 deletions api/v1alpha1/node_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type NodeConfigSpec struct {
AWS *AWSNodeSpec `json:"aws,omitempty"`
// +optional
Docker *DockerNodeSpec `json:"docker,omitempty"`
// +optional
Nutanix *NutanixNodeSpec `json:"nutanix,omitempty"`
}

func (s NodeConfigSpec) VariableSchema() clusterv1.VariableSchema {
Expand All @@ -49,6 +51,13 @@ func (s NodeConfigSpec) VariableSchema() clusterv1.VariableSchema {
"docker": DockerNodeSpec{}.VariableSchema().OpenAPIV3Schema,
},
)
case s.Nutanix != nil:
maps.Copy(
nodeConfigProps.OpenAPIV3Schema.Properties,
map[string]clusterv1.JSONSchemaProps{
"nutanix": NutanixNodeSpec{}.VariableSchema().OpenAPIV3Schema,
},
)
}

return nodeConfigProps
Expand Down
115 changes: 115 additions & 0 deletions api/v1alpha1/nutanix_clusterconfig_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2024 D2iQ, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package v1alpha1

import (
corev1 "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"

"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables"
)

const (
PrismCentralPort = 9440
)

// NutanixSpec defines the desired state of NutanixCluster.
type NutanixSpec struct {
// ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
// host can be either DNS name or ip address
ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"`

// Nutanix Prism Central endpoint configuration.
PrismCentralEndpoint NutanixPrismCentralEndpointSpec `json:"prismCentralEndpoint"`
}

func (NutanixSpec) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Description: "Nutanix cluster configuration",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"controlPlaneEndpoint": ControlPlaneEndpointSpec{}.VariableSchema().OpenAPIV3Schema,
"prismCentralEndpoint": NutanixPrismCentralEndpointSpec{}.VariableSchema().OpenAPIV3Schema,
},
},
}
}

type NutanixPrismCentralEndpointSpec struct {
// host is the DNS name or IP address of the Nutanix Prism Central
Host string `json:"host"`

// port is the port number to access the Nutanix Prism Central
Port int32 `json:"port"`

// use insecure connection to Prism Central endpoint
// +optional
Insecure bool `json:"insecure"`

// A reference to the ConfigMap containing a PEM encoded x509 cert for the RootCA that was used to create
// the certificate for a Prism Central that uses certificates that were issued by a non-publicly trusted RootCA.
// The trust bundle is added to the cert pool used to authenticate the TLS connection to the Prism Central.
// +optional
AdditionalTrustBundle *corev1.LocalObjectReference `json:"additionalTrustBundle,omitempty"`

// A reference to the Secret for credential information for the target Prism Central instance
Credentials corev1.LocalObjectReference `json:"credentials"`
}

func (NutanixPrismCentralEndpointSpec) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Description: "Nutanix Prism Central endpoint configuration",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"host": {
Description: "the DNS name or IP address of the Nutanix Prism Central",
Type: "string",
MinLength: ptr.To[int64](1),
},
"port": {
Description: "The port number to access the Nutanix Prism Central",
Type: "integer",
Default: variables.MustMarshal(PrismCentralPort),
Minimum: ptr.To[int64](1),
Maximum: ptr.To[int64](65535),
},
"insecure": {
Description: "Use insecure connection to Prism Central endpoint",
Type: "boolean",
},
"additionalTrustBundle": {
Description: "A reference to the ConfigMap containing a PEM encoded x509 cert for the RootCA " +
"that was used to create the certificate for a Prism Central that uses certificates " +
"that were issued by a non-publicly trusted RootCA." +
"The trust bundle is added to the cert pool used to authenticate the TLS connection " +
"to the Prism Central.",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"name": {
Description: "The name of the ConfigMap",
Type: "string",
},
},
Required: []string{"name"},
},
"credentials": {
Description: "A reference to the Secret for credential information" +
"for the target Prism Central instance",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"name": {
Description: "The name of the Secret",
Type: "string",
},
},
Required: []string{"name"},
},
},
Required: []string{"host", "port", "credentials"},
},
}
}
163 changes: 163 additions & 0 deletions api/v1alpha1/nutanix_node_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// Copyright 2024 D2iQ, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package v1alpha1

import (
"k8s.io/apimachinery/pkg/api/resource"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"

capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1"
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables"
)

type NutanixNodeSpec struct {
MachineDetails NutanixMachineDetails `json:"machineDetails"`
}

func (NutanixNodeSpec) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Description: "Nutanix Node configuration",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"machineDetails": NutanixMachineDetails{}.VariableSchema().OpenAPIV3Schema,
},
Required: []string{"machineDetails"},
},
}
}

type NutanixMachineDetails struct {
// vcpusPerSocket is the number of vCPUs per socket of the VM
VCPUsPerSocket int32 `json:"vcpusPerSocket"`

// vcpuSockets is the number of vCPU sockets of the VM
VCPUSockets int32 `json:"vcpuSockets"`

// memorySize is the memory size (in Quantity format) of the VM
MemorySize resource.Quantity `json:"memorySize"`

// image is to identify the rhcos image uploaded to the Prism Central (PC)
// The image identifier (uuid or name) can be obtained from the Prism Central console
// or using the prism_central API.
Image NutanixResourceIdentifier `json:"image"`

// cluster is to identify the cluster (the Prism Element under management
// of the Prism Central), in which the Machine's VM will be created.
// The cluster identifier (uuid or name) can be obtained from the Prism Central console
// or using the prism_central API.
Cluster NutanixResourceIdentifier `json:"cluster"`

// subnet is to identify the cluster's network subnet to use for the Machine's VM
// The cluster identifier (uuid or name) can be obtained from the Prism Central console
// or using the prism_central API.
Subnets NutanixResourceIdentifiers `json:"subnets"`

// Defines the boot type of the virtual machine. Only supports UEFI and Legacy
BootType NutanixBootType `json:"bootType,omitempty"`

// systemDiskSize is size (in Quantity format) of the system disk of the VM
// The minimum systemDiskSize is 20Gi bytes
SystemDiskSize resource.Quantity `json:"systemDiskSize"`
}

func (NutanixMachineDetails) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Description: "Nutanix Machine configuration",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"vcpusPerSocket": {
Description: "vcpusPerSocket is the number of vCPUs per socket of the VM",
Type: "integer",
},
"vcpuSockets": {
Description: "vcpuSockets is the number of vCPU sockets of the VM",
Type: "integer",
},
"memorySize": {
Description: "memorySize is the memory size (in Quantity format) of the VM eg. 4Gi",
Type: "string",
},
"image": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema,
"cluster": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema,
"subnets": NutanixResourceIdentifiers{}.VariableSchema().OpenAPIV3Schema,
"bootType": NutanixBootType(capxv1.NutanixBootTypeLegacy).VariableSchema().OpenAPIV3Schema,
"systemDiskSize": {
Description: "systemDiskSize is size (in Quantity format) of the system disk of the VM eg. 20Gi",
Type: "string",
},
},
Required: []string{"vcpusPerSocket", "vcpuSockets", "memorySize", "image", "cluster", "subnets", "systemDiskSize"},
},
}
}

// NutanixIdentifierType is an enumeration of different resource identifier types.
type NutanixIdentifierType capxv1.NutanixIdentifierType

func (NutanixIdentifierType) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Type: "string",
Description: "NutanixIdentifierType is an enumeration of different resource identifier types",
Enum: variables.MustMarshalValuesToEnumJSON(
capxv1.NutanixIdentifierUUID,
capxv1.NutanixIdentifierName,
),
},
}
}

// NutanixBootType is an enumeration of different boot types.
type NutanixBootType capxv1.NutanixBootType

func (NutanixBootType) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Type: "string",
Description: "NutanixBootType is an enumeration of different boot types.",
Enum: variables.MustMarshalValuesToEnumJSON(
capxv1.NutanixBootTypeLegacy,
capxv1.NutanixBootTypeUEFI,
),
},
}
}

type NutanixResourceIdentifier capxv1.NutanixResourceIdentifier

func (NutanixResourceIdentifier) VariableSchema() clusterv1.VariableSchema {
return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Description: "Nutanix Resource Identifier",
Type: "object",
Properties: map[string]clusterv1.JSONSchemaProps{
"type": NutanixIdentifierType(capxv1.NutanixIdentifierName).VariableSchema().OpenAPIV3Schema,
"uuid": {
Type: "string",
Description: "uuid is the UUID of the resource in the PC.",
},
"name": {
Type: "string",
Description: "name is the resource name in the PC.",
},
},
},
}
}

type NutanixResourceIdentifiers []NutanixResourceIdentifier

func (NutanixResourceIdentifiers) VariableSchema() clusterv1.VariableSchema {
resourceSchema := NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema

return clusterv1.VariableSchema{
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
Description: "Nutanix resource identifier",
Type: "array",
Items: &resourceSchema,
},
}
}
Loading

0 comments on commit 2fe9631

Please sign in to comment.