operator: always create initial resources (#858)

* operator: move csp clients to own path

* operator: use cloudfake as default csp
This commit is contained in:
3u13r 2023-01-04 16:44:47 +01:00 committed by GitHub
parent f720726074
commit 98316b5248
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 112 additions and 108 deletions

View File

@ -0,0 +1,91 @@
/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
package client
import (
"context"
"fmt"
updatev1alpha1 "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/api/v1alpha1"
)
const (
controlPlanesID = "control-planes-id"
workersID = "workers-id"
)
// Client is a stub client providing the minimal implementation to set up the initial resources.
type Client struct{}
// GetNodeImage retrieves the image currently used by a node.
func (c *Client) GetNodeImage(ctx context.Context, providerID string) (string, error) {
panic("not implemented")
}
// GetScalingGroupID retrieves the scaling group that a node is part of.
func (c *Client) GetScalingGroupID(ctx context.Context, providerID string) (string, error) {
panic("not implemented")
}
// CreateNode creates a new node inside a specified scaling group at the CSP and returns its future name and provider id.
func (c *Client) CreateNode(ctx context.Context, scalingGroupID string) (nodeName, providerID string, err error) {
panic("not implemented")
}
// DeleteNode starts the termination of the node at the CSP.
func (c *Client) DeleteNode(ctx context.Context, providerID string) error {
panic("not implemented")
}
// GetNodeState retrieves the state of a pending node from a CSP.
func (c *Client) GetNodeState(ctx context.Context, providerID string) (updatev1alpha1.CSPNodeState, error) {
panic("not implemented")
}
// SetScalingGroupImage sets the image to be used by newly created nodes in a scaling group.
func (c *Client) SetScalingGroupImage(ctx context.Context, scalingGroupID, image string) error {
panic("not implemented")
}
// GetScalingGroupImage retrieves the image currently used by a scaling group.
func (c *Client) GetScalingGroupImage(ctx context.Context, scalingGroupID string) (string, error) {
return "unsupportedCSP", nil
}
// GetScalingGroupName retrieves the name of a scaling group.
func (c *Client) GetScalingGroupName(scalingGroupID string) (string, error) {
switch scalingGroupID {
case controlPlanesID:
return controlPlanesID, nil
case workersID:
return workersID, nil
default:
return "", fmt.Errorf("unknown scaling group id %s", scalingGroupID)
}
}
// GetAutoscalingGroupName retrieves the name of a scaling group as needed by the cluster-autoscaler.
func (c *Client) GetAutoscalingGroupName(scalingGroupID string) (string, error) {
switch scalingGroupID {
case controlPlanesID:
return controlPlanesID, nil
case workersID:
return workersID, nil
default:
return "", fmt.Errorf("unknown scaling group id %s", scalingGroupID)
}
}
// ListScalingGroups retrieves a list of scaling groups for the cluster.
func (c *Client) ListScalingGroups(ctx context.Context, uid string) (controlPlaneGroupIDs []string, workerGroupIDs []string, err error) {
return []string{controlPlanesID}, []string{workersID}, nil
}
// AutoscalingCloudProvider returns the cloud-provider name as used by k8s cluster-autoscaler.
func (c *Client) AutoscalingCloudProvider() string {
return "unsupportedCSP"
}

View File

@ -44,7 +44,7 @@ func InitialResources(ctx context.Context, k8sClient client.Client, imageInfo im
if err != nil { if err != nil {
return fmt.Errorf("determining initial node image: %w", err) return fmt.Errorf("determining initial node image: %w", err)
} }
imageVersion, err := imageInfo.ImageVersion(imageReference) imageVersion, err := imageInfo.ImageVersion()
if err != nil { if err != nil {
// do not fail if the image version cannot be determined // do not fail if the image version cannot be determined
// this is important for backwards compatibility // this is important for backwards compatibility
@ -192,7 +192,7 @@ func createScalingGroup(ctx context.Context, config newScalingGroupConfig) error
} }
type imageInfoGetter interface { type imageInfoGetter interface {
ImageVersion(imageReference string) (string, error) ImageVersion() (string, error)
} }
type scalingGroupGetter interface { type scalingGroupGetter interface {

View File

@ -393,7 +393,7 @@ type stubImageInfo struct {
err error err error
} }
func (s stubImageInfo) ImageVersion(_ string) (string, error) { func (s stubImageInfo) ImageVersion() (string, error) {
return s.imageVersion, s.err return s.imageVersion, s.err
} }

View File

@ -29,7 +29,7 @@ func NewImageInfo() *ImageInfo {
// ImageVersion tries to parse the image version from the host mounted os-release file. // ImageVersion tries to parse the image version from the host mounted os-release file.
// If the file is not present or does not contain the version, a fallback lookup is performed. // If the file is not present or does not contain the version, a fallback lookup is performed.
func (i *ImageInfo) ImageVersion(imageReference string) (string, error) { func (i *ImageInfo) ImageVersion() (string, error) {
var version string var version string
var err error var err error
for _, path := range osReleasePaths { for _, path := range osReleasePaths {
@ -38,10 +38,13 @@ func (i *ImageInfo) ImageVersion(imageReference string) (string, error) {
break break
} }
} }
if version != "" { if err != nil {
return version, nil return "", err
} }
return imageVersionFromFallback(imageReference) if version == "" {
return "", fmt.Errorf("IMAGE_VERSION not found in %s", strings.Join(osReleasePaths, ", "))
}
return version, nil
} }
// getOSReleaseImageVersion reads the os-release file and returns the image version (if present). // getOSReleaseImageVersion reads the os-release file and returns the image version (if present).
@ -94,17 +97,6 @@ func parseOSRelease(osRelease *bufio.Scanner) (map[string]string, error) {
return osReleaseMap, nil return osReleaseMap, nil
} }
// imageVersionFromFallback tries to guess the image version from the image reference.
// It is a fallback mechanism in case the os-release file is not present or does not contain the version.
// This was the case for older images (< v2.3.0).
func imageVersionFromFallback(imageReference string) (string, error) {
version, ok := fallbackLookup[strings.ToLower(imageReference)]
if !ok {
return "", fmt.Errorf("image version not found in fallback lookup")
}
return version, nil
}
const versionKey = "IMAGE_VERSION" const versionKey = "IMAGE_VERSION"
var ( var (
@ -114,41 +106,4 @@ var (
"/host/etc/os-release", "/host/etc/os-release",
"/host/usr/lib/os-release", "/host/usr/lib/os-release",
} }
fallbackLookup = map[string]string{
// AWS
"ami-06b8cbf4837a0a57c": "v2.2.2",
"ami-02e96dc04a9e438cd": "v2.2.2",
"ami-028ead928a9034b2f": "v2.2.2",
"ami-032ac10dd8d8266e3": "v2.2.1",
"ami-032e0d57cc4395088": "v2.2.1",
"ami-053c3e49e19b96bdd": "v2.2.1",
"ami-0e27ebcefc38f648b": "v2.2.0",
"ami-098cd37f66523b7c3": "v2.2.0",
"ami-04a87d302e2509aad": "v2.2.0",
// Azure
"/communitygalleries/constellationcvm-b3782fa0-0df7-4f2f-963e-fc7fc42663df/images/constellation/versions/2.2.2": "v2.2.2",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation/images/constellation/versions/2.2.2": "v2.2.2",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation_cvm/images/constellation/versions/2.2.2": "v2.2.2",
"/communitygalleries/constellationcvm-b3782fa0-0df7-4f2f-963e-fc7fc42663df/images/constellation/versions/2.2.1": "v2.2.1",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation/images/constellation/versions/2.2.1": "v2.2.1",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation_cvm/images/constellation/versions/2.2.1": "v2.2.1",
"/communitygalleries/constellationcvm-b3782fa0-0df7-4f2f-963e-fc7fc42663df/images/constellation/versions/2.2.0": "v2.2.0",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation/images/constellation/versions/2.2.0": "v2.2.0",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation_cvm/images/constellation/versions/2.2.0": "v2.2.0",
"/communitygalleries/constellationcvm-b3782fa0-0df7-4f2f-963e-fc7fc42663df/images/constellation/versions/2.1.0": "v2.1.0",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation/images/constellation/versions/2.1.0": "v2.1.0",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation_cvm/images/constellation/versions/2.1.0": "v2.1.0",
"/communitygalleries/constellationcvm-b3782fa0-0df7-4f2f-963e-fc7fc42663df/images/constellation/versions/2.0.0": "v2.0.0",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation/images/constellation/versions/2.0.0": "v2.0.0",
"/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourcegroups/constellation-images/providers/microsoft.compute/galleries/constellation_cvm/images/constellation/versions/2.0.0": "v2.0.0",
// GCP
"projects/constellation-images/global/images/constellation-v2-2-2": "v2.2.2",
"projects/constellation-images/global/images/constellation-v2-2-1": "v2.2.1",
"projects/constellation-images/global/images/constellation-v2-2-0": "v2.2.0",
"projects/constellation-images/global/images/constellation-v2-1-0": "v2.1.0",
"projects/constellation-images/global/images/constellation-v2-0-0": "v2.0.0",
}
) )

View File

@ -38,10 +38,6 @@ func TestImageVersion(t *testing.T) {
imageReference: "some-reference", imageReference: "some-reference",
wantErr: true, wantErr: true,
}, },
"fallback version found": {
imageReference: "ami-04a87d302e2509aad",
wantVersion: "v2.2.0",
},
} }
for name, tc := range testCases { for name, tc := range testCases {
@ -59,7 +55,7 @@ func TestImageVersion(t *testing.T) {
fs: &afero.Afero{Fs: fs}, fs: &afero.Afero{Fs: fs},
} }
version, err := imageInfo.ImageVersion(tc.imageReference) version, err := imageInfo.ImageVersion()
if tc.wantErr { if tc.wantErr {
assert.Error(err) assert.Error(err)
return return
@ -124,46 +120,6 @@ func TestParseOSRelease(t *testing.T) {
assert.Equal(wantMap, osReleaseMap) assert.Equal(wantMap, osReleaseMap)
} }
func TestImageVersionFromFallback(t *testing.T) {
testCases := map[string]struct {
imageReference string
wantVersion string
wantErr bool
}{
"AWS reference": {
imageReference: "ami-06b8cbf4837a0a57c",
wantVersion: "v2.2.2",
},
"Azure reference": {
imageReference: "/subscriptions/0d202bbb-4fa7-4af8-8125-58c269a05435/resourceGroups/constellation-images/providers/Microsoft.Compute/galleries/Constellation/images/constellation/versions/2.1.0",
wantVersion: "v2.1.0",
},
"GCP reference": {
imageReference: "projects/constellation-images/global/images/constellation-v2-0-0",
wantVersion: "v2.0.0",
},
"unknown reference": {
imageReference: "unknown",
wantErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
version, err := imageVersionFromFallback(tc.imageReference)
if tc.wantErr {
assert.Error(err)
return
}
require.NoError(err)
assert.Equal(tc.wantVersion, version)
})
}
}
const osRelease = ` const osRelease = `
# Some comment # Some comment
# Some empty lines below # Some empty lines below

View File

@ -24,9 +24,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/log/zap"
azureclient "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/internal/azure/client" azureclient "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/internal/cloud/azure/client"
cloudfake "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/internal/cloud/fake/client"
gcpclient "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/internal/cloud/gcp/client"
"github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/internal/deploy" "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/internal/deploy"
gcpclient "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/internal/gcp/client"
updatev1alpha1 "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/api/v1alpha1" updatev1alpha1 "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/api/v1alpha1"
"github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/controllers" "github.com/edgelesssys/constellation/operators/constellation-node-operator/v2/controllers"
@ -100,6 +101,7 @@ func main() {
} }
default: default:
setupLog.Info("CSP does not support upgrades", "csp", csp) setupLog.Info("CSP does not support upgrades", "csp", csp)
cspClient = &cloudfake.Client{}
} }
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
@ -127,13 +129,13 @@ func main() {
} }
defer etcdClient.Close() defer etcdClient.Close()
// Create Controllers
if csp == "azure" || csp == "gcp" {
imageInfo := deploy.NewImageInfo() imageInfo := deploy.NewImageInfo()
if err := deploy.InitialResources(context.Background(), k8sClient, imageInfo, cspClient, os.Getenv(constellationUID)); err != nil { if err := deploy.InitialResources(context.Background(), k8sClient, imageInfo, cspClient, os.Getenv(constellationUID)); err != nil {
setupLog.Error(err, "Unable to deploy initial resources") setupLog.Error(err, "Unable to deploy initial resources")
os.Exit(1) os.Exit(1)
} }
// Create Controllers
if csp == "azure" || csp == "gcp" {
if err = controllers.NewNodeVersionReconciler( if err = controllers.NewNodeVersionReconciler(
cspClient, etcdClient, mgr.GetClient(), mgr.GetScheme(), cspClient, etcdClient, mgr.GetClient(), mgr.GetScheme(),
).SetupWithManager(mgr); err != nil { ).SetupWithManager(mgr); err != nil {
@ -204,7 +206,7 @@ type cspAPI interface {
SetScalingGroupImage(ctx context.Context, scalingGroupID, imageURI string) error SetScalingGroupImage(ctx context.Context, scalingGroupID, imageURI string) error
// GetScalingGroupName retrieves the name of a scaling group. // GetScalingGroupName retrieves the name of a scaling group.
GetScalingGroupName(scalingGroupID string) (string, error) GetScalingGroupName(scalingGroupID string) (string, error)
// GetScalingGroupName retrieves the name of a scaling group as needed by the cluster-autoscaler. // GetAutoscalingGroupName retrieves the name of a scaling group as needed by the cluster-autoscaler.
GetAutoscalingGroupName(scalingGroupID string) (string, error) GetAutoscalingGroupName(scalingGroupID string) (string, error)
// ListScalingGroups retrieves a list of scaling groups for the cluster. // ListScalingGroups retrieves a list of scaling groups for the cluster.
ListScalingGroups(ctx context.Context, uid string) (controlPlaneGroupIDs []string, workerGroupIDs []string, err error) ListScalingGroups(ctx context.Context, uid string) (controlPlaneGroupIDs []string, workerGroupIDs []string, err error)