Skip to content

Commit

Permalink
Merge pull request #289 from pdettori/issue-288
Browse files Browse the repository at this point in the history
✨ more forceful kflex ctx commands
  • Loading branch information
pdettori authored Oct 22, 2024
2 parents 1131006 + cf73578 commit d47109e
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 16 deletions.
4 changes: 2 additions & 2 deletions cmd/kflex/create/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ type CPCreate struct {
common.CP
}

// Create a ne control plane
// Create a new control plane
func (c *CPCreate) Create(controlPlaneType, backendType, hook string, hookVars []string, chattyStatus bool) {
done := make(chan bool)
var wg sync.WaitGroup
cx := cont.CPCtx{}
cx.Context(chattyStatus, false)
cx.Context(chattyStatus, false, false, false)

clp, err := kfclient.GetClient(c.Kubeconfig)
if err != nil {
Expand Down
27 changes: 22 additions & 5 deletions cmd/kflex/ctx/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type CPCtx struct {
}

// Context switch context in Kubeconfig
func (c *CPCtx) Context(chattyStatus, failIfNone bool) {
func (c *CPCtx) Context(chattyStatus, failIfNone, overwriteExistingCtx, setCurrentCtxAsHosting bool) {
done := make(chan bool)
var wg sync.WaitGroup
kconf, err := kubeconfig.LoadKubeconfig(c.Ctx)
Expand All @@ -51,6 +51,9 @@ func (c *CPCtx) Context(chattyStatus, failIfNone bool) {

switch c.CP.Name {
case "":
if setCurrentCtxAsHosting { // set hosting cluster context unconditionally to the current context
kubeconfig.SetHostingClusterContextPreference(kconf, nil)
}
util.PrintStatus("Checking for saved hosting cluster context...", done, &wg, chattyStatus)
time.Sleep(1 * time.Second)
done <- true
Expand All @@ -64,19 +67,32 @@ func (c *CPCtx) Context(chattyStatus, failIfNone bool) {
} else if failIfNone {
if !c.isCurrentContextHostingClusterContext() {
fmt.Fprintln(os.Stderr, "The hosting cluster context is not known!\n"+
"You can make it known to kflex by doing `kubectl config use-context $name_of_hosting_context` "+
"and then either `kflex ctx` or `kflex create ...`")
"You can make it known to kflex by doing `kubectl config use-context` \n"+
"to set the current context to the hosting cluster context and then using \n"+
"`kflex ctx --set-current-for-hosting` to restore the needed kubeconfig extension.")
os.Exit(1)
}
util.PrintStatus("Hosting cluster context not set, setting it to current context", done, &wg, chattyStatus)
kubeconfig.SetHostingClusterContextPreference(kconf)
kubeconfig.SetHostingClusterContextPreference(kconf, nil)
done <- true
}
default:
ctxName := certs.GenerateContextName(c.Name)
if overwriteExistingCtx {
util.PrintStatus("Overwriting existing context for control plane", done, &wg, chattyStatus)
if err = kubeconfig.DeleteContext(kconf, c.Name); err != nil {
fmt.Fprintf(os.Stderr, "no kubeconfig context for %s was found: %s\n", c.Name, err)
}
done <- true
}

util.PrintStatus(fmt.Sprintf("Switching to context %s...", ctxName), done, &wg, chattyStatus)
if err = kubeconfig.SwitchContext(kconf, c.Name); err != nil {
fmt.Fprintf(os.Stderr, "kubeconfig context %s not found (%s), trying to load from server...\n", c.Name, err)
if overwriteExistingCtx {
fmt.Fprintf(os.Stderr, "trying to load new context %s from server...\n", c.Name)
} else {
fmt.Fprintf(os.Stderr, "kubeconfig context %s not found (%s), trying to load from server...\n", c.Name, err)
}
if err := c.switchToHostingClusterContextAndWrite(kconf); err != nil {
fmt.Fprintf(os.Stderr, "Error switching back to hosting cluster context: %s\n", err)
os.Exit(1)
Expand All @@ -97,6 +113,7 @@ func (c *CPCtx) Context(chattyStatus, failIfNone bool) {
}
}
done <- true

}

if err = kubeconfig.WriteKubeconfig(c.Ctx, kconf); err != nil {
Expand Down
3 changes: 2 additions & 1 deletion cmd/kflex/delete/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ func (c *CPDelete) Delete(chattyStatus bool) {
}

if err = kubeconfig.SwitchToHostingClusterContext(kconf, false); err != nil {
fmt.Fprintf(os.Stderr, "no initial kubeconfig context was found: %s\n", err)
fmt.Fprintf(os.Stderr, "error switching to hosting cluster kubeconfig context: %s\n", err)
os.Exit(1)
}

if err = kubeconfig.DeleteContext(kconf, c.Name); err != nil {
Expand Down
6 changes: 5 additions & 1 deletion cmd/kflex/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ var externalPort int
var chattyStatus bool
var hookVars []string
var hostContainer string
var overwriteExistingCtx bool
var setCurrentCtxAsHosting bool

// defaults
const BKTypeDefault = string(tenancyv1alpha1.BackendDBTypeShared)
Expand Down Expand Up @@ -175,7 +177,7 @@ var ctxCmd = &cobra.Command{
Kubeconfig: kubeconfig,
},
}
cp.Context(chattyStatus, true)
cp.Context(chattyStatus, true, overwriteExistingCtx, setCurrentCtxAsHosting)
},
}

Expand Down Expand Up @@ -206,6 +208,8 @@ func init() {
ctxCmd.Flags().StringVarP(&kubeconfig, "kubeconfig", "k", "", "path to kubeconfig file")
ctxCmd.Flags().IntVarP(&verbosity, "verbosity", "v", 0, "log level") // TODO - figure out how to inject verbosity
ctxCmd.Flags().BoolVarP(&chattyStatus, "chatty-status", "s", true, "chatty status indicator")
ctxCmd.Flags().BoolVarP(&overwriteExistingCtx, "overwrite-existing-context", "o", false, "Overwrite of hosting cluster context with new control plane context")
ctxCmd.Flags().BoolVarP(&setCurrentCtxAsHosting, "set-current-for-hosting", "c", false, "Set current context as hosting cluster context")

rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(initCmd)
Expand Down
14 changes: 11 additions & 3 deletions docs/users.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,15 @@ kflex ctx

That command requires your kubeconfig file to hold an extension that `kflex init` created to hold the name of the hosting cluster context. See [below](#hosting-context) for more information.

To update or refresh outdated or corrupted context information for a control plane stored in
the kubeconfig file, you can forcefully reload and overwrite the existing context data from
the KubeFlex hosting cluster. This can be accomplished by using the `--overwrite-existing-context`
flag. Here is an example:

```shell
kflex ctx cp1 --overwrite-existing-context
```

To switch back to a control plane context, use the
`ctx <control plane name>` command, e.g:

Expand Down Expand Up @@ -718,9 +727,8 @@ You can do this in either of the two following ways.
If the relevant extension is missing then you can restore it by using
`kubectl config use-context` to set the current context to the hosting
cluster context and then using `kflex ctx $cpname` to switch to
another context. In the course of doing that, `kflex` will restore the
needed kubeconfig extension.
cluster context and then using `kflex ctx --set-current-for-hosting`
to restore the needed kubeconfig extension.
### Restore Hosting Context Preference by editing kubeconfig file
Expand Down
21 changes: 17 additions & 4 deletions pkg/kubeconfig/config-util.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func merge(existing, new *clientcmdapi.Config) error {
}

if !IsHostingClusterContextPreferenceSet(existing) {
SetHostingClusterContextPreference(existing)
SetHostingClusterContextPreference(existing, nil)
}

// set the current context to the nex context
Expand Down Expand Up @@ -88,6 +88,7 @@ func SwitchToHostingClusterContext(config *clientcmdapi.Config, removeExtension
if !IsHostingClusterContextPreferenceSet(config) {
return fmt.Errorf("hosting cluster preference context not set")
}

// found that the only way to unmarshal the runtime.Object into a ConfigMap
// was to use the unMarshallCM() function based on json marshal/unmarshal
cm, err := unMarshallCM(config.Preferences.Extensions[ConfigExtensionName])
Expand All @@ -99,6 +100,13 @@ func SwitchToHostingClusterContext(config *clientcmdapi.Config, removeExtension
if !ok {
return fmt.Errorf("hosting cluster preference context data not set")
}

// make sure that context set in extension is a valid context
_, ok = config.Contexts[contextData]
if !ok {
return fmt.Errorf("hosting cluster preference context data is set to a non-existing context")
}

config.CurrentContext = contextData

// remove the extensions
Expand All @@ -108,14 +116,19 @@ func SwitchToHostingClusterContext(config *clientcmdapi.Config, removeExtension
return nil
}

func SetHostingClusterContextPreference(config *clientcmdapi.Config) {
// sets hosting cluster context to current context if userSuppliedContext is nil, otherwise set to userSuppliedContext
func SetHostingClusterContextPreference(config *clientcmdapi.Config, userSuppliedContext *string) {
hostingContext := config.CurrentContext
if userSuppliedContext != nil {
hostingContext = *userSuppliedContext
}
runtimeObjects := make(map[string]runtime.Object)
runtimeObjects[ConfigExtensionName] = &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: ConfigExtensionName,
},
Data: map[string]string{
InitialContextName: config.CurrentContext,
InitialContextName: hostingContext,
},
}

Expand All @@ -139,7 +152,7 @@ func SaveHostingClusterContextPreference(ctx context.Context) error {
if err != nil {
return fmt.Errorf("setHostingClusterContextPreference: error loading kubeconfig %s", err)
}
SetHostingClusterContextPreference(kconfig)
SetHostingClusterContextPreference(kconfig, nil)
return WriteKubeconfig(ctx, kconfig)
}

Expand Down

0 comments on commit d47109e

Please sign in to comment.