Merge "Use site-wide kubeconfig only on demand"

This commit is contained in:
Zuul 2021-05-18 19:06:09 +00:00 committed by Gerrit Code Review
commit e38f4fbf4c
8 changed files with 37 additions and 5 deletions

View File

@ -126,6 +126,7 @@ metadata:
name: clusterctl-move name: clusterctl-move
clusterName: target-cluster clusterName: target-cluster
config: config:
siteWideKubeconfig: true
executorRef: executorRef:
apiVersion: airshipit.org/v1alpha1 apiVersion: airshipit.org/v1alpha1
kind: Clusterctl kind: Clusterctl

View File

@ -32,6 +32,7 @@ type Phase struct {
// phase runner object which should contain runner configuration // phase runner object which should contain runner configuration
type PhaseConfig struct { type PhaseConfig struct {
ExecutorRef *corev1.ObjectReference `json:"executorRef"` ExecutorRef *corev1.ObjectReference `json:"executorRef"`
SiteWideKubeconfig bool `json:"siteWideKubeconfig,omitempty"`
DocumentEntryPoint string `json:"documentEntryPoint"` DocumentEntryPoint string `json:"documentEntryPoint"`
} }

View File

@ -83,12 +83,18 @@ func (cmd *GetKubeconfigCommand) RunE(cfgFactory config.Factory, writer io.Write
return err return err
} }
var siteWide bool
if cmd.ClusterName == "" {
siteWide = true
}
kubeconf := kubeconfig.NewBuilder(). kubeconf := kubeconfig.NewBuilder().
WithBundle(helper.PhaseConfigBundle()). WithBundle(helper.PhaseConfigBundle()).
WithClusterctlClient(client). WithClusterctlClient(client).
WithClusterMap(cMap). WithClusterMap(cMap).
WithClusterName(cmd.ClusterName). WithClusterName(cmd.ClusterName).
WithTempRoot(helper.WorkDir()). WithTempRoot(helper.WorkDir()).
SiteWide(siteWide).
Build() Build()
return kubeconf.Write(writer) return kubeconf.Write(writer)

View File

@ -41,6 +41,7 @@ func NewBuilder() *Builder {
// Builder is an object that allows to build a kubeconfig based on various provided sources // Builder is an object that allows to build a kubeconfig based on various provided sources
// such as path to kubeconfig, path to bundle that should contain kubeconfig and parent cluster // such as path to kubeconfig, path to bundle that should contain kubeconfig and parent cluster
type Builder struct { type Builder struct {
siteWide bool
clusterName string clusterName string
root string root string
@ -88,11 +89,21 @@ func (b *Builder) WithFilesystem(fs fs.FileSystem) *Builder {
return b return b
} }
// SiteWide allows to build kubeconfig for the entire site.
// If set to true ClusterName will be ignored, since all clusters are requested.
func (b *Builder) SiteWide(t bool) *Builder {
b.siteWide = t
return b
}
// Build site kubeconfig, ignores, but logs, errors that happen when building individual // Build site kubeconfig, ignores, but logs, errors that happen when building individual
// kubeconfigs. We need this behavior because, some clusters may not yet be deployed // kubeconfigs. We need this behavior because, some clusters may not yet be deployed
// and their kubeconfig is inaccessible yet, but will be accessible at later phases // and their kubeconfig is inaccessible yet, but will be accessible at later phases
// If builder can't build kubeconfig for specific cluster, its context will not be present // If builder can't build kubeconfig for specific cluster, its context will not be present
// in final kubeconfig. User of kubeconfig, will receive error stating that context doesn't exist // in final kubeconfig. User of kubeconfig, will receive error stating that context doesn't exist
// To request site-wide kubeconfig use builder method SiteWide(true).
// To request a single cluster kubeconfig use methods WithClusterName("my-cluster").SiteWide(false)
// ClusterName is ignored if SiteWide(true) is used.
func (b *Builder) Build() Interface { func (b *Builder) Build() Interface {
return NewKubeConfig(b.build, InjectFileSystem(b.fs), InjectTempRoot(b.root)) return NewKubeConfig(b.build, InjectFileSystem(b.fs), InjectTempRoot(b.root))
} }
@ -101,19 +112,19 @@ func (b *Builder) build() ([]byte, error) {
// Set current context to clustername if it was provided // Set current context to clustername if it was provided
var result *api.Config var result *api.Config
var err error var err error
var kubeContext string if !b.siteWide {
if b.clusterName != "" { var kubeContext string
kubeContext, result, err = b.buildOne(b.clusterName) kubeContext, result, err = b.buildOne(b.clusterName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
b.siteKubeconf.CurrentContext = kubeContext
} else { } else {
result, err = b.builtSiteKubeconf() result, err = b.builtSiteKubeconf()
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
b.siteKubeconf.CurrentContext = kubeContext
return clientcmd.Write(*result) return clientcmd.Write(*result)
} }

View File

@ -95,6 +95,7 @@ func TestBuilderClusterctl(t *testing.T) {
errString string errString string
requestedClusterName string requestedClusterName string
tempRoot string tempRoot string
siteWide bool
expectedContexts, expectedClusters, expectedAuthInfos []string expectedContexts, expectedClusters, expectedAuthInfos []string
clusterMap clustermap.ClusterMap clusterMap clustermap.ClusterMap
@ -106,6 +107,7 @@ func TestBuilderClusterctl(t *testing.T) {
expectedContexts: []string{parentClusterID}, expectedContexts: []string{parentClusterID},
expectedClusters: []string{parentParentCluster}, expectedClusters: []string{parentParentCluster},
expectedAuthInfos: []string{parentParentUser}, expectedAuthInfos: []string{parentParentUser},
siteWide: true,
clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{ clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{
Map: map[string]*v1alpha1.Cluster{ Map: map[string]*v1alpha1.Cluster{
childClusterID: { childClusterID: {
@ -134,6 +136,7 @@ func TestBuilderClusterctl(t *testing.T) {
expectedContexts: []string{parentClusterID, parentParentClusterID}, expectedContexts: []string{parentClusterID, parentParentClusterID},
expectedClusters: []string{"dummycluster_ephemeral", parentParentCluster}, expectedClusters: []string{"dummycluster_ephemeral", parentParentCluster},
expectedAuthInfos: []string{"kubernetes-admin", parentParentUser}, expectedAuthInfos: []string{"kubernetes-admin", parentParentUser},
siteWide: true,
clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{ clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{
Map: map[string]*v1alpha1.Cluster{ Map: map[string]*v1alpha1.Cluster{
parentParentClusterID: { parentParentClusterID: {
@ -165,6 +168,7 @@ func TestBuilderClusterctl(t *testing.T) {
expectedContexts: []string{parentClusterID, childClusterID, parentParentClusterID}, expectedContexts: []string{parentClusterID, childClusterID, parentParentClusterID},
expectedClusters: []string{parentCluster, parentParentCluster, childCluster}, expectedClusters: []string{parentCluster, parentParentCluster, childCluster},
expectedAuthInfos: []string{parentUser, parentParentUser, childUser}, expectedAuthInfos: []string{parentUser, parentParentUser, childUser},
siteWide: true,
clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{ clusterMap: clustermap.NewClusterMap(&v1alpha1.ClusterMap{
Map: map[string]*v1alpha1.Cluster{ Map: map[string]*v1alpha1.Cluster{
childClusterID: { childClusterID: {
@ -265,6 +269,7 @@ func TestBuilderClusterctl(t *testing.T) {
WithTempRoot(tt.tempRoot). WithTempRoot(tt.tempRoot).
WithClusterctlClient(tt.clusterctlClient). WithClusterctlClient(tt.clusterctlClient).
WithFilesystem(tt.fs). WithFilesystem(tt.fs).
SiteWide(tt.siteWide).
Build() Build()
require.NotNil(t, kube) require.NotNil(t, kube)
filePath, cleanup, err := kube.GetFile() filePath, cleanup, err := kube.GetFile()

View File

@ -114,6 +114,8 @@ func (p *phase) executor(docFactory document.DocFactoryFunc,
WithClusterMap(cMap). WithClusterMap(cMap).
WithTempRoot(p.helper.WorkDir()). WithTempRoot(p.helper.WorkDir()).
WithClusterctlClient(cctlClient). WithClusterctlClient(cctlClient).
WithClusterName(p.apiObj.ClusterName).
SiteWide(p.apiObj.Config.SiteWideKubeconfig).
Build() Build()
return executorFactory( return executorFactory(

View File

@ -437,6 +437,7 @@ func TestPlanRunCommand(t *testing.T) {
name string name string
factory config.Factory factory config.Factory
expectedErr string expectedErr string
planID ifc.ID
}{ }{
{ {
name: "Error config factory", name: "Error config factory",
@ -456,7 +457,10 @@ func TestPlanRunCommand(t *testing.T) {
expectedErr: "missing configuration: context with name 'does not exist'", expectedErr: "missing configuration: context with name 'does not exist'",
}, },
{ {
name: "Error phase by id", name: "Error plan by id",
planID: ifc.ID{
Name: "doesn't exist",
},
factory: func() (*config.Config, error) { factory: func() (*config.Config, error) {
conf := config.NewConfig() conf := config.NewConfig()
conf.Manifests = map[string]*config.Manifest{ conf.Manifests = map[string]*config.Manifest{
@ -479,7 +483,7 @@ func TestPlanRunCommand(t *testing.T) {
} }
return conf, nil return conf, nil
}, },
expectedErr: `context "ephemeral-cluster" does not exist`, expectedErr: `found no documents`,
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
@ -490,6 +494,7 @@ func TestPlanRunCommand(t *testing.T) {
GenericRunFlags: phase.GenericRunFlags{ GenericRunFlags: phase.GenericRunFlags{
DryRun: true, DryRun: true,
}, },
PlanID: tt.planID,
}, },
Factory: tt.factory, Factory: tt.factory,
} }

View File

@ -94,6 +94,7 @@ func (c *ContainerExecutor) Run(evtCh chan events.Event, opts ifc.RunOptions) {
cleanup, err := c.SetKubeConfig() cleanup, err := c.SetKubeConfig()
if err != nil { if err != nil {
handleError(evtCh, err) handleError(evtCh, err)
return
} }
defer cleanup() defer cleanup()
} }