-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial provider implementation (#2)
- Loading branch information
Showing
30 changed files
with
4,346 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# machine-api-provider-cloudscale | ||
|
||
Provider for cloudscale.ch for the OpenShift machine-api. | ||
|
||
## Development | ||
|
||
## Updating OCP dependencies | ||
|
||
```bash | ||
RELEASE=release-4.XX | ||
go get -u "github.com/openshift/api@${RELEASE}" | ||
go get -u "github.com/openshift/library-go@${RELEASE}" | ||
go get -u "github.com/openshift/machine-api-operator@${RELEASE}" | ||
go mod tidy | ||
|
||
# Update the CRDs required for testing on a local non-OCP cluster | ||
make sync-crds | ||
``` | ||
|
||
### Testing on a local non-OCP cluster | ||
|
||
```bash | ||
# Apply required upstream CRDs | ||
kubectl apply -k config/crds | ||
|
||
make run | ||
|
||
# Apply a generic machine object that will not join a cluster | ||
kubectl apply -f config/samples/machine-cloudscale-generic.yml | ||
``` | ||
|
||
### Testing on a Project Syn managed OCP cluster | ||
|
||
```bash | ||
# Switch to the openshift-machine-api namespace | ||
yq -i '.current-context as $cc | with((.contexts[] | select(.name == $cc) | .context); .namespace = "openshift-machine-api")' ${KUBECONFIG:-$HOME/.kube/config} | ||
# Become system:admin | ||
yq -i '.current-context as $cc | (.contexts[] | select(.name == $cc) | .context.user) as $cu | with(.users[] | select(.name == $cu); .user.as = "system:admin")' ${KUBECONFIG:-$HOME/.kube/config} | ||
oc whoami | ||
|
||
# Deploy nodelink controller if required | ||
hack/deploy-nodelink-controller.sh | ||
|
||
# Generate the userData secret from the main.tf.json in the cluster catalog | ||
./pkg/machine/userdata/userdata-secret-from-maintfjson.sh manifests/openshift4-terraform/main.tf.json | k apply -f- | ||
|
||
make run | ||
|
||
# Apply a known working machine object | ||
# This will join the cluster and become a worker node | ||
# You want to update: | ||
# - metadata.labels["machine.openshift.io/cluster-api-cluster"] | ||
# - spec.providerSpec.value.zone | ||
# - spec.providerSpec.value.baseDomain | ||
# - spec.providerSpec.value.image | ||
# - spec.providerSpec.value.interfaces[0].networkUUID | ||
kubectl apply -f config/samples/machine-cloudscale-known-working.yml | ||
``` |
110 changes: 110 additions & 0 deletions
110
api/cloudscale/provider/v1beta1/cloudscaleprovider_types.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package v1beta1 | ||
|
||
import ( | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
type InterfaceType string | ||
|
||
const ( | ||
// InterfaceTypePublic is a public network interface. | ||
InterfaceTypePublic InterfaceType = "Public" | ||
// InterfaceTypePrivate is a private network interface. | ||
InterfaceTypePrivate InterfaceType = "Private" | ||
) | ||
|
||
// CloudscaleMachineProviderSpec is the type that will be embedded in a Machine.Spec.ProviderSpec field | ||
// for a cloudscale virtual machine. It is used by the cloudscale machine actuator to create a single Machine. | ||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object | ||
type CloudscaleMachineProviderSpec struct { | ||
metav1.TypeMeta `json:",inline"` | ||
|
||
// ObjectMeta is the standard object's metadata. | ||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata | ||
metav1.ObjectMeta `json:"metadata,omitempty"` | ||
|
||
// UserDataSecret is a reference to a secret that contains the UserData to apply to the instance. | ||
// The secret must contain a key named userData. The value is evaluated using Jsonnet; it can be either pure JSON or a Jsonnet template. | ||
// The Jsonnet template has access to the following variables: | ||
// - std.extVar('context').machine: the Machine object. The name can be accessed via std.extVar('context').machine.metadata.name for example. | ||
// - std.extVar('context').data: all keys from the UserDataSecret. For example, std.extVar('context').data.foo will access the value of the key foo. | ||
// +optional | ||
UserDataSecret *corev1.LocalObjectReference `json:"userDataSecret,omitempty"` | ||
// TokenSecret is a reference to the secret with the cloudscale API token. | ||
// The secret must contain a key named token. | ||
// If no token is provided, the operator will try to use the default token from CLOUDSCALE_API_TOKEN. | ||
// +optional | ||
TokenSecret *corev1.LocalObjectReference `json:"tokenSecret,omitempty"` | ||
|
||
// BaseDomain is the base domain to use for the machine. | ||
// +optional | ||
BaseDomain string `json:"baseDomain,omitempty"` | ||
// Zone is the zone in which the machine will be created. | ||
Zone string `json:"zone"` | ||
// AntiAffinityKey is a key to use for anti-affinity. If set, the machine will be placed in different cloudscale server groups based on this key. | ||
// The machines are automatically distributed across server groups with the same key. | ||
// +optional | ||
AntiAffinityKey string `json:"antiAffinityKey,omitempty"` | ||
// ServerGroups is a list of UUIDs identifying the server groups to which the new server will be added. | ||
// Used for anti-affinity. | ||
// https://www.cloudscale.ch/en/api/v1#server-groups | ||
ServerGroups []string `json:"serverGroups,omitempty"` | ||
// Tags is a map of tags to apply to the machine. | ||
Tags map[string]string `json:"tags"` | ||
// Flavor is the flavor of the machine. | ||
Flavor string `json:"flavor"` | ||
// Image is the base image to use for the machine. | ||
// For images provided by cloudscale: the image’s slug. | ||
// For custom images: the image’s slug prefixed with custom: (e.g. custom:ubuntu-foo), or its UUID. | ||
// If multiple custom images with the same slug exist, the newest custom image will be used. | ||
// https://www.cloudscale.ch/en/api/v1#images | ||
Image string `json:"image"` | ||
// RootVolumeSizeGB is the size of the root volume in GB. | ||
RootVolumeSizeGB int `json:"rootVolumeSizeGB"` | ||
// SSHKeys is a list of SSH keys to add to the machine. | ||
SSHKeys []string `json:"sshKeys"` | ||
// UseIPV6 is a flag to enable IPv6 on the machine. | ||
// Defaults to true. | ||
UseIPV6 *bool `json:"useIPV6,omitempty"` | ||
// Interfaces is a list of network interfaces to add to the machine. | ||
Interfaces []Interface `json:"interfaces"` | ||
} | ||
|
||
// Interface is a network interface to add to a machine. | ||
type Interface struct { | ||
// Type is the type of the interface. Required. | ||
Type InterfaceType `json:"type"` | ||
// NetworkUUID is the UUID of the network to attach the interface to. | ||
// Can only be set if type is private. | ||
// Must be compatible with Addresses.SubnetUUID if both are specified. | ||
NetworkUUID string `json:"networkUUID"` | ||
// Addresses is an optional list of addresses to assign to the interface. | ||
// Can only be set if type is private. | ||
Addresses []Address `json:"addresses"` | ||
} | ||
|
||
// Address is an address to assign to a network interface. | ||
type Address struct { | ||
// Address is an optional IP address to assign to the interface. | ||
Address string `json:"address"` | ||
// SubnetUUID is the UUID of the subnet to assign the address to. | ||
// Must be compatible with Interface.NetworkUUID if both are specified. | ||
SubnetUUID string `json:"subnetUUID"` | ||
} | ||
|
||
// CloudscaleMachineProviderStatus is the type that will be embedded in a Machine.Status.ProviderStatus field. | ||
// It contains cloudscale-specific status information. | ||
type CloudscaleMachineProviderStatus struct { | ||
metav1.TypeMeta `json:",inline"` | ||
|
||
// InstanceID is the ID of the instance in Cloudscale. | ||
// +optional | ||
InstanceID string `json:"instanceId,omitempty"` | ||
// Status is the status of the instance in Cloudscale. | ||
// Can be "changing", "running" or "stopped". | ||
Status string `json:"status,omitempty"` | ||
// Conditions is a set of conditions associated with the Machine to indicate | ||
// errors or other status | ||
Conditions []metav1.Condition `json:"conditions,omitempty"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package v1beta1 | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
|
||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/klog/v2" | ||
"sigs.k8s.io/yaml" | ||
) | ||
|
||
// RawExtensionFromProviderSpec marshals the machine provider spec. | ||
func RawExtensionFromProviderSpec(spec *CloudscaleMachineProviderSpec) (*runtime.RawExtension, error) { | ||
if spec == nil { | ||
return &runtime.RawExtension{}, nil | ||
} | ||
|
||
s := spec.DeepCopy() | ||
s.APIVersion = GroupVersion.String() | ||
|
||
var rawBytes []byte | ||
var err error | ||
if rawBytes, err = json.Marshal(s); err != nil { | ||
return nil, fmt.Errorf("error marshalling providerSpec: %v", err) | ||
} | ||
|
||
return &runtime.RawExtension{ | ||
Raw: rawBytes, | ||
}, nil | ||
} | ||
|
||
// RawExtensionFromProviderStatus marshals the provider status | ||
func RawExtensionFromProviderStatus(status *CloudscaleMachineProviderStatus) (*runtime.RawExtension, error) { | ||
if status == nil { | ||
return &runtime.RawExtension{}, nil | ||
} | ||
|
||
s := status.DeepCopy() | ||
s.APIVersion = GroupVersion.String() | ||
|
||
var rawBytes []byte | ||
var err error | ||
if rawBytes, err = json.Marshal(s); err != nil { | ||
return nil, fmt.Errorf("error marshalling providerStatus: %v", err) | ||
} | ||
|
||
return &runtime.RawExtension{ | ||
Raw: rawBytes, | ||
}, nil | ||
} | ||
|
||
// ProviderSpecFromRawExtension unmarshals the JSON-encoded spec | ||
func ProviderSpecFromRawExtension(rawExtension *runtime.RawExtension) (*CloudscaleMachineProviderSpec, error) { | ||
if rawExtension == nil { | ||
return &CloudscaleMachineProviderSpec{}, nil | ||
} | ||
|
||
spec := new(CloudscaleMachineProviderSpec) | ||
if err := yaml.Unmarshal(rawExtension.Raw, &spec); err != nil { | ||
return nil, fmt.Errorf("error unmarshalling providerSpec: %v", err) | ||
} | ||
|
||
klog.V(5).Infof("Got provider spec from raw extension: %+v", spec) | ||
return spec, nil | ||
} | ||
|
||
// ProviderStatusFromRawExtension unmarshals a raw extension into a GCPMachineProviderStatus type | ||
func ProviderStatusFromRawExtension(rawExtension *runtime.RawExtension) (*CloudscaleMachineProviderStatus, error) { | ||
if rawExtension == nil { | ||
return &CloudscaleMachineProviderStatus{}, nil | ||
} | ||
|
||
providerStatus := new(CloudscaleMachineProviderStatus) | ||
if err := yaml.Unmarshal(rawExtension.Raw, providerStatus); err != nil { | ||
return nil, fmt.Errorf("error unmarshalling providerStatus: %v", err) | ||
} | ||
|
||
klog.V(5).Infof("Got provider Status from raw extension: %+v", providerStatus) | ||
return providerStatus, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package v1beta1 | ||
|
||
import "k8s.io/apimachinery/pkg/runtime/schema" | ||
|
||
// +k8s:deepcopy-gen=package | ||
// +k8s:defaulter-gen=TypeMeta | ||
// +k8s:openapi-gen=true | ||
|
||
var ( | ||
GroupName = "machine.appuio.io" | ||
GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"} | ||
) |
Oops, something went wrong.