mirror of https://github.com/kubernetes/kops.git
Minimal cluster-api integration
This only barely works, but we can start to boot machines and make incremental progress.
This commit is contained in:
parent
68c500cf83
commit
ea3122bf67
|
@ -0,0 +1,17 @@
|
|||
# Copyright 2024 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.
|
||||
|
||||
apply:
|
||||
go generate ./...
|
||||
go run sigs.k8s.io/kustomize/kustomize/v5 build config/ | kubectl apply -f -
|
|
@ -0,0 +1,50 @@
|
|||
This is experimental integration with the cluster-api. It is very much not production ready (and currently barely works).
|
||||
|
||||
We plug in our own bootstrap provider with the goal of enabling cluster-api nodes to join a kOps cluster.
|
||||
|
||||
# Create a cluster on GCP
|
||||
|
||||
*Note*: the name & zone matter, we need to match the values we'll create later in the CAPI resources.
|
||||
|
||||
```
|
||||
kops create cluster clusterapi.k8s.local --zones us-east4-a
|
||||
kops update cluster clusterapi.k8s.local --yes --admin
|
||||
kops validate cluster --wait=10m
|
||||
```
|
||||
|
||||
#cd cluster-api-provider-gcp
|
||||
#REGISTRY=${USER} make docker-build docker-push
|
||||
#REGISTRY=${USER} make install-management-cluster # Doesn't yet exist in capg
|
||||
|
||||
|
||||
|
||||
# TODO: Install cert-manager
|
||||
|
||||
# Install CAPI and CAPG
|
||||
```
|
||||
cd clusterapi
|
||||
kubectl apply ---server-side -f manifests/build
|
||||
```
|
||||
|
||||
# Install our CRDs
|
||||
```
|
||||
kustomize build config | kubectl apply --server-side -f -
|
||||
```
|
||||
|
||||
# Remove any stuff left over from previous runs
|
||||
```
|
||||
kubectl delete machinedeployment --all
|
||||
kubectl delete gcpmachinetemplate --all
|
||||
```
|
||||
|
||||
```
|
||||
# Very carefully create a MachineDeployment matching our configuration
|
||||
cat examples/manifest.yaml | IMAGE_ID=projects/ubuntu-os-cloud/global/images/family/ubuntu-2204-lts GCP_NODE_MACHINE_TYPE=e2-medium KUBERNETES_VERSION=v1.28.6 WORKER_MACHINE_COUNT=1 GCP_ZONE=us-east4-a GCP_REGION=us-east4 GCP_NETWORK_NAME=clusterapi-k8s-local GCP_SUBNET=us-east4-clusterapi-k8s-local GCP_PROJECT=$(gcloud config get project) CLUSTER_NAME=clusterapi-k8s-local envsubst | kubectl apply --server-side -n kube-system -f -
|
||||
```
|
||||
|
||||
# IMAGE_ID=projects/debian-cloud/global/images/family/debian-12 doesn't work with user-data (????)
|
||||
|
||||
# Run our controller, which populates the secret with the bootstrap script
|
||||
```
|
||||
go run .
|
||||
```
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
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 controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/klog/v2"
|
||||
api "k8s.io/kops/clusterapi/bootstrap/kops/api/v1beta1"
|
||||
clusterv1 "k8s.io/kops/clusterapi/snapshot/cluster-api/api/v1beta1"
|
||||
"k8s.io/kops/pkg/apis/kops"
|
||||
"k8s.io/kops/pkg/assets"
|
||||
"k8s.io/kops/pkg/client/simple/vfsclientset"
|
||||
"k8s.io/kops/pkg/model"
|
||||
"k8s.io/kops/pkg/model/resources"
|
||||
"k8s.io/kops/pkg/wellknownservices"
|
||||
"k8s.io/kops/upup/pkg/fi"
|
||||
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||
"k8s.io/kops/util/pkg/architectures"
|
||||
"k8s.io/kops/util/pkg/mirrors"
|
||||
"k8s.io/kops/util/pkg/vfs"
|
||||
"k8s.io/utils/pointer"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
)
|
||||
|
||||
// NewKopsConfigReconciler is the constructor for a KopsConfigReconciler
|
||||
func NewKopsConfigReconciler(mgr manager.Manager) error {
|
||||
r := &KopsConfigReconciler{
|
||||
client: mgr.GetClient(),
|
||||
}
|
||||
|
||||
return ctrl.NewControllerManagedBy(mgr).
|
||||
For(&api.KopsConfig{}).
|
||||
Complete(r)
|
||||
}
|
||||
|
||||
// KopsConfigReconciler observes KopsConfig objects.
|
||||
type KopsConfigReconciler struct {
|
||||
// client is the controller-runtime client
|
||||
client client.Client
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=,resources=nodes,verbs=get;list;watch;patch
|
||||
|
||||
// Reconcile is the main reconciler function that observes node changes.
|
||||
func (r *KopsConfigReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||
obj := &api.KopsConfig{}
|
||||
if err := r.client.Get(ctx, req.NamespacedName, obj); err != nil {
|
||||
klog.Warningf("unable to fetch object: %v", err)
|
||||
if apierrors.IsNotFound(err) {
|
||||
// we'll ignore not-found errors, since they can't be fixed by an immediate
|
||||
// requeue (we'll need to wait for a new notification), and we can get them
|
||||
// on deleted requests.
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
data, err := r.buildBootstrapData(ctx)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
if err := r.storeBootstrapData(ctx, obj, data); err != nil {
|
||||
return ctrl.Result{}, err
|
||||
}
|
||||
|
||||
if err := r.client.Status().Update(ctx, obj); err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("error patching status: %w", err)
|
||||
}
|
||||
return ctrl.Result{}, nil
|
||||
}
|
||||
|
||||
// storeBootstrapData creates a new secret with the data passed in as input,
|
||||
// sets the reference in the configuration status and ready to true.
|
||||
func (r *KopsConfigReconciler) storeBootstrapData(ctx context.Context, parent *api.KopsConfig, data []byte) error {
|
||||
// log := ctrl.LoggerFrom(ctx)
|
||||
|
||||
clusterName := parent.Labels[clusterv1.ClusterNameLabel]
|
||||
|
||||
if clusterName == "" {
|
||||
return fmt.Errorf("cluster name label %q not yet set", clusterv1.ClusterNameLabel)
|
||||
}
|
||||
|
||||
secretName := types.NamespacedName{
|
||||
Namespace: parent.GetNamespace(),
|
||||
Name: parent.GetName(),
|
||||
}
|
||||
|
||||
secret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretName.Name,
|
||||
Namespace: secretName.Namespace,
|
||||
Labels: map[string]string{
|
||||
clusterv1.ClusterNameLabel: clusterName,
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"value": data,
|
||||
// "format": []byte(scope.Config.Spec.Format),
|
||||
},
|
||||
Type: clusterv1.ClusterSecretType,
|
||||
}
|
||||
|
||||
parentAPIVersion, parentKind := parent.GetObjectKind().GroupVersionKind().ToAPIVersionAndKind()
|
||||
secret.OwnerReferences = []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: parentAPIVersion,
|
||||
Kind: parentKind,
|
||||
Name: parent.GetName(),
|
||||
UID: parent.GetUID(),
|
||||
Controller: pointer.Bool(true),
|
||||
},
|
||||
}
|
||||
|
||||
var existing corev1.Secret
|
||||
if err := r.client.Get(ctx, secretName, &existing); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
if err := r.client.Create(ctx, secret); err != nil {
|
||||
return fmt.Errorf("failed to create bootstrap data secret for KopsConfig %s/%s: %w", parent.GetNamespace(), parent.GetName(), err)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("failed to get bootstrap data secret: %w", err)
|
||||
}
|
||||
} else {
|
||||
// TODO: Verify that the existing secret "matches"
|
||||
klog.Warningf("TODO: verify that the existing secret matches our expected value")
|
||||
}
|
||||
|
||||
parent.Status.DataSecretName = pointer.String(secret.Name)
|
||||
parent.Status.Ready = true
|
||||
// conditions.MarkTrue(scope.Config, bootstrapv1.DataSecretAvailableCondition)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *KopsConfigReconciler) buildBootstrapData(ctx context.Context) ([]byte, error) {
|
||||
// tf := &TemplateFunctions{
|
||||
// KopsModelContext: *modelContext,
|
||||
// cloud: cloud,
|
||||
// }
|
||||
// TODO: Make dynamic
|
||||
clusterName := "clusterapi.k8s.local"
|
||||
clusterStoreBasePath := "gs://kops-state-justinsb-root-20220725"
|
||||
|
||||
wellKnownAddresses := model.WellKnownAddresses{}
|
||||
wellKnownAddresses[wellknownservices.KopsController] = append(wellKnownAddresses[wellknownservices.KopsController], "10.0.16.2")
|
||||
wellKnownAddresses[wellknownservices.KubeAPIServer] = append(wellKnownAddresses[wellknownservices.KubeAPIServer], "10.0.16.2")
|
||||
|
||||
vfsContext := vfs.NewVFSContext()
|
||||
basePath, err := vfsContext.BuildVfsPath(clusterStoreBasePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing vfs base path: %w", err)
|
||||
}
|
||||
|
||||
// cluster := &kops.Cluster{}
|
||||
// cluster.Spec.KubernetesVersion = "1.28.3"
|
||||
// cluster.Spec.KubeAPIServer = &kops.KubeAPIServerConfig{}
|
||||
|
||||
vfsClientset := vfsclientset.NewVFSClientset(vfsContext, basePath)
|
||||
cluster, err := vfsClientset.GetCluster(ctx, clusterName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting cluster %q: %w", clusterName, err)
|
||||
}
|
||||
|
||||
if cluster.Spec.KubeAPIServer == nil {
|
||||
cluster.Spec.KubeAPIServer = &kops.KubeAPIServerConfig{}
|
||||
}
|
||||
|
||||
ig := &kops.InstanceGroup{}
|
||||
ig.Spec.Role = kops.InstanceGroupRoleNode
|
||||
|
||||
getAssets := false
|
||||
assetBuilder := assets.NewAssetBuilder(vfsContext, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, getAssets)
|
||||
|
||||
encryptionConfigSecretHash := ""
|
||||
// if fi.ValueOf(c.Cluster.Spec.EncryptionConfig) {
|
||||
// secret, err := secretStore.FindSecret("encryptionconfig")
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("could not load encryptionconfig secret: %v", err)
|
||||
// }
|
||||
// if secret == nil {
|
||||
// fmt.Println("")
|
||||
// fmt.Println("You have encryptionConfig enabled, but no encryptionconfig secret has been set.")
|
||||
// fmt.Println("See `kops create secret encryptionconfig -h` and https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/")
|
||||
// return fmt.Errorf("could not find encryptionconfig secret")
|
||||
// }
|
||||
// hashBytes := sha256.Sum256(secret.Data)
|
||||
// encryptionConfigSecretHash = base64.URLEncoding.EncodeToString(hashBytes[:])
|
||||
// }
|
||||
|
||||
nodeUpAssets := make(map[architectures.Architecture]*mirrors.MirroredAsset)
|
||||
for _, arch := range architectures.GetSupported() {
|
||||
|
||||
asset, err := cloudup.NodeUpAsset(assetBuilder, arch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeUpAssets[arch] = asset
|
||||
}
|
||||
|
||||
assets := make(map[architectures.Architecture][]*mirrors.MirroredAsset)
|
||||
configBuilder, err := cloudup.NewNodeUpConfigBuilder(cluster, assetBuilder, assets, encryptionConfigSecretHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// bootstrapScript := &model.BootstrapScript{
|
||||
// // KopsModelContext: modelContext,
|
||||
// Lifecycle: fi.LifecycleSync,
|
||||
// // NodeUpConfigBuilder: configBuilder,
|
||||
// // NodeUpAssets: c.NodeUpAssets,
|
||||
// }
|
||||
|
||||
keysets := make(map[string]*fi.Keyset)
|
||||
|
||||
keystore, err := vfsClientset.KeyStore(cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, keyName := range []string{"kubernetes-ca"} {
|
||||
keyset, err := keystore.FindKeyset(ctx, keyName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting keyset %q: %w", keyName, err)
|
||||
}
|
||||
|
||||
if keyset == nil {
|
||||
return nil, fmt.Errorf("failed to find keyset %q", keyName)
|
||||
}
|
||||
|
||||
keysets[keyName] = keyset
|
||||
}
|
||||
|
||||
_, bootConfig, err := configBuilder.BuildConfig(ig, wellKnownAddresses, keysets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// configData, err := utils.YamlMarshal(config)
|
||||
// if err != nil {
|
||||
// return nil, fmt.Errorf("error converting nodeup config to yaml: %v", err)
|
||||
// }
|
||||
// sum256 := sha256.Sum256(configData)
|
||||
// bootConfig.NodeupConfigHash = base64.StdEncoding.EncodeToString(sum256[:])
|
||||
// b.nodeupConfig.Resource = fi.NewBytesResource(configData)
|
||||
|
||||
var nodeupScript resources.NodeUpScript
|
||||
nodeupScript.NodeUpAssets = nodeUpAssets
|
||||
nodeupScript.BootConfig = bootConfig
|
||||
|
||||
{
|
||||
nodeupScript.EnvironmentVariables = func() (string, error) {
|
||||
env := make(map[string]string)
|
||||
|
||||
// env, err := b.buildEnvironmentVariables()
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// Sort keys to have a stable sequence of "export xx=xxx"" statements
|
||||
var keys []string
|
||||
for k := range env {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
var b bytes.Buffer
|
||||
for _, k := range keys {
|
||||
b.WriteString(fmt.Sprintf("export %s=%s\n", k, env[k]))
|
||||
}
|
||||
return b.String(), nil
|
||||
}
|
||||
|
||||
nodeupScript.ProxyEnv = func() (string, error) {
|
||||
return "", nil
|
||||
// return b.createProxyEnv(cluster.Spec.Networking.EgressProxy)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: nodeupScript.CompressUserData = fi.ValueOf(b.ig.Spec.CompressUserData)
|
||||
|
||||
// By setting some sysctls early, we avoid broken configurations that prevent nodeup download.
|
||||
// See https://github.com/kubernetes/kops/issues/10206 for details.
|
||||
// TODO: nodeupScript.SetSysctls = setSysctls()
|
||||
|
||||
nodeupScript.CloudProvider = string(cluster.Spec.GetCloudProvider())
|
||||
|
||||
nodeupScriptResource, err := nodeupScript.Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b, err := fi.ResourceAsBytes(nodeupScriptResource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
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 v1beta1
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 v1beta1 contains API Schema definitions for the kops v1beta1 API group
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=bootstrap.cluster.x-k8s.io
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects.
|
||||
GroupVersion = schema.GroupVersion{Group: "bootstrap.cluster.x-k8s.io", Version: "v1beta1"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// KopsConfigSpec defines the desired state of KopsConfig.
|
||||
// Either ClusterConfiguration and InitConfiguration should be defined or the JoinConfiguration should be defined.
|
||||
type KopsConfigSpec struct {
|
||||
}
|
||||
|
||||
// KopsConfigStatus defines the observed state of KopsConfig.
|
||||
type KopsConfigStatus struct {
|
||||
// Ready indicates the BootstrapData field is ready to be consumed
|
||||
// +optional
|
||||
Ready bool `json:"ready"`
|
||||
|
||||
// DataSecretName is the name of the secret that stores the bootstrap data script.
|
||||
// +optional
|
||||
DataSecretName *string `json:"dataSecretName,omitempty"`
|
||||
|
||||
// // FailureReason will be set on non-retryable errors
|
||||
// // +optional
|
||||
// FailureReason string `json:"failureReason,omitempty"`
|
||||
|
||||
// // FailureMessage will be set on non-retryable errors
|
||||
// // +optional
|
||||
// FailureMessage string `json:"failureMessage,omitempty"`
|
||||
|
||||
// // ObservedGeneration is the latest generation observed by the controller.
|
||||
// // +optional
|
||||
// ObservedGeneration int64 `json:"observedGeneration,omitempty"`
|
||||
|
||||
// // Conditions defines current service state of the KopsConfig.
|
||||
// // +optional
|
||||
// Conditions clusterv1.Conditions `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=kopsconfigs,scope=Namespaced,categories=cluster-api
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels['cluster\\.x-k8s\\.io/cluster-name']",description="Cluster"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of KopsConfig"
|
||||
|
||||
// KopsConfig is the Schema for the kopsconfigs API.
|
||||
type KopsConfig struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec KopsConfigSpec `json:"spec,omitempty"`
|
||||
Status KopsConfigStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// KopsConfigList contains a list of KopsConfig.
|
||||
type KopsConfigList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []KopsConfig `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&KopsConfig{}, &KopsConfigList{})
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
clusterv1 "k8s.io/kops/clusterapi/snapshot/cluster-api/api/v1beta1"
|
||||
)
|
||||
|
||||
// KopsConfigTemplateSpec defines the desired state of KopsConfigTemplate.
|
||||
type KopsConfigTemplateSpec struct {
|
||||
Template KopsConfigTemplateResource `json:"template"`
|
||||
}
|
||||
|
||||
// KopsConfigTemplateResource defines the Template structure.
|
||||
type KopsConfigTemplateResource struct {
|
||||
// Standard object's metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
|
||||
// +optional
|
||||
ObjectMeta clusterv1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec KopsConfigSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=kopsconfigtemplates,scope=Namespaced,categories=cluster-api
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of KopsConfigTemplate"
|
||||
|
||||
// KopsConfigTemplate is the Schema for the kopsconfigtemplates API.
|
||||
type KopsConfigTemplate struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec KopsConfigTemplateSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// KopsConfigTemplateList contains a list of KopsConfigTemplate.
|
||||
type KopsConfigTemplateList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []KopsConfigTemplate `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&KopsConfigTemplate{}, &KopsConfigTemplateList{})
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
commonLabels:
|
||||
cluster.x-k8s.io/v1beta1: v1beta1
|
||||
|
||||
resources:
|
||||
- crds/bootstrap.cluster.x-k8s.io_kopsconfigs.yaml
|
||||
- crds/bootstrap.cluster.x-k8s.io_kopsconfigtemplates.yaml
|
||||
- crds/controlplane.cluster.x-k8s.io_kopscontrolplanes.yaml
|
||||
- crds/controlplane.cluster.x-k8s.io_kopscontrolplanetemplates.yaml
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
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 v1beta1
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
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 v1beta1 contains API Schema definitions for the kops v1beta1 API group
|
||||
// +kubebuilder:object:generate=true
|
||||
// +groupName=controlplane.cluster.x-k8s.io
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects.
|
||||
GroupVersion = schema.GroupVersion{Group: "controlplane.cluster.x-k8s.io", Version: "v1beta1"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
clusterv1 "k8s.io/kops/clusterapi/snapshot/cluster-api/api/v1beta1"
|
||||
)
|
||||
|
||||
// RolloutStrategyType defines the rollout strategies for a KopsControlPlane.
|
||||
type RolloutStrategyType string
|
||||
|
||||
// KopsControlPlaneSpec defines the desired state of KopsControlPlane.
|
||||
type KopsControlPlaneSpec struct {
|
||||
}
|
||||
|
||||
// KopsControlPlaneMachineTemplate defines the template for Machines
|
||||
// in a KopsControlPlane object.
|
||||
type KopsControlPlaneMachineTemplate struct {
|
||||
// Standard object's metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
|
||||
// +optional
|
||||
ObjectMeta clusterv1.ObjectMeta `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// KopsControlPlaneStatus defines the observed state of KopsControlPlane.
|
||||
type KopsControlPlaneStatus struct {
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=kopscontrolplanes,shortName=kcp,scope=Namespaced,categories=cluster-api
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:subresource:status
|
||||
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
|
||||
// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels['cluster\\.x-k8s\\.io/cluster-name']",description="Cluster"
|
||||
// +kubebuilder:printcolumn:name="Initialized",type=boolean,JSONPath=".status.initialized",description="This denotes whether or not the control plane has the uploaded kops-config configmap"
|
||||
// +kubebuilder:printcolumn:name="API Server Available",type=boolean,JSONPath=".status.ready",description="KopsControlPlane API Server is ready to receive requests"
|
||||
// +kubebuilder:printcolumn:name="Desired",type=integer,JSONPath=".spec.replicas",description="Total number of machines desired by this control plane",priority=10
|
||||
// +kubebuilder:printcolumn:name="Replicas",type=integer,JSONPath=".status.replicas",description="Total number of non-terminated machines targeted by this control plane"
|
||||
// +kubebuilder:printcolumn:name="Ready",type=integer,JSONPath=".status.readyReplicas",description="Total number of fully running and ready control plane machines"
|
||||
// +kubebuilder:printcolumn:name="Updated",type=integer,JSONPath=".status.updatedReplicas",description="Total number of non-terminated machines targeted by this control plane that have the desired template spec"
|
||||
// +kubebuilder:printcolumn:name="Unavailable",type=integer,JSONPath=".status.unavailableReplicas",description="Total number of unavailable machines targeted by this control plane"
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of KopsControlPlane"
|
||||
// +kubebuilder:printcolumn:name="Version",type=string,JSONPath=".spec.version",description="Kubernetes version associated with this control plane"
|
||||
|
||||
// KopsControlPlane is the Schema for the KopsControlPlane API.
|
||||
type KopsControlPlane struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec KopsControlPlaneSpec `json:"spec,omitempty"`
|
||||
Status KopsControlPlaneStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// KopsControlPlaneList contains a list of KopsControlPlane.
|
||||
type KopsControlPlaneList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []KopsControlPlane `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&KopsControlPlane{}, &KopsControlPlaneList{})
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
clusterv1 "k8s.io/kops/clusterapi/snapshot/cluster-api/api/v1beta1"
|
||||
// bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kops/api/v1beta1"
|
||||
)
|
||||
|
||||
// KopsControlPlaneTemplateSpec defines the desired state of KopsControlPlaneTemplate.
|
||||
type KopsControlPlaneTemplateSpec struct {
|
||||
Template KopsControlPlaneTemplateResource `json:"template"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
// +kubebuilder:resource:path=kopscontrolplanetemplates,scope=Namespaced,categories=cluster-api
|
||||
// +kubebuilder:storageversion
|
||||
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Time duration since creation of KopsControlPlaneTemplate"
|
||||
|
||||
// KopsControlPlaneTemplate is the Schema for the kopscontrolplanetemplates API.
|
||||
type KopsControlPlaneTemplate struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec KopsControlPlaneTemplateSpec `json:"spec,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// KopsControlPlaneTemplateList contains a list of KopsControlPlaneTemplate.
|
||||
type KopsControlPlaneTemplateList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []KopsControlPlaneTemplate `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&KopsControlPlaneTemplate{}, &KopsControlPlaneTemplateList{})
|
||||
}
|
||||
|
||||
// KopsControlPlaneTemplateResource describes the data needed to create a KopsControlPlane from a template.
|
||||
type KopsControlPlaneTemplateResource struct {
|
||||
// Standard object's metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
|
||||
// +optional
|
||||
ObjectMeta clusterv1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec KopsControlPlaneTemplateResourceSpec `json:"spec"`
|
||||
}
|
||||
|
||||
// KopsControlPlaneTemplateResourceSpec defines the desired state of KopsControlPlane.
|
||||
// NOTE: KopsControlPlaneTemplateResourceSpec is similar to KopsControlPlaneSpec but
|
||||
// omits Replicas and Version fields. These fields do not make sense on the KopsControlPlaneTemplate,
|
||||
// because they are calculated by the Cluster topology reconciler during reconciliation and thus cannot
|
||||
// be configured on the KopsControlPlaneTemplate.
|
||||
type KopsControlPlaneTemplateResourceSpec struct {
|
||||
}
|
||||
|
||||
// KopsControlPlaneTemplateMachineTemplate defines the template for Machines
|
||||
// in a KopsControlPlaneTemplate object.
|
||||
// NOTE: KopsControlPlaneTemplateMachineTemplate is similar to KopsControlPlaneMachineTemplate but
|
||||
// omits ObjectMeta and InfrastructureRef fields. These fields do not make sense on the KopsControlPlaneTemplate,
|
||||
// because they are calculated by the Cluster topology reconciler during reconciliation and thus cannot
|
||||
// be configured on the KopsControlPlaneTemplate.
|
||||
type KopsControlPlaneTemplateMachineTemplate struct {
|
||||
// Standard object's metadata.
|
||||
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
|
||||
// +optional
|
||||
ObjectMeta clusterv1.ObjectMeta `json:"metadata,omitempty"`
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
---
|
||||
apiVersion: cluster.x-k8s.io/v1beta1
|
||||
kind: Cluster
|
||||
metadata:
|
||||
name: "${CLUSTER_NAME}"
|
||||
spec:
|
||||
#clusterNetwork:
|
||||
# pods:
|
||||
# cidrBlocks: ["192.168.0.0/16"]
|
||||
infrastructureRef:
|
||||
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
|
||||
kind: GCPCluster
|
||||
name: "${CLUSTER_NAME}"
|
||||
controlPlaneRef:
|
||||
kind: KopsControlPlane
|
||||
apiVersion: controlplane.cluster.x-k8s.io/v1beta1
|
||||
name: "${CLUSTER_NAME}-control-plane"
|
||||
---
|
||||
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
|
||||
kind: GCPCluster
|
||||
metadata:
|
||||
name: "${CLUSTER_NAME}"
|
||||
spec:
|
||||
project: "${GCP_PROJECT}"
|
||||
region: "${GCP_REGION}"
|
||||
network:
|
||||
name: "${GCP_NETWORK_NAME}"
|
||||
# ---
|
||||
# kind: KubeadmControlPlane
|
||||
# apiVersion: controlplane.cluster.x-k8s.io/v1beta1
|
||||
# metadata:
|
||||
# name: "${CLUSTER_NAME}-control-plane"
|
||||
# spec:
|
||||
# replicas: ${CONTROL_PLANE_MACHINE_COUNT}
|
||||
# machineTemplate:
|
||||
# infrastructureRef:
|
||||
# kind: GCPMachineTemplate
|
||||
# apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
|
||||
# name: "${CLUSTER_NAME}-control-plane"
|
||||
# kubeadmConfigSpec:
|
||||
# initConfiguration:
|
||||
# nodeRegistration:
|
||||
# name: '{{ ds.meta_data.local_hostname.split(".")[0] }}'
|
||||
# kubeletExtraArgs:
|
||||
# cloud-provider: gce
|
||||
# clusterConfiguration:
|
||||
# apiServer:
|
||||
# timeoutForControlPlane: 20m
|
||||
# extraArgs:
|
||||
# cloud-provider: gce
|
||||
# controllerManager:
|
||||
# extraArgs:
|
||||
# cloud-provider: gce
|
||||
# allocate-node-cidrs: "false"
|
||||
# joinConfiguration:
|
||||
# nodeRegistration:
|
||||
# name: '{{ ds.meta_data.local_hostname.split(".")[0] }}'
|
||||
# kubeletExtraArgs:
|
||||
# cloud-provider: gce
|
||||
# version: "${KUBERNETES_VERSION}"
|
||||
# ---
|
||||
# kind: GCPMachineTemplate
|
||||
# apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
|
||||
# metadata:
|
||||
# name: "${CLUSTER_NAME}-control-plane"
|
||||
# spec:
|
||||
# template:
|
||||
# spec:
|
||||
# instanceType: "${GCP_CONTROL_PLANE_MACHINE_TYPE}"
|
||||
# image: "${IMAGE_ID}"
|
||||
---
|
||||
apiVersion: cluster.x-k8s.io/v1beta1
|
||||
kind: MachineDeployment
|
||||
metadata:
|
||||
name: "${CLUSTER_NAME}-md-0"
|
||||
spec:
|
||||
clusterName: "${CLUSTER_NAME}"
|
||||
replicas: ${WORKER_MACHINE_COUNT}
|
||||
selector:
|
||||
matchLabels:
|
||||
template:
|
||||
spec:
|
||||
clusterName: "${CLUSTER_NAME}"
|
||||
version: "${KUBERNETES_VERSION}"
|
||||
failureDomain: "${GCP_ZONE}"
|
||||
bootstrap:
|
||||
configRef:
|
||||
name: "${CLUSTER_NAME}-md-0"
|
||||
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
|
||||
kind: KopsConfigTemplate
|
||||
infrastructureRef:
|
||||
name: "${CLUSTER_NAME}-md-0"
|
||||
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
|
||||
kind: GCPMachineTemplate
|
||||
---
|
||||
apiVersion: infrastructure.cluster.x-k8s.io/v1beta1
|
||||
kind: GCPMachineTemplate
|
||||
metadata:
|
||||
name: "${CLUSTER_NAME}-md-0"
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
instanceType: "${GCP_NODE_MACHINE_TYPE}"
|
||||
image: "${IMAGE_ID}"
|
||||
subnet: "${GCP_SUBNET}"
|
||||
additionalNetworkTags:
|
||||
- clusterapi-k8s-local-k8s-io-role-node
|
||||
publicIP: true
|
||||
additionalMetadata:
|
||||
- key: kops-k8s-io-instance-group-name
|
||||
value: nodes-us-east4-a
|
||||
- key: cluster-name
|
||||
value: clusterapi.k8s.local
|
||||
|
||||
|
||||
---
|
||||
apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
|
||||
kind: KopsConfigTemplate
|
||||
metadata:
|
||||
name: "${CLUSTER_NAME}-md-0"
|
||||
spec:
|
||||
template:
|
||||
spec: {}
|
||||
#joinConfiguration:
|
||||
# nodeRegistration:
|
||||
# name: '{{ ds.meta_data.local_hostname.split(".")[0] }}'
|
||||
# kubeletExtraArgs:
|
||||
# cloud-provider: gce
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
Copyright 2024 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 main
|
||||
|
||||
//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 output:dir=config/crds crd:crdVersions=v1 paths=./bootstrap/kops/api/...;./controlplane/kops/api/...
|
||||
|
||||
//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.14.0 object paths=./snapshot/cluster-api/...;./bootstrap/kops/api/...;./controlplane/kops/api/...
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
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 main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
coordinationv1 "k8s.io/api/coordination/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/klog/v2/klogr"
|
||||
"k8s.io/kops/clusterapi/bootstrap/controllers"
|
||||
bootstrapapi "k8s.io/kops/clusterapi/bootstrap/kops/api/v1beta1"
|
||||
controlplaneapi "k8s.io/kops/clusterapi/controlplane/kops/api/v1beta1"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
|
||||
var (
|
||||
scheme = runtime.NewScheme()
|
||||
)
|
||||
|
||||
func init() {
|
||||
// +kubebuilder:scaffold:scheme
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
if err := run(ctx); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(ctx context.Context) error {
|
||||
klog.InitFlags(nil)
|
||||
|
||||
// Disable metrics by default (avoid port conflicts, also risky because we are host network)
|
||||
metricsAddress := ":0"
|
||||
|
||||
flag.Parse()
|
||||
|
||||
ctrl.SetLogger(klogr.New())
|
||||
|
||||
if err := buildScheme(); err != nil {
|
||||
return fmt.Errorf("error building scheme: %w", err)
|
||||
}
|
||||
|
||||
kubeConfig := ctrl.GetConfigOrDie()
|
||||
options := ctrl.Options{
|
||||
Scheme: scheme,
|
||||
// MetricsBindAddress: metricsAddress,
|
||||
// LeaderElection: true,
|
||||
// LeaderElectionID: "kops-clusterapi-leader",
|
||||
}
|
||||
options.Metrics = server.Options{
|
||||
BindAddress: metricsAddress,
|
||||
}
|
||||
mgr, err := ctrl.NewManager(kubeConfig, options)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting manager: %w", err)
|
||||
}
|
||||
|
||||
if err := controllers.NewKopsConfigReconciler(mgr); err != nil {
|
||||
return fmt.Errorf("error creating controller: %w", err)
|
||||
}
|
||||
|
||||
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||
return fmt.Errorf("error running manager: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildScheme() error {
|
||||
if err := corev1.AddToScheme(scheme); err != nil {
|
||||
return fmt.Errorf("error registering corev1: %v", err)
|
||||
}
|
||||
|
||||
if err := bootstrapapi.AddToScheme(scheme); err != nil {
|
||||
return fmt.Errorf("error registering api: %w", err)
|
||||
}
|
||||
|
||||
if err := controlplaneapi.AddToScheme(scheme); err != nil {
|
||||
return fmt.Errorf("error registering api: %w", err)
|
||||
}
|
||||
|
||||
// Needed so that the leader-election system can post events
|
||||
if err := coordinationv1.AddToScheme(scheme); err != nil {
|
||||
return fmt.Errorf("error registering coordinationv1: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -36,7 +36,8 @@ type LegacyIdentifier interface {
|
|||
}
|
||||
|
||||
type LegacyInfo struct {
|
||||
InstanceID string
|
||||
InstanceGroup string
|
||||
InstanceID string
|
||||
InstanceGroup string
|
||||
// TODO: Remove
|
||||
InstanceLifecycle string
|
||||
}
|
||||
|
|
|
@ -153,8 +153,8 @@ func (c *NodeUpCommand) Run(out io.Writer) error {
|
|||
return fmt.Errorf("no instance group defined in nodeup config")
|
||||
}
|
||||
|
||||
if want := bootConfig.NodeupConfigHash; want != "" {
|
||||
if got := base64.StdEncoding.EncodeToString(nodeupConfigHash[:]); got != want {
|
||||
if bootConfig.NodeupConfigHash != "" {
|
||||
if want, got := bootConfig.NodeupConfigHash, base64.StdEncoding.EncodeToString(nodeupConfigHash[:]); got != want {
|
||||
return fmt.Errorf("nodeup config hash mismatch (was %q, expected %q)", got, want)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue