Add clustermap object and interface
This commit adds cluster map api object, cluster map interface and it's implementation built on top of cluster map api object. Important note: ClusterMap interface needs a method to identify namespace of the cluster, it can't be a part of api object, because real source for cluster namespace is cluster object from cluster-api upstream lib. This will need further design discussion on how we will find cluster-api kind: Cluster object in our manifests. For now, there is dummy "default" namespace being used Change-Id: I8175f54abbe77331f0c87c0bde50857ee5c0eb1d
This commit is contained in:
parent
233bbda0e0
commit
0a7661ab7c
@ -25,7 +25,7 @@ type ClusterMap struct {
|
|||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
// Keys in this map MUST correspond to context names in kubeconfigs provided
|
// Keys in this map MUST correspond to context names in kubeconfigs provided
|
||||||
Map map[string]*Cluster
|
Map map[string]*Cluster `json:"map,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cluster uniquely identifies a cluster and its parent cluster
|
// Cluster uniquely identifies a cluster and its parent cluster
|
||||||
|
@ -38,6 +38,8 @@ type Builder struct {
|
|||||||
OutputMetadataFileName string `json:"outputMetadataFileName,omitempty"`
|
OutputMetadataFileName string `json:"outputMetadataFileName,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
// ImageConfiguration structure is inherited from apimachinery TypeMeta and ObjectMeta and is a top level
|
// ImageConfiguration structure is inherited from apimachinery TypeMeta and ObjectMeta and is a top level
|
||||||
// configuration structure for building image
|
// configuration structure for building image
|
||||||
type ImageConfiguration struct {
|
type ImageConfiguration struct {
|
||||||
|
@ -18,6 +18,8 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
// RemoteDirectConfiguration structure is inherited from apimachinery TypeMeta and ObjectMeta structures
|
// RemoteDirectConfiguration structure is inherited from apimachinery TypeMeta and ObjectMeta structures
|
||||||
// and defines parameters used to bootstrap the ephemeral node during the remote direct
|
// and defines parameters used to bootstrap the ephemeral node during the remote direct
|
||||||
type RemoteDirectConfiguration struct {
|
type RemoteDirectConfiguration struct {
|
||||||
|
@ -56,6 +56,21 @@ func (in *ApplyWaitOptions) DeepCopy() *ApplyWaitOptions {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Builder) DeepCopyInto(out *Builder) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Builder.
|
||||||
|
func (in *Builder) DeepCopy() *Builder {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Builder)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Cluster) DeepCopyInto(out *Cluster) {
|
func (in *Cluster) DeepCopyInto(out *Cluster) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -164,6 +179,56 @@ func (in *Clusterctl) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Container) DeepCopyInto(out *Container) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Container.
|
||||||
|
func (in *Container) DeepCopy() *Container {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Container)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImageConfiguration) DeepCopyInto(out *ImageConfiguration) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
if in.Container != nil {
|
||||||
|
in, out := &in.Container, &out.Container
|
||||||
|
*out = new(Container)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.Builder != nil {
|
||||||
|
in, out := &in.Builder, &out.Builder
|
||||||
|
*out = new(Builder)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageConfiguration.
|
||||||
|
func (in *ImageConfiguration) DeepCopy() *ImageConfiguration {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImageConfiguration)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||||
|
func (in *ImageConfiguration) DeepCopyObject() runtime.Object {
|
||||||
|
if c := in.DeepCopy(); c != nil {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *InitOptions) DeepCopyInto(out *InitOptions) {
|
func (in *InitOptions) DeepCopyInto(out *InitOptions) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -401,63 +466,6 @@ func (in *Provider) DeepCopy() *Provider {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *ImageConfiguration) DeepCopyInto(out *ImageConfiguration) {
|
|
||||||
*out = *in
|
|
||||||
out.TypeMeta = in.TypeMeta
|
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
|
||||||
in.Container.DeepCopyInto(out.Container)
|
|
||||||
in.Builder.DeepCopyInto(out.Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Phase.
|
|
||||||
func (in *ImageConfiguration) DeepCopy() *ImageConfiguration {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(ImageConfiguration)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
|
||||||
func (in *ImageConfiguration) DeepCopyObject() runtime.Object {
|
|
||||||
if c := in.DeepCopy(); c != nil {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *Container) DeepCopyInto(out *Container) {
|
|
||||||
*out = *in
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhaseConfig.
|
|
||||||
func (in *Container) DeepCopy() *Container {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(Container)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *Builder) DeepCopyInto(out *Builder) {
|
|
||||||
*out = *in
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PhaseConfig.
|
|
||||||
func (in *Builder) DeepCopy() *Builder {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(Builder)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *RemoteDirectConfiguration) DeepCopyInto(out *RemoteDirectConfiguration) {
|
func (in *RemoteDirectConfiguration) DeepCopyInto(out *RemoteDirectConfiguration) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -465,7 +473,7 @@ func (in *RemoteDirectConfiguration) DeepCopyInto(out *RemoteDirectConfiguration
|
|||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Phase.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteDirectConfiguration.
|
||||||
func (in *RemoteDirectConfiguration) DeepCopy() *RemoteDirectConfiguration {
|
func (in *RemoteDirectConfiguration) DeepCopy() *RemoteDirectConfiguration {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return nil
|
return nil
|
||||||
|
41
pkg/cluster/clustermap/errors.go
Normal file
41
pkg/cluster/clustermap/errors.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
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 clustermap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrParentNotFound returned when requested cluster is not defined or doesn't have a parent
|
||||||
|
type ErrParentNotFound struct {
|
||||||
|
Child string
|
||||||
|
Map *v1alpha1.ClusterMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrParentNotFound) Error() string {
|
||||||
|
return fmt.Sprintf("failed to find a parent for cluster %s in cluster map %v", e.Child, e.Map)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrClusterNotInMap returned when requested cluster is not defined in cluster map
|
||||||
|
type ErrClusterNotInMap struct {
|
||||||
|
Child string
|
||||||
|
Map *v1alpha1.ClusterMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrClusterNotInMap) Error() string {
|
||||||
|
return fmt.Sprintf("cluster %s is not defined in in cluster map %v", e.Child, e.Map)
|
||||||
|
}
|
79
pkg/cluster/clustermap/map.go
Normal file
79
pkg/cluster/clustermap/map.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
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 clustermap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClusterMap interface that allows to list all clusters, find its parent, namespace,
|
||||||
|
// check if dynamic kubeconfig is enabled.
|
||||||
|
// TODO use typed cluster names
|
||||||
|
type ClusterMap interface {
|
||||||
|
ParentCluster(string) (string, error)
|
||||||
|
AllClusters() []string
|
||||||
|
DynamicKubeConfig(string) bool
|
||||||
|
ClusterNamespace(string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// clusterMap allows to view clusters and relationship between them
|
||||||
|
type clusterMap struct {
|
||||||
|
apiMap *v1alpha1.ClusterMap
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ ClusterMap = clusterMap{}
|
||||||
|
|
||||||
|
// NewClusterMap returns ClusterMap interface
|
||||||
|
func NewClusterMap(cMap *v1alpha1.ClusterMap) ClusterMap {
|
||||||
|
return clusterMap{apiMap: cMap}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParentCluster finds a parent cluster for provided child
|
||||||
|
func (cm clusterMap) ParentCluster(child string) (string, error) {
|
||||||
|
currentCluster, exists := cm.apiMap.Map[child]
|
||||||
|
if !exists {
|
||||||
|
return "", ErrClusterNotInMap{Child: child, Map: cm.apiMap}
|
||||||
|
}
|
||||||
|
if currentCluster.Parent == "" {
|
||||||
|
return "", ErrParentNotFound{Child: child, Map: cm.apiMap}
|
||||||
|
}
|
||||||
|
return currentCluster.Parent, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DynamicKubeConfig check if dynamic kubeconfig is enabled for the child cluster
|
||||||
|
func (cm clusterMap) DynamicKubeConfig(child string) bool {
|
||||||
|
childCluster, exist := cm.apiMap.Map[child]
|
||||||
|
if !exist {
|
||||||
|
log.Debugf("cluster %s is not defined in cluster map %v", child, cm.apiMap)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return childCluster.DynamicKubeConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllClusters returns all clusters in a map
|
||||||
|
func (cm clusterMap) AllClusters() []string {
|
||||||
|
clusters := []string{}
|
||||||
|
for k := range cm.apiMap.Map {
|
||||||
|
clusters = append(clusters, k)
|
||||||
|
}
|
||||||
|
return clusters
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClusterNamespace a namespace for given cluster
|
||||||
|
// TODO implement how to get namespace for cluster
|
||||||
|
func (cm clusterMap) ClusterNamespace(clusterName string) (string, error) {
|
||||||
|
return "default", nil
|
||||||
|
}
|
90
pkg/cluster/clustermap/map_test.go
Normal file
90
pkg/cluster/clustermap/map_test.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
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 clustermap_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClusterMap(t *testing.T) {
|
||||||
|
targetCluster := "target"
|
||||||
|
ephemeraCluster := "ephemeral"
|
||||||
|
workloadCluster := "workload"
|
||||||
|
workloadClusterNoParent := "workload without parent"
|
||||||
|
apiMap := &v1alpha1.ClusterMap{
|
||||||
|
Map: map[string]*v1alpha1.Cluster{
|
||||||
|
targetCluster: {
|
||||||
|
Parent: ephemeraCluster,
|
||||||
|
DynamicKubeConfig: false,
|
||||||
|
},
|
||||||
|
ephemeraCluster: {},
|
||||||
|
workloadCluster: {
|
||||||
|
Parent: targetCluster,
|
||||||
|
DynamicKubeConfig: true,
|
||||||
|
},
|
||||||
|
workloadClusterNoParent: {
|
||||||
|
DynamicKubeConfig: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cMap := clustermap.NewClusterMap(apiMap)
|
||||||
|
require.NotNil(t, cMap)
|
||||||
|
|
||||||
|
t.Run("ephemeral parent", func(t *testing.T) {
|
||||||
|
parent, err := cMap.ParentCluster(targetCluster)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, ephemeraCluster, parent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no cluster found", func(t *testing.T) {
|
||||||
|
parent, err := cMap.ParentCluster("does not exist")
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "", parent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("not dynamic kubeconf target", func(t *testing.T) {
|
||||||
|
dynamic := cMap.DynamicKubeConfig(targetCluster)
|
||||||
|
assert.False(t, dynamic)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("dynamic kubeconf workload", func(t *testing.T) {
|
||||||
|
dynamic := cMap.DynamicKubeConfig(workloadCluster)
|
||||||
|
assert.True(t, dynamic)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("target parent", func(t *testing.T) {
|
||||||
|
parent, err := cMap.ParentCluster(workloadCluster)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, targetCluster, parent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("ephemeral no parent", func(t *testing.T) {
|
||||||
|
parent, err := cMap.ParentCluster(ephemeraCluster)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "", parent)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("all clusters", func(t *testing.T) {
|
||||||
|
clusters := cMap.AllClusters()
|
||||||
|
assert.Len(t, clusters, 4)
|
||||||
|
})
|
||||||
|
}
|
@ -190,7 +190,7 @@ func TestExecutorRun(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ch := make(chan events.Event)
|
ch := make(chan events.Event)
|
||||||
go executor.Run(ch, ifc.RunOptions{Debug: true, DryRun: true})
|
go executor.Run(ch, ifc.RunOptions{DryRun: true})
|
||||||
var actualEvt []events.Event
|
var actualEvt []events.Event
|
||||||
for evt := range ch {
|
for evt := range ch {
|
||||||
actualEvt = append(actualEvt, evt)
|
actualEvt = append(actualEvt, evt)
|
||||||
|
@ -17,11 +17,10 @@ package kubeconfig
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/document"
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
"opendev.org/airship/airshipctl/pkg/errors"
|
"opendev.org/airship/airshipctl/pkg/errors"
|
||||||
"opendev.org/airship/airshipctl/pkg/log"
|
|
||||||
"opendev.org/airship/airshipctl/pkg/util"
|
"opendev.org/airship/airshipctl/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -41,7 +40,7 @@ type Builder struct {
|
|||||||
clusterName string
|
clusterName string
|
||||||
root string
|
root string
|
||||||
|
|
||||||
clusterMap *v1alpha1.ClusterMap
|
clusterMap clustermap.ClusterMap
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithPath allows to set path to prexisting kubeconfig
|
// WithPath allows to set path to prexisting kubeconfig
|
||||||
@ -57,7 +56,7 @@ func (b *Builder) WithBundle(bundlePath string) *Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithClusterMap allows to set a parent cluster, that can be used to extract kubeconfig for target cluster
|
// WithClusterMap allows to set a parent cluster, that can be used to extract kubeconfig for target cluster
|
||||||
func (b *Builder) WithClusterMap(cMap *v1alpha1.ClusterMap) *Builder {
|
func (b *Builder) WithClusterMap(cMap clustermap.ClusterMap) *Builder {
|
||||||
b.clusterMap = cMap
|
b.clusterMap = cMap
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
@ -101,16 +100,5 @@ func (b *Builder) fromParent() bool {
|
|||||||
if b.clusterMap == nil {
|
if b.clusterMap == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
currentCluster, exists := b.clusterMap.Map[b.clusterName]
|
return b.clusterMap.DynamicKubeConfig(b.clusterName)
|
||||||
if !exists {
|
|
||||||
log.Debugf("cluster %s is not defined in cluster map %v", b.clusterName, b.clusterMap)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Check if DynamicKubeConfig is enabled, if so that means, we should get kubeconfig
|
|
||||||
// for this cluster from its parent
|
|
||||||
if currentCluster.Parent == "" || !currentCluster.DynamicKubeConfig {
|
|
||||||
log.Debugf("dynamic kubeconfig or parent cluster is not set for cluster %s", b.clusterName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
|
||||||
"opendev.org/airship/airshipctl/pkg/util"
|
"opendev.org/airship/airshipctl/pkg/util"
|
||||||
@ -66,7 +67,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
builder := kubeconfig.NewBuilder().
|
builder := kubeconfig.NewBuilder().
|
||||||
WithClusterMap(clusterMap).
|
WithClusterMap(clustermap.NewClusterMap(clusterMap)).
|
||||||
WithClusterName(childCluster)
|
WithClusterName(childCluster)
|
||||||
kube := builder.Build()
|
kube := builder.Build()
|
||||||
// This should not be implemented yet, and we need to check that we are getting there
|
// This should not be implemented yet, and we need to check that we are getting there
|
||||||
@ -81,7 +82,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
t.Run("No current cluster, fall to default", func(t *testing.T) {
|
t.Run("No current cluster, fall to default", func(t *testing.T) {
|
||||||
clusterMap := &v1alpha1.ClusterMap{}
|
clusterMap := &v1alpha1.ClusterMap{}
|
||||||
builder := kubeconfig.NewBuilder().
|
builder := kubeconfig.NewBuilder().
|
||||||
WithClusterMap(clusterMap).
|
WithClusterMap(clustermap.NewClusterMap(clusterMap)).
|
||||||
WithClusterName("some-cluster")
|
WithClusterName("some-cluster")
|
||||||
kube := builder.Build()
|
kube := builder.Build()
|
||||||
// We should get a default value for cluster since we don't have some-cluster set
|
// We should get a default value for cluster since we don't have some-cluster set
|
||||||
@ -92,7 +93,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
assert.Equal(t, path, actualPath)
|
assert.Equal(t, path, actualPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("No parent cluster is defined, fall to default", func(t *testing.T) {
|
t.Run("Dynamic, but no parent", func(t *testing.T) {
|
||||||
childCluster := "child"
|
childCluster := "child"
|
||||||
clusterMap := &v1alpha1.ClusterMap{
|
clusterMap := &v1alpha1.ClusterMap{
|
||||||
Map: map[string]*v1alpha1.Cluster{
|
Map: map[string]*v1alpha1.Cluster{
|
||||||
@ -102,15 +103,15 @@ func TestBuilder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
builder := kubeconfig.NewBuilder().
|
builder := kubeconfig.NewBuilder().
|
||||||
WithClusterMap(clusterMap).
|
WithClusterMap(clustermap.NewClusterMap(clusterMap)).
|
||||||
WithClusterName(childCluster)
|
WithClusterName(childCluster)
|
||||||
kube := builder.Build()
|
kube := builder.Build()
|
||||||
// We should get a default value for cluster, as we can't find parent cluster
|
// We should get a default value for cluster, as we can't find parent cluster
|
||||||
actualPath, cleanup, err := kube.GetFile()
|
filePath, cleanup, err := kube.GetFile()
|
||||||
defer cleanup()
|
require.Error(t, err)
|
||||||
require.NoError(t, err)
|
require.Contains(t, err.Error(), "not implemented")
|
||||||
path := filepath.Join(util.UserHomeDir(), config.AirshipConfigDir, kubeconfig.KubeconfigDefaultFileName)
|
assert.Equal(t, "", filePath)
|
||||||
assert.Equal(t, path, actualPath)
|
require.Nil(t, cleanup)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Default source", func(t *testing.T) {
|
t.Run("Default source", func(t *testing.T) {
|
||||||
@ -119,8 +120,8 @@ func TestBuilder(t *testing.T) {
|
|||||||
// When ClusterMap is specified, but it doesn't have cluster-name defined, and no
|
// When ClusterMap is specified, but it doesn't have cluster-name defined, and no
|
||||||
// other sources provided,
|
// other sources provided,
|
||||||
actualPath, cleanup, err := kube.GetFile()
|
actualPath, cleanup, err := kube.GetFile()
|
||||||
defer cleanup()
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
defer cleanup()
|
||||||
path := filepath.Join(util.UserHomeDir(), config.AirshipConfigDir, kubeconfig.KubeconfigDefaultFileName)
|
path := filepath.Join(util.UserHomeDir(), config.AirshipConfigDir, kubeconfig.KubeconfigDefaultFileName)
|
||||||
assert.Equal(t, path, actualPath)
|
assert.Equal(t, path, actualPath)
|
||||||
})
|
})
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/document"
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
"opendev.org/airship/airshipctl/pkg/events"
|
"opendev.org/airship/airshipctl/pkg/events"
|
||||||
@ -56,7 +56,7 @@ type ExecutorConfig struct {
|
|||||||
PhaseName string
|
PhaseName string
|
||||||
ClusterName string
|
ClusterName string
|
||||||
|
|
||||||
ClusterMap *v1alpha1.ClusterMap
|
ClusterMap clustermap.ClusterMap
|
||||||
ExecutorDocument document.Document
|
ExecutorDocument document.Document
|
||||||
ExecutorBundle document.Bundle
|
ExecutorBundle document.Bundle
|
||||||
AirshipConfig *config.Config
|
AirshipConfig *config.Config
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
|
||||||
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||||
|
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||||
clusterctl "opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
clusterctl "opendev.org/airship/airshipctl/pkg/clusterctl/client"
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/document"
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
@ -106,7 +107,7 @@ func (p *Cmd) GetPhase(name string) (*airshipv1.Phase, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetClusterMap returns cluster map object
|
// GetClusterMap returns cluster map object
|
||||||
func (p *Cmd) GetClusterMap() (*airshipv1.ClusterMap, error) {
|
func (p *Cmd) GetClusterMap() (clustermap.ClusterMap, error) {
|
||||||
bundle, err := p.getBundle()
|
bundle, err := p.getBundle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -124,7 +125,7 @@ func (p *Cmd) GetClusterMap() (*airshipv1.ClusterMap, error) {
|
|||||||
if err = doc.ToAPIObject(clusterMap, airshipv1.Scheme); err != nil {
|
if err = doc.ToAPIObject(clusterMap, airshipv1.Scheme); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return clusterMap, nil
|
return clustermap.NewClusterMap(clusterMap), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExecutor referenced in a phase configuration
|
// GetExecutor referenced in a phase configuration
|
||||||
|
2
pkg/phase/testdata/broken_metadata.yaml
vendored
Normal file
2
pkg/phase/testdata/broken_metadata.yaml
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
phase:
|
||||||
|
path: "doesnot-exist"
|
@ -2,7 +2,7 @@ apiVersion: airshipit.org/v1alpha1
|
|||||||
kind: ClusterMap
|
kind: ClusterMap
|
||||||
metadata:
|
metadata:
|
||||||
name: clusterctl-v1
|
name: clusterctl-v1
|
||||||
plan:
|
map:
|
||||||
target:
|
target:
|
||||||
parent: ephemeral
|
parent: ephemeral
|
||||||
dynamicKubeConf: false
|
dynamicKubeConf: false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user