Add reader interface
With this implementation reader is an in memory interface that allows to build clusterctl config based airshipctl documents Relates-To: #200 Closes: #200 Change-Id: If4a5fbd5c8402c958563cdfc939fc579289b0bfb
This commit is contained in:
parent
71b06db819
commit
391525a165
2
go.mod
2
go.mod
@ -23,9 +23,7 @@ require (
|
|||||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c // indirect
|
||||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||||
github.com/spf13/afero v1.2.2
|
|
||||||
github.com/spf13/cobra v0.0.6
|
github.com/spf13/cobra v0.0.6
|
||||||
github.com/spf13/viper v1.6.2
|
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
k8s.io/api v0.17.3
|
k8s.io/api v0.17.3
|
||||||
k8s.io/apiextensions-apiserver v0.17.3
|
k8s.io/apiextensions-apiserver v0.17.3
|
||||||
|
@ -15,20 +15,17 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/afero"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
clusterctlclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client"
|
clusterctlclient "sigs.k8s.io/cluster-api/cmd/clusterctl/client"
|
||||||
clusterctlconfig "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
clusterctlconfig "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
||||||
clog "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
|
clog "sigs.k8s.io/cluster-api/cmd/clusterctl/log"
|
||||||
"sigs.k8s.io/yaml"
|
|
||||||
|
|
||||||
airshipv1 "opendev.org/airship/airshipctl/pkg/clusterctl/api/v1alpha1"
|
airshipv1 "opendev.org/airship/airshipctl/pkg/clusterctl/api/v1alpha1"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/clusterctl/implementations"
|
||||||
"opendev.org/airship/airshipctl/pkg/log"
|
"opendev.org/airship/airshipctl/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// path to file on in memory file system
|
// path to file on in memory file system
|
||||||
confFilePath = "/air-clusterctl.yaml"
|
|
||||||
dummyComponentPath = "/dummy/path/v0.3.2/components.yaml"
|
dummyComponentPath = "/dummy/path/v0.3.2/components.yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -78,38 +75,20 @@ func (c *Client) Init(kubeconfigPath string) error {
|
|||||||
|
|
||||||
// newConfig returns clusterctl config client
|
// newConfig returns clusterctl config client
|
||||||
func newConfig(options *airshipv1.Clusterctl) (clusterctlconfig.Client, error) {
|
func newConfig(options *airshipv1.Clusterctl) (clusterctlconfig.Client, error) {
|
||||||
fs := afero.NewMemMapFs()
|
|
||||||
b := []map[string]string{}
|
|
||||||
for _, provider := range options.Providers {
|
for _, provider := range options.Providers {
|
||||||
p := map[string]string{
|
|
||||||
"name": provider.Name,
|
|
||||||
"type": provider.Type,
|
|
||||||
"url": provider.URL,
|
|
||||||
}
|
|
||||||
// this is a workaround as cluserctl validates if URL is empty, even though it is not
|
// this is a workaround as cluserctl validates if URL is empty, even though it is not
|
||||||
// used anywhere outside repository factory which we override
|
// used anywhere outside repository factory which we override
|
||||||
// TODO (kkalynovskyi) we need to create issue for this in clusterctl, and remove URL
|
// TODO (kkalynovskyi) we need to create issue for this in clusterctl, and remove URL
|
||||||
// validation and move it to be an error during repository interface initialization
|
// validation and move it to be an error during repository interface initialization
|
||||||
if !provider.IsClusterctlRepository {
|
if !provider.IsClusterctlRepository {
|
||||||
p["url"] = dummyComponentPath
|
provider.URL = dummyComponentPath
|
||||||
}
|
}
|
||||||
b = append(b, p)
|
|
||||||
}
|
}
|
||||||
cconf := map[string][]map[string]string{
|
reader, err := implementations.NewAirshipReader(options)
|
||||||
"providers": b,
|
|
||||||
}
|
|
||||||
data, err := yaml.Marshal(cconf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = afero.WriteFile(fs, confFilePath, data, 0600)
|
return clusterctlconfig.New("", clusterctlconfig.InjectReader(reader))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Set filesystem to global viper object, to make sure, that clusterctl config is read from
|
|
||||||
// memory filesystem instead of real one.
|
|
||||||
viper.SetFs(fs)
|
|
||||||
return clusterctlconfig.New(confFilePath)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClusterctlClient(root string, options *airshipv1.Clusterctl) (clusterctlclient.Client, error) {
|
func newClusterctlClient(root string, options *airshipv1.Clusterctl) (clusterctlclient.Client, error) {
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
https://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 implementations
|
package implementations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -21,3 +35,12 @@ type ErrNoVersionsAvailable struct {
|
|||||||
func (e ErrNoVersionsAvailable) Error() string {
|
func (e ErrNoVersionsAvailable) Error() string {
|
||||||
return fmt.Sprintf(`version map is empty or not defined, %v`, e.Versions)
|
return fmt.Sprintf(`version map is empty or not defined, %v`, e.Versions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrValueForVariableNotSet is returned when version map is empty or not defined
|
||||||
|
type ErrValueForVariableNotSet struct {
|
||||||
|
Variable string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrValueForVariableNotSet) Error() string {
|
||||||
|
return fmt.Sprintf("value for variable %q is not set", e.Variable)
|
||||||
|
}
|
||||||
|
97
pkg/clusterctl/implementations/reader.go
Normal file
97
pkg/clusterctl/implementations/reader.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
https://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 implementations
|
||||||
|
|
||||||
|
import (
|
||||||
|
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
|
||||||
|
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
|
||||||
|
airshipv1 "opendev.org/airship/airshipctl/pkg/clusterctl/api/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ config.Reader = &AirshipReader{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TODO this must come as as ProviderConfigKey from clusterctl/client/config pkg
|
||||||
|
// see https://github.com/kubernetes-sigs/cluster-api/blob/master/cmd/clusterctl/client/config/imagemeta_client.go#L27
|
||||||
|
imagesConfigKey = "images"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AirshipReader provides a reader implementation backed by a map
|
||||||
|
type AirshipReader struct {
|
||||||
|
variables map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// configProvider is a mirror of config.Provider, re-implemented here in order to
|
||||||
|
// avoid circular dependencies between pkg/client/config and pkg/internal/test
|
||||||
|
type configProvider struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
|
Type clusterctlv1.ProviderType `json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init implementation of clusterctl reader interface
|
||||||
|
// This is dummy method that is must be present to implement Reader interface
|
||||||
|
func (f *AirshipReader) Init(config string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get implementation of clusterctl reader interface
|
||||||
|
func (f *AirshipReader) Get(key string) (string, error) {
|
||||||
|
// TODO handle empty keys
|
||||||
|
if val, ok := f.variables[key]; ok {
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
return "", ErrValueForVariableNotSet{Variable: key}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set implementation of clusterctl reader interface
|
||||||
|
func (f *AirshipReader) Set(key, value string) {
|
||||||
|
// TODO handle empty keys
|
||||||
|
f.variables[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalKey implementation of clusterctl reader interface
|
||||||
|
func (f *AirshipReader) UnmarshalKey(key string, rawval interface{}) error {
|
||||||
|
data, err := f.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return yaml.Unmarshal([]byte(data), rawval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAirshipReader returns airship implementation of clusterctl reader interface
|
||||||
|
func NewAirshipReader(options *airshipv1.Clusterctl) (*AirshipReader, error) {
|
||||||
|
variables := map[string]string{}
|
||||||
|
providers := []configProvider{}
|
||||||
|
for _, prov := range options.Providers {
|
||||||
|
appendProvider := configProvider{
|
||||||
|
Name: prov.Name,
|
||||||
|
Type: clusterctlv1.ProviderType(prov.Type),
|
||||||
|
URL: prov.URL,
|
||||||
|
}
|
||||||
|
providers = append(providers, appendProvider)
|
||||||
|
}
|
||||||
|
b, err := yaml.Marshal(providers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Add providers to config
|
||||||
|
variables[config.ProvidersConfigKey] = string(b)
|
||||||
|
// Add empty image configuration to config
|
||||||
|
variables[imagesConfigKey] = ""
|
||||||
|
return &AirshipReader{variables: variables}, nil
|
||||||
|
}
|
271
pkg/clusterctl/implementations/reader_test.go
Normal file
271
pkg/clusterctl/implementations/reader_test.go
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
https://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 implementations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
|
||||||
|
"sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
|
||||||
|
|
||||||
|
airshipv1 "opendev.org/airship/airshipctl/pkg/clusterctl/api/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeValidOptions() *airshipv1.Clusterctl {
|
||||||
|
return &airshipv1.Clusterctl{
|
||||||
|
Providers: []*airshipv1.Provider{
|
||||||
|
{
|
||||||
|
Name: "metal3",
|
||||||
|
Type: "InfrastructureProvider",
|
||||||
|
Versions: map[string]string{
|
||||||
|
"v0.3.1": "manifests/function/capm3/v0.3.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "kubeadm",
|
||||||
|
Type: "BootstrapProvider",
|
||||||
|
Versions: map[string]string{
|
||||||
|
"v0.3.3": "manifests/function/cabpk/v0.3.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "cluster-api",
|
||||||
|
Type: "InfrastructureProvider",
|
||||||
|
Versions: map[string]string{
|
||||||
|
"v0.3.3": "manifests/function/capi/v0.3.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "kubeadm",
|
||||||
|
Type: "ControlPlaneProvider",
|
||||||
|
Versions: map[string]string{
|
||||||
|
"v0.3.3": "manifests/function/cacpk/v0.3.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewReader(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
options *airshipv1.Clusterctl
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// make sure we get no panic here
|
||||||
|
name: "pass empty options",
|
||||||
|
options: &airshipv1.Clusterctl{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pass airshipctl valid config",
|
||||||
|
options: makeValidOptions(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
options := tt.options
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
reader, err := NewAirshipReader(options)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.NotNil(t, reader)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
options *airshipv1.Clusterctl
|
||||||
|
key string
|
||||||
|
expectedErr error
|
||||||
|
expectedResult string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// make sure we get no panic here
|
||||||
|
name: "pass empty options",
|
||||||
|
options: &airshipv1.Clusterctl{},
|
||||||
|
key: "FOO",
|
||||||
|
expectedErr: ErrValueForVariableNotSet{Variable: "FOO"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pass airshipctl valid config",
|
||||||
|
options: makeValidOptions(),
|
||||||
|
key: "providers",
|
||||||
|
expectedErr: nil,
|
||||||
|
expectedResult: `- name: metal3
|
||||||
|
type: InfrastructureProvider
|
||||||
|
- name: kubeadm
|
||||||
|
type: BootstrapProvider
|
||||||
|
- name: cluster-api
|
||||||
|
type: InfrastructureProvider
|
||||||
|
- name: kubeadm
|
||||||
|
type: ControlPlaneProvider
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
reader, err := NewAirshipReader(tt.options)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, reader)
|
||||||
|
value, err := reader.Get(tt.key)
|
||||||
|
assert.Equal(t, tt.expectedErr, err)
|
||||||
|
assert.Equal(t, tt.expectedResult, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetGet(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
setKey string
|
||||||
|
setGetValue string
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// should return empty string
|
||||||
|
name: "set simple key",
|
||||||
|
setKey: "FOO",
|
||||||
|
expectedErr: nil,
|
||||||
|
setGetValue: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "set providers",
|
||||||
|
setKey: "providers",
|
||||||
|
expectedErr: nil,
|
||||||
|
setGetValue: `- name: metal3
|
||||||
|
type: InfrastructureProvider
|
||||||
|
- name: kubeadm
|
||||||
|
type: BootstrapProvider
|
||||||
|
- name: cluster-api
|
||||||
|
type: InfrastructureProvider
|
||||||
|
- name: kubeadm
|
||||||
|
type: ControlPlaneProvider
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// set empty
|
||||||
|
name: "empty key",
|
||||||
|
setKey: "",
|
||||||
|
setGetValue: "some key",
|
||||||
|
expectedErr: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
reader, err := NewAirshipReader(&airshipv1.Clusterctl{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, reader)
|
||||||
|
reader.Set(tt.setKey, tt.setGetValue)
|
||||||
|
result, err := reader.Get(tt.setKey)
|
||||||
|
require.Equal(t, tt.expectedErr, err)
|
||||||
|
assert.Equal(t, tt.setGetValue, result)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test verifies that options provider returns
|
||||||
|
func TestUnmarshalProviders(t *testing.T) {
|
||||||
|
options := &airshipv1.Clusterctl{
|
||||||
|
Providers: []*airshipv1.Provider{
|
||||||
|
{
|
||||||
|
Name: config.Metal3ProviderName,
|
||||||
|
Type: string(clusterctlv1.InfrastructureProviderType),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: config.KubeadmBootstrapProviderName,
|
||||||
|
Type: string(clusterctlv1.BootstrapProviderType),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: config.ClusterAPIProviderName,
|
||||||
|
Type: string(clusterctlv1.CoreProviderType),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: config.KubeadmControlPlaneProviderName,
|
||||||
|
Type: string(clusterctlv1.ControlPlaneProviderType),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
providers := []configProvider{}
|
||||||
|
reader, err := NewAirshipReader(options)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, reader)
|
||||||
|
// check if we can unmarshal provider key into correct struct
|
||||||
|
err = reader.UnmarshalKey(config.ProvidersConfigKey, &providers)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, providers, 4)
|
||||||
|
for _, actualProvider := range providers {
|
||||||
|
assert.NotNil(t, options.Provider(actualProvider.Name, actualProvider.Type))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshal(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expectErr bool
|
||||||
|
variables map[string]string
|
||||||
|
getKey string
|
||||||
|
unmarshal interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "unmarshal into nil",
|
||||||
|
getKey: "Foo",
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value doesn't exist",
|
||||||
|
getKey: "Foo",
|
||||||
|
variables: map[string]string{},
|
||||||
|
unmarshal: []configProvider{},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value doesn't exist",
|
||||||
|
getKey: "foo",
|
||||||
|
expectErr: false,
|
||||||
|
variables: map[string]string{
|
||||||
|
"foo": "foo: bar",
|
||||||
|
},
|
||||||
|
unmarshal: &struct {
|
||||||
|
Foo string `json:"foo,omitempty"`
|
||||||
|
}{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
reader, err := NewAirshipReader(&airshipv1.Clusterctl{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, reader)
|
||||||
|
reader.variables = tt.variables
|
||||||
|
if tt.expectErr {
|
||||||
|
assert.Error(t, reader.UnmarshalKey(tt.getKey, tt.unmarshal))
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, reader.UnmarshalKey(tt.getKey, tt.unmarshal))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test is simply for test coverage of the Reader interface
|
||||||
|
func TestInit(t *testing.T) {
|
||||||
|
reader, err := NewAirshipReader(&airshipv1.Clusterctl{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, reader)
|
||||||
|
assert.NoError(t, reader.Init("anything"))
|
||||||
|
}
|
@ -1,3 +1,17 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
https://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 implementations
|
package implementations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -60,12 +74,14 @@ func (r *Repository) GetFile(version string, filePath string) ([]byte, error) {
|
|||||||
// default should be latest
|
// default should be latest
|
||||||
version = r.defaultVersion
|
version = r.defaultVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
path, ok := r.versions[version]
|
path, ok := r.versions[version]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrVersionNotDefined{Version: version}
|
return nil, ErrVersionNotDefined{Version: version}
|
||||||
}
|
}
|
||||||
|
kustomizePath := filepath.Join(r.root, path)
|
||||||
bundle, err := document.NewBundleByPath(filepath.Join(r.root, path))
|
log.Debugf("Building cluster-api provider component documents from kustomize path at %s", kustomizePath)
|
||||||
|
bundle, err := document.NewBundleByPath(kustomizePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -101,8 +117,9 @@ func NewRepository(root string, versions map[string]string) (repository.Reposito
|
|||||||
availableSemVersion, err := version.ParseSemantic(ver)
|
availableSemVersion, err := version.ParseSemantic(ver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// ignore and delete version if we can't parse it.
|
// ignore and delete version if we can't parse it.
|
||||||
log.Debugf(`Invalid version %s in repository versions map %q, ignoring it. Version must obey the syntax,
|
fmtMsg := "Invalid version %s in repository versions map %q, ignoring it. " +
|
||||||
semantics of the "Semantic Versioning" specification (http://semver.org/)`, ver, versions)
|
"Version must obey the the Semantic Versioning specification (http://semver.org/)"
|
||||||
|
log.Debugf(fmtMsg, ver, versions)
|
||||||
// delete the version so actual version list is clean
|
// delete the version so actual version list is clean
|
||||||
delete(versions, ver)
|
delete(versions, ver)
|
||||||
continue
|
continue
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
|
||||||
|
https://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 implementations_test
|
package implementations_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
Loading…
Reference in New Issue
Block a user