Merge "Allow to use variable substitution for cluster-api components"
This commit is contained in:
commit
fbbd21f392
@ -29,6 +29,12 @@ type Clusterctl struct {
|
|||||||
Providers []*Provider `json:"providers,omitempty"`
|
Providers []*Provider `json:"providers,omitempty"`
|
||||||
InitOptions *InitOptions `json:"init-options,omitempty"`
|
InitOptions *InitOptions `json:"init-options,omitempty"`
|
||||||
MoveOptions *MoveOptions `json:"move-options,omitempty"`
|
MoveOptions *MoveOptions `json:"move-options,omitempty"`
|
||||||
|
// AdditionalComponentVariables are variables that will be available to clusterctl
|
||||||
|
// when reading provider components
|
||||||
|
AdditionalComponentVariables map[string]string `json:"additional-vars,omitempty"`
|
||||||
|
// EnvVars if set to true, allows to source variables for cluster-api components
|
||||||
|
// for environment variables.
|
||||||
|
EnvVars bool `json:"env-vars,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provider is part of clusterctl config
|
// Provider is part of clusterctl config
|
||||||
@ -44,6 +50,11 @@ type Provider struct {
|
|||||||
// Map of versions where each key is a version and value is path relative to target path of the manifest
|
// Map of versions where each key is a version and value is path relative to target path of the manifest
|
||||||
// ignored if IsClusterctlRepository is set to true
|
// ignored if IsClusterctlRepository is set to true
|
||||||
Versions map[string]string `json:"versions,omitempty"`
|
Versions map[string]string `json:"versions,omitempty"`
|
||||||
|
|
||||||
|
// VariableSubstitution indicates weather you want to substitute variales in the cluster-api manifests
|
||||||
|
// if set to true, variables will be substituted only if they are defined either in Environment or
|
||||||
|
// in AdditionalComponentVariables, if not they will be left as is.
|
||||||
|
VariableSubstitution bool `json:"variable-substitution,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitOptions container with exposed clusterctl InitOptions
|
// InitOptions container with exposed clusterctl InitOptions
|
||||||
|
@ -86,9 +86,10 @@ func (f RepositoryFactory) repoFactory(provider config.Provider) (repository.Cli
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &implementations.RepositoryClient{
|
return &implementations.RepositoryClient{
|
||||||
Client: repoClient,
|
Client: repoClient,
|
||||||
ProviderType: string(repoType),
|
ProviderType: string(repoType),
|
||||||
ProviderName: name}, nil
|
ProviderName: name,
|
||||||
|
VariableSubstitution: airProv.VariableSubstitution}, nil
|
||||||
}
|
}
|
||||||
log.Printf("Creating clusterctl repository implementation interface for provider %s of type %s\n",
|
log.Printf("Creating clusterctl repository implementation interface for provider %s of type %s\n",
|
||||||
name,
|
name,
|
||||||
|
@ -25,17 +25,17 @@ var _ repository.ComponentsClient = &ComponentsClient{}
|
|||||||
// ComponentsClient override Get() method to return same components,
|
// ComponentsClient override Get() method to return same components,
|
||||||
// but in our implementation we skip variable substitution.
|
// but in our implementation we skip variable substitution.
|
||||||
type ComponentsClient struct {
|
type ComponentsClient struct {
|
||||||
client repository.ComponentsClient
|
client repository.ComponentsClient
|
||||||
providerType string
|
providerType string
|
||||||
providerName string
|
providerName string
|
||||||
|
variableSubstitution bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the components from a repository but without variable substitution
|
// Get returns the components from a repository but without variable substitution
|
||||||
func (cc *ComponentsClient) Get(options repository.ComponentsOptions) (repository.Components, error) {
|
func (cc *ComponentsClient) Get(options repository.ComponentsOptions) (repository.Components, error) {
|
||||||
// This removes variable substitution in components.yaml
|
// Invert variable substitution, so that by default clusterctl will not substitute variables
|
||||||
// TODO we may consider making this configurable
|
options.SkipVariables = !cc.variableSubstitution
|
||||||
options.SkipVariables = true
|
log.Printf("Getting airshipctl provider components, skipping variable substitution: %t.\n"+
|
||||||
log.Debugf("Getting airshipctl provider components, setting skipping variable substitution.\n"+
|
"Provider type: %s, name: %s\n", options.SkipVariables, cc.providerType, cc.providerName)
|
||||||
"Provider type: %s, name: %s\n", cc.providerType, cc.providerName)
|
|
||||||
return cc.client.Get(options)
|
return cc.client.Get(options)
|
||||||
}
|
}
|
||||||
|
@ -44,3 +44,12 @@ type ErrValueForVariableNotSet struct {
|
|||||||
func (e ErrValueForVariableNotSet) Error() string {
|
func (e ErrValueForVariableNotSet) Error() string {
|
||||||
return fmt.Sprintf("value for variable %q is not set", e.Variable)
|
return fmt.Sprintf("value for variable %q is not set", e.Variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrAppendNotAllowed is returned when version map is empty or not defined
|
||||||
|
type ErrAppendNotAllowed struct {
|
||||||
|
Variables map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrAppendNotAllowed) Error() string {
|
||||||
|
return fmt.Sprintf(`variables %v, are not allowed to be appended from clusterctl.AdditoinalVariables`, e.Variables)
|
||||||
|
}
|
||||||
|
@ -15,11 +15,15 @@
|
|||||||
package implementations
|
package implementations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
|
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
|
||||||
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
|
|
||||||
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ config.Reader = &AirshipReader{}
|
var _ config.Reader = &AirshipReader{}
|
||||||
@ -32,7 +36,8 @@ const (
|
|||||||
|
|
||||||
// AirshipReader provides a reader implementation backed by a map
|
// AirshipReader provides a reader implementation backed by a map
|
||||||
type AirshipReader struct {
|
type AirshipReader struct {
|
||||||
variables map[string]string
|
variables map[string]string
|
||||||
|
varsFromEnv bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// configProvider is a mirror of config.Provider, re-implemented here in order to
|
// configProvider is a mirror of config.Provider, re-implemented here in order to
|
||||||
@ -51,10 +56,20 @@ func (f *AirshipReader) Init(config string) error {
|
|||||||
|
|
||||||
// Get implementation of clusterctl reader interface
|
// Get implementation of clusterctl reader interface
|
||||||
func (f *AirshipReader) Get(key string) (string, error) {
|
func (f *AirshipReader) Get(key string) (string, error) {
|
||||||
// TODO handle empty keys
|
// if value is set in variables - return it, variables from variables map take precedence over
|
||||||
|
// env variables
|
||||||
if val, ok := f.variables[key]; ok {
|
if val, ok := f.variables[key]; ok {
|
||||||
return val, nil
|
return val, nil
|
||||||
}
|
}
|
||||||
|
// if we are allowed to check environment variables and key is allowed to be taken from env
|
||||||
|
// look it up and return
|
||||||
|
if f.varsFromEnv && allowFromEnv(key) {
|
||||||
|
val, ok := os.LookupEnv(key)
|
||||||
|
if ok {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if neither env nor variables slice has the var, return error
|
||||||
return "", ErrValueForVariableNotSet{Variable: key}
|
return "", ErrValueForVariableNotSet{Variable: key}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +88,23 @@ func (f *AirshipReader) UnmarshalKey(key string, rawval interface{}) error {
|
|||||||
return yaml.Unmarshal([]byte(data), rawval)
|
return yaml.Unmarshal([]byte(data), rawval)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func allowFromEnv(key string) bool {
|
||||||
|
variableRegEx := regexp.MustCompile(`^([A-Z0-9_$]+)$`)
|
||||||
|
log.Debugf("Verifying that variable %s is allowed to be taken from environment", key)
|
||||||
|
return variableRegEx.MatchString(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func allowAppend(key, _ string) bool {
|
||||||
|
// TODO Investigate if more vaildation should be done here
|
||||||
|
forbidenVars := map[string]string{
|
||||||
|
config.ProvidersConfigKey: "",
|
||||||
|
imagesConfigKey: "",
|
||||||
|
}
|
||||||
|
_, forbid := forbidenVars[key]
|
||||||
|
log.Debugf("Verifying that variable %s is allowed to be appended", key)
|
||||||
|
return !forbid
|
||||||
|
}
|
||||||
|
|
||||||
// NewAirshipReader returns airship implementation of clusterctl reader interface
|
// NewAirshipReader returns airship implementation of clusterctl reader interface
|
||||||
func NewAirshipReader(options *airshipv1.Clusterctl) (*AirshipReader, error) {
|
func NewAirshipReader(options *airshipv1.Clusterctl) (*AirshipReader, error) {
|
||||||
variables := map[string]string{}
|
variables := map[string]string{}
|
||||||
@ -89,9 +121,18 @@ func NewAirshipReader(options *airshipv1.Clusterctl) (*AirshipReader, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
for key, val := range options.AdditionalComponentVariables {
|
||||||
|
// if variable is not allowed, it will be ignored
|
||||||
|
if allowAppend(key, val) {
|
||||||
|
variables[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
// Add providers to config
|
// Add providers to config
|
||||||
variables[config.ProvidersConfigKey] = string(b)
|
variables[config.ProvidersConfigKey] = string(b)
|
||||||
// Add empty image configuration to config
|
// Add empty image configuration to config
|
||||||
variables[imagesConfigKey] = ""
|
variables[imagesConfigKey] = ""
|
||||||
return &AirshipReader{variables: variables}, nil
|
return &AirshipReader{
|
||||||
|
variables: variables,
|
||||||
|
varsFromEnv: options.EnvVars,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,9 @@ var _ config.Provider = &RepositoryClient{}
|
|||||||
// but in our implementation we skip variable substitution.
|
// but in our implementation we skip variable substitution.
|
||||||
type RepositoryClient struct {
|
type RepositoryClient struct {
|
||||||
repository.Client
|
repository.Client
|
||||||
ProviderType string
|
VariableSubstitution bool
|
||||||
ProviderName string
|
ProviderType string
|
||||||
|
ProviderName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Components provide access to YAML file for creating provider components.
|
// Components provide access to YAML file for creating provider components.
|
||||||
@ -36,8 +37,9 @@ func (rc *RepositoryClient) Components() repository.ComponentsClient {
|
|||||||
log.Debugf("Setting up airshipctl provider Components client\n"+
|
log.Debugf("Setting up airshipctl provider Components client\n"+
|
||||||
"Provider type: %s, name: %s\n", rc.ProviderType, rc.ProviderName)
|
"Provider type: %s, name: %s\n", rc.ProviderType, rc.ProviderName)
|
||||||
return &ComponentsClient{
|
return &ComponentsClient{
|
||||||
client: rc.Client.Components(),
|
client: rc.Client.Components(),
|
||||||
providerName: rc.ProviderName,
|
providerName: rc.ProviderName,
|
||||||
providerType: rc.ProviderType,
|
providerType: rc.ProviderType,
|
||||||
|
variableSubstitution: rc.VariableSubstitution,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
package implementations
|
package implementations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
|
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
|
||||||
clusterctlconfig "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
clusterctlconfig "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
||||||
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
|
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/repository"
|
||||||
@ -27,14 +30,153 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestRepositoryClient(t *testing.T) {
|
func TestRepositoryClient(t *testing.T) {
|
||||||
|
airRepoClient := testRepoClient(testRepoOpts{
|
||||||
|
kustRoot: "functions/4",
|
||||||
|
envVars: false,
|
||||||
|
additionalVars: map[string]string{},
|
||||||
|
}, t)
|
||||||
|
// get the components of the repository with empty options, all defaults should work
|
||||||
|
// SkipVariables is to true, to make sure that it is ignored in this implementation, and instead
|
||||||
|
// taken from airship clusterctl provider option, which disables var substitution by default
|
||||||
|
c, err := airRepoClient.Components().Get(repository.ComponentsOptions{SkipVariables: true})
|
||||||
|
require.NoError(t, err)
|
||||||
|
// No errors must be returned since there is are no variables that need to be substituted
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
// Make sure that target namespace is the same as defined by repository implementation bundle
|
||||||
|
assert.Equal(t, "newnamespace", c.TargetNamespace())
|
||||||
|
// Make sure that variables for substitution are actually found
|
||||||
|
require.Len(t, c.Variables(), 1)
|
||||||
|
// make sure that variable name is correct
|
||||||
|
assert.Equal(t, "PROVISIONING_IP", c.Variables()[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMissingVariableRepoClient(t *testing.T) {
|
||||||
|
airRepoClient := testRepoClient(testRepoOpts{
|
||||||
|
kustRoot: "functions/5",
|
||||||
|
envVars: true,
|
||||||
|
additionalVars: map[string]string{},
|
||||||
|
varSubstitution: true,
|
||||||
|
}, t)
|
||||||
|
envVars := map[string]string{
|
||||||
|
"AZURE_SUBSCRIPTION_ID_B64": "c29tZS1iYXNlNjQtSUQtdGV4dAo=",
|
||||||
|
"AZURE_TENANT_ID_B64": "c29tZS1iYXNlNjQtVEVOQU5ULUlELXRleHQK",
|
||||||
|
"AZURE_CLIENT_ID_B64": "c29tZS1iYXNlNjQtQ0xJRU5ULUlELXRleHQK",
|
||||||
|
}
|
||||||
|
for key, val := range envVars {
|
||||||
|
os.Setenv(key, val)
|
||||||
|
defer os.Unsetenv(key)
|
||||||
|
}
|
||||||
|
c, err := airRepoClient.Components().Get(repository.ComponentsOptions{})
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), `value for variables [AZURE_CLIENT_SECRET_B64] is not set`)
|
||||||
|
assert.Nil(t, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvVariableSubstiutionRepoClient(t *testing.T) {
|
||||||
|
airRepoClient := testRepoClient(testRepoOpts{
|
||||||
|
kustRoot: "functions/5",
|
||||||
|
envVars: true,
|
||||||
|
additionalVars: map[string]string{},
|
||||||
|
varSubstitution: true,
|
||||||
|
}, t)
|
||||||
|
envVars := map[string]string{
|
||||||
|
"AZURE_SUBSCRIPTION_ID_B64": "c29tZS1iYXNlNjQtSUQtdGV4dAo=",
|
||||||
|
"AZURE_TENANT_ID_B64": "c29tZS1iYXNlNjQtVEVOQU5ULUlELXRleHQK",
|
||||||
|
"AZURE_CLIENT_ID_B64": "c29tZS1iYXNlNjQtQ0xJRU5ULUlELXRleHQK",
|
||||||
|
"AZURE_CLIENT_SECRET_B64": "c29tZS1iYXNlNjQtQ0xJRU5ULVNFQ1JFVC10ZXh0Cg==",
|
||||||
|
}
|
||||||
|
for key, val := range envVars {
|
||||||
|
os.Setenv(key, val)
|
||||||
|
defer os.Unsetenv(key)
|
||||||
|
}
|
||||||
|
c, err := airRepoClient.Components().Get(repository.ComponentsOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
assert.Len(t, c.Variables(), len(dataKeyMapping()))
|
||||||
|
// find secret containing env variables
|
||||||
|
for _, obj := range c.InstanceObjs() {
|
||||||
|
if obj.GetKind() == "Secret" {
|
||||||
|
cm := &v1.ConfigMap{}
|
||||||
|
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), cm)
|
||||||
|
require.NoError(t, err)
|
||||||
|
for key, expectedVal := range envVars {
|
||||||
|
dataKey, exists := dataKeyMapping()[key]
|
||||||
|
require.True(t, exists)
|
||||||
|
actualVal, exists := cm.Data[dataKey]
|
||||||
|
require.True(t, exists)
|
||||||
|
assert.Equal(t, expectedVal, actualVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test covers a case, where we want some variables to be substituted and some
|
||||||
|
// are not. Clusterctl behavior doesn't allow to skip variable substitution completely
|
||||||
|
// instead if SkipVariables is set to True, it will not throw errors if these variables
|
||||||
|
// are not set in config reader.
|
||||||
|
func TestAdditionalVariableSubstiutionRepoClient(t *testing.T) {
|
||||||
|
vars := map[string]string{
|
||||||
|
"AZURE_SUBSCRIPTION_ID_B64": "c29tZS1iYXNlNjQtSUQtdGV4dAo=",
|
||||||
|
"AZURE_TENANT_ID_B64": "c29tZS1iYXNlNjQtVEVOQU5ULUlELXRleHQK",
|
||||||
|
"AZURE_CLIENT_ID_B64": "c29tZS1iYXNlNjQtQ0xJRU5ULUlELXRleHQK",
|
||||||
|
}
|
||||||
|
notSubstitutedVars := map[string]string{
|
||||||
|
"AZURE_CLIENT_SECRET_B64": "${AZURE_CLIENT_SECRET_B64}",
|
||||||
|
}
|
||||||
|
airRepoClient := testRepoClient(testRepoOpts{
|
||||||
|
kustRoot: "functions/5",
|
||||||
|
envVars: false,
|
||||||
|
additionalVars: vars,
|
||||||
|
// set to false so errors are not thrown when AZURE_CLIENT_SECRET_B64 is not found
|
||||||
|
varSubstitution: false,
|
||||||
|
}, t)
|
||||||
|
c, err := airRepoClient.Components().Get(repository.ComponentsOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, c)
|
||||||
|
assert.Len(t, c.Variables(), len(dataKeyMapping()))
|
||||||
|
// find secret containing env variables
|
||||||
|
for _, obj := range c.InstanceObjs() {
|
||||||
|
if obj.GetKind() == "Secret" {
|
||||||
|
// merge two maps
|
||||||
|
mergedVars := map[string]string{}
|
||||||
|
for k, v := range vars {
|
||||||
|
mergedVars[k] = v
|
||||||
|
}
|
||||||
|
for k, v := range notSubstitutedVars {
|
||||||
|
mergedVars[k] = v
|
||||||
|
}
|
||||||
|
cm := &v1.ConfigMap{}
|
||||||
|
err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.UnstructuredContent(), cm)
|
||||||
|
require.NoError(t, err)
|
||||||
|
for key, expectedVal := range vars {
|
||||||
|
dataKey, exists := dataKeyMapping()[key]
|
||||||
|
require.True(t, exists)
|
||||||
|
actualVal, exists := cm.Data[dataKey]
|
||||||
|
require.True(t, exists)
|
||||||
|
assert.Equal(t, expectedVal, actualVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testRepoOpts struct {
|
||||||
|
kustRoot string
|
||||||
|
envVars bool
|
||||||
|
additionalVars map[string]string
|
||||||
|
varSubstitution bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRepoClient(opts testRepoOpts, t *testing.T) repository.Client {
|
||||||
providerName := "metal3"
|
providerName := "metal3"
|
||||||
providerType := "InfrastructureProvider"
|
providerType := "InfrastructureProvider"
|
||||||
// this version contains a variable that is suppose to be substituted by clusterctl
|
// this version contains a variable that is suppose to be substituted by clusterctl
|
||||||
// and we will test if the variable is found and not substituted
|
// and we will test if the variable is found and not substituted
|
||||||
versions := map[string]string{
|
versions := map[string]string{
|
||||||
"v0.2.3": "functions/4",
|
"v0.2.3": opts.kustRoot,
|
||||||
}
|
}
|
||||||
options := &airshipv1.Clusterctl{
|
cctl := &airshipv1.Clusterctl{
|
||||||
|
AdditionalComponentVariables: opts.additionalVars,
|
||||||
|
EnvVars: opts.envVars,
|
||||||
Providers: []*airshipv1.Provider{
|
Providers: []*airshipv1.Provider{
|
||||||
{
|
{
|
||||||
Name: providerName,
|
Name: providerName,
|
||||||
@ -45,7 +187,7 @@ func TestRepositoryClient(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
// create instance of airship reader interface implementation for clusterctl and inject it
|
// create instance of airship reader interface implementation for clusterctl and inject it
|
||||||
reader, err := NewAirshipReader(options)
|
reader, err := NewAirshipReader(cctl)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, reader)
|
require.NotNil(t, reader)
|
||||||
optionReader := clusterctlconfig.InjectReader(reader)
|
optionReader := clusterctlconfig.InjectReader(reader)
|
||||||
@ -66,19 +208,19 @@ func TestRepositoryClient(t *testing.T) {
|
|||||||
repoClient, err := repository.New(provider, configClient, optionsRepo)
|
repoClient, err := repository.New(provider, configClient, optionsRepo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, repoClient)
|
require.NotNil(t, repoClient)
|
||||||
// create airship implementation of clusterctl repository client
|
return &RepositoryClient{
|
||||||
airRepoClient := RepositoryClient{
|
ProviderName: providerName,
|
||||||
Client: repoClient,
|
ProviderType: providerType,
|
||||||
|
Client: repoClient,
|
||||||
|
VariableSubstitution: opts.varSubstitution,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataKeyMapping() map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"AZURE_SUBSCRIPTION_ID_B64": "subscription-id",
|
||||||
|
"AZURE_TENANT_ID_B64": "tenant-id",
|
||||||
|
"AZURE_CLIENT_ID_B64": "client-id",
|
||||||
|
"AZURE_CLIENT_SECRET_B64": "client-secret",
|
||||||
}
|
}
|
||||||
// get the components of the repository with empty options, all defaults should work
|
|
||||||
c, err := airRepoClient.Components().Get(repository.ComponentsOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
// No errors must be returned since there is are no variables that need to be substituted
|
|
||||||
assert.NotNil(t, c)
|
|
||||||
// Make sure that target namespace is the same as defined by repository implementation bundle
|
|
||||||
assert.Equal(t, "newnamespace", c.TargetNamespace())
|
|
||||||
// Make sure that variables for substitution are actually found
|
|
||||||
require.Len(t, c.Variables(), 1)
|
|
||||||
// make sure that variable name is correct
|
|
||||||
assert.Equal(t, "PROVISIONING_IP", c.Variables()[0])
|
|
||||||
}
|
}
|
||||||
|
29
pkg/clusterctl/implementations/testdata/functions/5/azure-resources.yaml
vendored
Normal file
29
pkg/clusterctl/implementations/testdata/functions/5/azure-resources.yaml
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
## contains a namespace that should be idenitifed by components interface,
|
||||||
|
---
|
||||||
|
apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3
|
||||||
|
kind: Metadata
|
||||||
|
metadata:
|
||||||
|
name: repository-metadata
|
||||||
|
releaseSeries:
|
||||||
|
- major: 0
|
||||||
|
minor: 3
|
||||||
|
contract: v1alpha3
|
||||||
|
- major: 0
|
||||||
|
minor: 2
|
||||||
|
contract: v1alpha2
|
||||||
|
---
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: newnamespace
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: manager-bootstrap-credentials
|
||||||
|
namespace: system
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
subscription-id: ${AZURE_SUBSCRIPTION_ID_B64}
|
||||||
|
tenant-id: ${AZURE_TENANT_ID_B64}
|
||||||
|
client-id: ${AZURE_CLIENT_ID_B64}
|
||||||
|
client-secret: ${AZURE_CLIENT_SECRET_B64}
|
3
pkg/clusterctl/implementations/testdata/functions/5/kustomization.yaml
vendored
Normal file
3
pkg/clusterctl/implementations/testdata/functions/5/kustomization.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Contains variables that should be substituted
|
||||||
|
resources:
|
||||||
|
- azure-resources.yaml
|
Loading…
Reference in New Issue
Block a user