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
clusterName: target-cluster
config:
siteWideKubeconfig: true
executorRef:
apiVersion: airshipit.org/v1alpha1
kind: Clusterctl

View File

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

View File

@ -83,12 +83,18 @@ func (cmd *GetKubeconfigCommand) RunE(cfgFactory config.Factory, writer io.Write
return err
}
var siteWide bool
if cmd.ClusterName == "" {
siteWide = true
}
kubeconf := kubeconfig.NewBuilder().
WithBundle(helper.PhaseConfigBundle()).
WithClusterctlClient(client).
WithClusterMap(cMap).
WithClusterName(cmd.ClusterName).
WithTempRoot(helper.WorkDir()).
SiteWide(siteWide).
Build()
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
// such as path to kubeconfig, path to bundle that should contain kubeconfig and parent cluster
type Builder struct {
siteWide bool
clusterName string
root string
@ -88,11 +89,21 @@ func (b *Builder) WithFilesystem(fs fs.FileSystem) *Builder {
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
// 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
// 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
// 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 {
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
var result *api.Config
var err error
var kubeContext string
if b.clusterName != "" {
if !b.siteWide {
var kubeContext string
kubeContext, result, err = b.buildOne(b.clusterName)
if err != nil {
return nil, err
}
b.siteKubeconf.CurrentContext = kubeContext
} else {
result, err = b.builtSiteKubeconf()
if err != nil {
return nil, err
}
}
b.siteKubeconf.CurrentContext = kubeContext
return clientcmd.Write(*result)
}

View File

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

View File

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

View File

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

View File

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