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

✨ CSPO #23

Merged
merged 33 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5a5048f
Update OpenStackClusterStackRelease and OpenStackNodeImageRelease types
matofeder Dec 21, 2023
3174fbd
Remove openstackclusterstackreleasetemplate controller
matofeder Dec 21, 2023
87c2426
Add GitHub client and download release assets
chess-knight Dec 21, 2023
668228d
Add OpenStackNodeImageRelease creation logic in OpenStackClusterStack…
matofeder Dec 27, 2023
fcb446f
Add conditions for OpenStackClusterStackRelease
matofeder Dec 28, 2023
71195a8
Add image import functionality
michal-gubricky Dec 21, 2023
c06113c
Rewrite "waitForImageActive" to be non-blocking
NotTheEvilOne Dec 21, 2023
1afdfcd
Fix error handling in "Reconcile()"
NotTheEvilOne Dec 21, 2023
7c6d831
Download images simultaneously
michal-gubricky Dec 22, 2023
e0d6c0d
Fix formatting and error handling
matofeder Dec 27, 2023
7731919
Add image import logic and adjust types accordingly
matofeder Dec 29, 2023
80e13fb
Reuse existing "images.CreateOpts" for node image releases
NotTheEvilOne Jan 3, 2024
a724a83
Add handling for all posible cases of (#31)
michal-gubricky Jan 4, 2024
e0ca13f
Revert "Reuse existing "images.CreateOpts" for node image releases"
matofeder Jan 4, 2024
43d1ee5
Handle image statuses
matofeder Jan 4, 2024
7990f5f
Add timeout logic
matofeder Jan 4, 2024
07f745e
Merge branch 'main' into cspo
matofeder Jan 4, 2024
8d2ae75
Add timeout error into container logs of cspo pod
michal-gubricky Jan 5, 2024
d6d907e
Reuse existing "images.CreateOpts" for node image releases
NotTheEvilOne Jan 4, 2024
9b606fa
Add shortName to resources
matofeder Jan 5, 2024
e180c9e
Bump CSO version to v0.1.0-alpha.2
matofeder Jan 8, 2024
4339be1
Add missing release targets and tools
chess-knight Jan 8, 2024
f10db2f
Deleting cso webhook is no longer necessary
chess-knight Jan 8, 2024
4755125
Rename cache cleaner github workflow file
chess-knight Jan 9, 2024
fd0889e
Add develop doc (#36)
michal-gubricky Jan 9, 2024
7872848
:book: Add Readme (#38)
matofeder Jan 10, 2024
0d6acfa
:sparkles: Cspo multiple images (#39)
matofeder Jan 10, 2024
0a9e95c
Merge branch 'main' into cspo
matofeder Jan 10, 2024
63bfb51
Apply suggestions from code review
matofeder Jan 11, 2024
592930b
Fix small typo after 63bfb51d6aea20260ba73be83f21f101fd0a9bd1
chess-knight Jan 12, 2024
a50f9f2
Ensure that cloud name MinLength is 1
chess-knight Jan 12, 2024
9c204d4
Update controller logic when some failure occurs
matofeder Jan 12, 2024
7d7345b
Catch NotFound secret and add condition
chess-knight Jan 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 12 additions & 0 deletions .envrc.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export KUBECONFIG=$PWD/.mgt-cluster-kubeconfig.yaml
export K8S_VERSION=1-27
export GIT_PROVIDER_B64=Z2l0aHVi
export GIT_ACCESS_TOKEN_B64=mybase64encodedtoken
export GIT_ORG_NAME_B64=U292ZXJlaWduQ2xvdWRTdGFjaw==
export GIT_REPOSITORY_NAME_B64=Y2x1c3Rlci1zdGFja3M=
export EXP_CLUSTER_RESOURCE_SET=true
export EXP_MACHINE_POOL=true
export CLUSTER_TOPOLOGY=true
export EXP_RUNTIME_SDK=true
export EXP_MACHINE_SET_PREFLIGHT_CHECKS=true
export CLUSTER_NAME=test-dfkhje
11 changes: 9 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,14 @@ clean-bin: ## Remove all generated helper binaries
rm -rf $(BIN_DIR)
rm -rf $(TOOLS_BIN_DIR)

.PHONY: clean-release
clean-release: ## Remove the release folder
rm -rf $(RELEASE_DIR)

.PHONY: clean-release-git
clean-release-git: ## Restores the git files usually modified during a release
git restore ./*manager_config_patch.yaml ./*manager_pull_policy.yaml

##@ Build

.PHONY: build
Expand Down Expand Up @@ -443,8 +451,7 @@ release: clean-release ## Builds and push container images using the latest git
@if ! [ -z "$$(git status --porcelain)" ]; then echo "Your local git repository contains uncommitted changes, use git clean before proceeding."; exit 1; fi
git checkout "${RELEASE_TAG}"
# Set the manifest image to the production bucket.
$(MAKE) set-manifest-image MANIFEST_IMG=$(IMAGE_PREFIX)/cso MANIFEST_TAG=$(RELEASE_TAG) TARGET_RESOURCE="./config/default/manager_config_patch.yaml"
$(MAKE) set-manifest-image MANIFEST_IMG=$(IMAGE_PREFIX)/cspo MANIFEST_TAG=$(RELEASE_TAG)
$(MAKE) set-manifest-image MANIFEST_IMG=$(IMAGE_PREFIX)/cspo MANIFEST_TAG=$(RELEASE_TAG) TARGET_RESOURCE="./config/default/manager_config_patch.yaml"
$(MAKE) set-manifest-pull-policy TARGET_RESOURCE="./config/default/manager_pull_policy.yaml"
## Build the manifests
$(MAKE) release-manifests clean-release-git
Expand Down
167 changes: 166 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,166 @@
# cluster-stack-provider-openstack
# Cluster Stack Provider OpenStack

[![GitHub Latest Release](https://img.shields.io/github/v/release/SovereignCloudStack/cluster-stack-provider-openstack?logo=github)](https://github.com/SovereignCloudStack/cluster-stack-provider-openstack/releases)
[![Go Report Card](https://goreportcard.com/badge/github.com/sovereignCloudStack/cluster-stack-provider-openstack)](https://goreportcard.com/report/github.com/sovereignCloudStack/cluster-stack-provider-openstack)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

The Cluster Stack Provider OpenStack (CSPO) works with the Cluster Stack Operator (CSO) and Cluster Stacks, enabling the creation of Kubernetes clusters in a Cluster-API-native (CAPI) fashion.

The primary goal of the CSPO is to facilitate the import of node images in a manner specific to OpenStack. These images are then used to create Kubernetes workload clusters on top of the OpenStack infrastructure.

To gain a comprehensive understanding of the entire concept, we recommend familiarizing yourself with the fundamental [concepts](https://github.com/SovereignCloudStack/cluster-stack-operator/blob/main/docs/concept.md) and [architecture](https://github.com/SovereignCloudStack/cluster-stack-operator/blob/main/docs/architecture/overview.md) outlined in [CSO](https://github.com/SovereignCloudStack/cluster-stack-operator/blob/main/README.md) and [Cluster Stacks](https://github.com/SovereignCloudStack/cluster-stacks/blob/main/README.md).

# Quickstart Guide

This section guides you through all the necessary steps to create a workload Kubernetes cluster on top of the OpenStack infrastructure. The guide describes a path that utilizes the [clusterctl] CLI tool to manage the lifecycle of a CAPI management cluster and employs [kind] to create a local non-production management cluster.

Note that it is a common practice to create a temporary, local [bootstrap cluster](https://cluster-api.sigs.k8s.io/reference/glossary#bootstrap-cluster) which is then used to provision a target [management cluster](https://cluster-api.sigs.k8s.io/reference/glossary#management-cluster) on the selected infrastructure.

## Prerequisites

- Install [Docker] and [kind]
- Install [kubectl]
- Install [Helm]
- Install [clusterctl]
- Install [go] # installation of the Go package `envsubst` is required to enable the expansion of variables specified in CSPO and CSO manifests.

## Initialize the management cluster

Create the kind cluster:

```bash
kind create cluster
```

Transform the Kubernetes cluster into a management cluster by using `clusterctl init` and bootstrap it with CAPI and Cluster API Provider OpenStack ([CAPO]) components:

```bash
# Enable Cluster Class CAPI experimental feature
export CLUSTER_TOPOLOGY=true

# Install CAPI and CAPO components
clusterctl init --infrastructure openstack
```

### Create a secret for OpenStack access

To enable communication between the CSPO and the Cluster API Provider for OpenStack (CAPO) with the OpenStack API, it is necessary to generate a secret containing the access data (clouds.yaml).
Ensure that this secret is located in the identical namespace as the other Custom Resources.

```bash
kubectl create secret generic <my-cloud-secret> --from-file=clouds.yaml=path/to/clouds.yaml

# Patch the created secrets so they are automatically moved to the target cluster later.

kubectl patch secret <my-cloud-secret> -p '{"metadata":{"labels":{"clusterctl.cluster.x-k8s.io/move":""}}}'
```

### CSO and CSPO variables preparation

The CSO and CSPO must be directed to the Cluster Stacks repository housing releases for the OpenStack provider.
Modify and export the following environment variables if you wish to redirect CSO and CSPO to an alternative Git repository

Be aware that GitHub enforces limitations on the number of API requests per unit of time. To overcome this,
it is recommended to configure a personal access token for authenticated calls. This will significantly increase the rate limit for GitHub API requests.

```bash
export GIT_PROVIDER_B64=Z2l0aHVi # github
export GIT_ORG_NAME_B64=U292ZXJlaWduQ2xvdWRTdGFjaw== # SovereignCloudStack
export GIT_REPOSITORY_NAME_B64=Y2x1c3Rlci1zdGFja3M= # cluster-stacks
export GIT_ACCESS_TOKEN_B64=<my-github-access-token>
```

### CSO and CSPO deployment

Install the [envsubst] Go package. It is required to enable the expansion of variables specified in CSPO and CSO manifests.

```bash
GOBIN=/tmp go install github.com/drone/envsubst/v2/cmd/envsubst@latest
```

Get the latest CSO release version and apply CSO manifests to the management cluster.

```bash
# Get the latest CSO release version
CSO_VERSION=$(curl https://api.github.com/repos/SovereignCloudStack/cluster-stack-operator/releases/latest -s | jq .name -r)
# Apply CSO manifests
curl -sSL https://github.com/sovereignCloudStack/cluster-stack-operator/releases/download/${CSO_VERSION}/cso-infrastructure-components.yaml | /tmp/envsubst | kubectl apply -f -
```

Get the latest CSPO release version and apply CSPO manifests to the management cluster.

```bash
# Get the latest CSPO release version
CSPO_VERSION=$(curl https://api.github.com/repos/SovereignCloudStack/cluster-stack-provider-openstack/releases/latest -s | jq .name -r)
# Apply CSPO manifests
curl -sSL https://github.com/sovereignCloudStack/cluster-stack-provider-openstack/releases/download/${CSPO_VERSION}/cspo-infrastructure-components.yaml | /tmp/envsubst | kubectl apply -f -
```
matofeder marked this conversation as resolved.
Show resolved Hide resolved

## Create the workload cluster

To transfer the credentials stored in the mentioned secret [above](#create-a-secret-for-openstack-access) to the operator,
create an `OpenStackClusterStackReleaseTemplate` object and specify this secret in the `identityRef` field.
The `clouds.yaml` file may contain one or more clouds, so users must specify the desired connection to a specific cloud using the `cloudName` field.
Refer to the [examples/cspotemplate.yaml](./examples/cspotemplate.yaml) file for more details.

Next, apply this template to the management cluster:

```bash
kubectl apply -f <path-to-openstack-clusterstack-release-template>
```

Proceed to apply the `ClusterStack` to the management cluster. For more details, refer to [examples/clusterstack.yaml](./examples/clusterstack.yaml):

```bash
kubectl apply -f <path-to-openstack-clusterstack>
```

Please be patient and wait for the operator to execute the necessary tasks.
If your `ClusterStack` object encounters no errors and `openstacknodeimagereleases` is ready, you can deploy a workload cluster.
This can be done by applying the cluster-template.
Refer to the example of this template in [examples/cluster.yaml](./examples/cluster.yaml):

```bash
kubectl apply -f <path-to-cluster-template>
```

Utilize a convenient CLI `clusterctl` to investigate the health of the cluster:

```bash
clusterctl describe cluster <cluster-name>
```

Once the cluster is provisioned and in good health, you can retrieve its kubeconfig and establish communication with the newly created workload cluster:

```bash
# Get the workload cluster kubeconfig
clusterctl get kubeconfig <cluster-name> > kubeconfig.yaml
# Communicate with the workload cluster
kubectl --kubeconfig kubeconfig.yaml get nodes
```

# Compatibility with Cluster Stack Operator

| | CSO `v0.1.0-alpha.2` |
| ----------------------- | -------------------- |
| CSPO `v0.1.0-alpha.rc1` | ✓ |

# Development guide

Refer to the [doc page](./docs/develop.md) to find more information about how to develop this operator.

# API Reference

CSPO currently exposes the following APIs:
- the CSPO Custom Resource Definitions (CRDs): [documentation](https://doc.crds.dev/github.com/SovereignCloudStack/cluster-stack-provider-openstack)
- Golang APIs: tbd

<!-- links -->
[Docker]: https://www.docker.com/
[Helm]: https://helm.sh/docs/intro/install/
[kind]: https://kind.sigs.k8s.io/
[kubectl]: https://kubernetes.io/docs/tasks/tools/install-kubectl/
[clusterctl]: https://cluster-api.sigs.k8s.io/user/quick-start.html#install-clusterctl
[CAPO]: https://github.com/kubernetes-sigs/cluster-api-provider-openstack
[go]: https://go.dev/doc/install
[envsubst]: https://github.com/drone/envsubst
4 changes: 2 additions & 2 deletions Tiltfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ settings = {
"preload_images_for_kind": True,
"kind_cluster_name": "cspo",
"capi_version": "v1.5.2",
"cso_version": "v0.1.0-alpha.1",
"cso_version": "v0.1.0-alpha.2",
"capo_version": "v0.8.0",
"cert_manager_version": "v1.13.1",
"kustomize_substitutions": {
Expand Down Expand Up @@ -185,7 +185,7 @@ def deploy_cspo():
"cspo-leader-election-rolebinding:rolebinding",
"cspo-manager-rolebinding:clusterrolebinding",
#"cspo-serving-cert:certificate",
#"cspo-cluster-stack-variables:secret",
"cspo-cluster-stack-variables:secret",
#"cspo-selfsigned-issuer:issuer",
#"cspo-validating-webhook-configuration:validatingwebhookconfiguration",
],
Expand Down
89 changes: 89 additions & 0 deletions api/v1alpha1/conditions_const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright 2023 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
clusterv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
)

const (
// ClusterStackReleaseAssetsReadyCondition reports on whether the download of cluster stack release assets is complete.
ClusterStackReleaseAssetsReadyCondition clusterv1beta1.ConditionType = "ClusterStackReleaseDownloaded"
matofeder marked this conversation as resolved.
Show resolved Hide resolved

// ReleaseAssetsNotDownloadedYetReason is used when release assets are not yet downloaded.
ReleaseAssetsNotDownloadedYetReason = "ReleaseAssetsNotDownloadedYet"

// IssueWithReleaseAssetsReason is used when release assets have an issue.
IssueWithReleaseAssetsReason = "IssueWithReleaseAssets"
)

const (
// OpenStackNodeImageReleasesReadyCondition reports on whether all relevant OpenStackNodeImageRelease objects are ready.
OpenStackNodeImageReleasesReadyCondition clusterv1beta1.ConditionType = "OpenStackNodeImageReleasesReady"

// ProcessOngoingReason is used when the process of the OpenStackNodeImageRelease object is still ongoing.
ProcessOngoingReason = "ProcessOngoing"
)

const (
// GitAPIAvailableCondition is used when Git API is available.
GitAPIAvailableCondition = "GitAPIAvailable"

// GitTokenOrEnvVariableNotSetReason is used when user don't specify the token or environment variable.
GitTokenOrEnvVariableNotSetReason = "GitTokenOrEnvVariableNotSet" //#nosec
)

const (
// CloudAvailableCondition is used when cloud is available.
CloudAvailableCondition = "CloudAvailable"

// CloudNotSetReason is used when user don't specify a valid clouds.yaml inside a secret.
CloudNotSetReason = "CloudNotSet"
)

const (
// OpenStackImageServiceClientAvailableCondition is used when OpenStack Image Service Client is available.
OpenStackImageServiceClientAvailableCondition = "OpenStackImageServiceClientAvailable"

// OpenStackImageServiceClientNotSetReason is used when OpenStack Image Service Client is not available.
OpenStackImageServiceClientNotSetReason = "OpenStackImageServiceClientNotSet"
)

const (
// OpenStackImageImportStartCondition reports the image import start.
OpenStackImageImportStartCondition = "OpenStackImageImportStart"
matofeder marked this conversation as resolved.
Show resolved Hide resolved

// OpenStackImageImportNotStartReason is used when image import does not start yet.
OpenStackImageImportNotStartReason = "OpenStackImageImportNotStartReason"
)

const (
// OpenStackImageReadyCondition reports on whether the image of cluster stack release is imported and active.
OpenStackImageReadyCondition clusterv1beta1.ConditionType = "OpenStackImageActive"

// OpenStackImageNotCreatedYetReason is used when image is not yet created.
OpenStackImageNotCreatedYetReason = "OpenStackImageNotCreateYet"

// OpenStackImageNotImportedYetReason is used when image is not yet imported.
OpenStackImageNotImportedYetReason = "OpenStackImageNotImportedYet"

// OpenStackImageImportTimeOutReason is used when image import timeout.
OpenStackImageImportTimeOutReason = "OpenStackImageImportTimeOutReason"

// IssueWithOpenStackImageReason is used when image has an issue.
IssueWithOpenStackImageReason = "IssueWithOpenStackImage"
)
27 changes: 22 additions & 5 deletions api/v1alpha1/openstackclusterstackrelease_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,38 @@ package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiv1alpha7 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7"
clusterv1beta1 "sigs.k8s.io/cluster-api/api/v1beta1"
)

// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// OpenStackClusterStackReleaseSpec defines the desired state of OpenStackClusterStackRelease.
type OpenStackClusterStackReleaseSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

// Foo is an example field of OpenStackClusterStackRelease. Edit openstackclusterstackrelease_types.go to remove/update
Foo string `json:"foo,omitempty"`
// The name of the cloud to use from the clouds secret
matofeder marked this conversation as resolved.
Show resolved Hide resolved
CloudName string `json:"cloudName"`
// IdentityRef is a reference to a identity to be used when reconciling this cluster
IdentityRef *apiv1alpha7.OpenStackIdentityReference `json:"identityRef"`
}

// OpenStackClusterStackReleaseStatus defines the observed state of OpenStackClusterStackRelease.
type OpenStackClusterStackReleaseStatus struct {
// +optional
// +kubebuilder:default:=false
Ready bool `json:"ready,omitempty"`
// Conditions defines current service state of the OpenStackClusterStackRelease.
// +optional
Conditions clusterv1beta1.Conditions `json:"conditions,omitempty"`
}

//+kubebuilder:object:root=true
//+kubebuilder:resource:shortName=oscsr
//+kubebuilder:subresource:status
//+kubebuilder:printcolumn:name="Ready",type="boolean",JSONPath=".status.ready"
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of OpenStackClusterStackRelease"
//+kubebuilder:printcolumn:name="Reason",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].reason"
//+kubebuilder:printcolumn:name="Message",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].message"

// OpenStackClusterStackRelease is the Schema for the openstackclusterstackreleases API.
type OpenStackClusterStackRelease struct {
Expand All @@ -53,6 +60,16 @@ type OpenStackClusterStackRelease struct {
Status OpenStackClusterStackReleaseStatus `json:"status,omitempty"`
}

// GetConditions returns the observations of the operational state of the OpenStackClusterStackRelease resource.
func (r *OpenStackClusterStackRelease) GetConditions() clusterv1beta1.Conditions {
return r.Status.Conditions
}

// SetConditions sets the underlying service state of the OpenStackClusterStackRelease to the predescribed clusterv1.Conditions.
func (r *OpenStackClusterStackRelease) SetConditions(conditions clusterv1beta1.Conditions) {
r.Status.Conditions = conditions
}

//+kubebuilder:object:root=true

// OpenStackClusterStackReleaseList contains a list of OpenStackClusterStackRelease.
Expand Down
1 change: 1 addition & 0 deletions api/v1alpha1/openstackclusterstackreleasetemplate_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type OpenStackClusterStackReleaseTemplateStatus struct {
}

//+kubebuilder:object:root=true
//+kubebuilder:resource:shortName=oscsrt
//+kubebuilder:subresource:status

// OpenStackClusterStackReleaseTemplate is the Schema for the openstackclusterstackreleasetemplates API.
Expand Down
Loading
Loading