Skip to content

Commit

Permalink
liqoctl offload ns: add support to output NamespaceOffloading resource
Browse files Browse the repository at this point in the history
  • Loading branch information
giorio94 authored and adamjensenbot committed Jun 15, 2022
1 parent dffc740 commit b7cf2a2
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 3 deletions.
13 changes: 13 additions & 0 deletions cmd/liqoctl/cmd/offload.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ Namespace offloading can be tuned in terms of:
* Naming: whether remote namespaces have the same name or a suffix is added to
prevent conflicts.
Besides the direct offloading of a namespace, this command also provides the
possibility to generate and output the underlying NamespaceOffloading
resource, that can later be applied through automation tools.
Examples:
$ {{ .Executable }} offload namespace foo
or
Expand All @@ -55,6 +59,8 @@ or (cluster labels in logical AND)
or (cluster labels in logical OR)
$ {{ .Executable }} offload namespace foo --namespace-mapping-strategy EnforceSameName \
--selector 'region in (europe,us-west)' --selector '!staging'
or (output the NamespaceOffloading resource as a yaml manifest, without applying it)
$ {{ .Executable }} offload namespace foo --output yaml
`

func newOffloadCommand(ctx context.Context, f *factory.Factory) *cobra.Command {
Expand Down Expand Up @@ -83,6 +89,8 @@ func newOffloadNamespaceCommand(ctx context.Context, f *factory.Factory) *cobra.
string(offloadingv1alpha1.DefaultNameMappingStrategyType)},
string(offloadingv1alpha1.DefaultNameMappingStrategyType))

outputFormat := args.NewEnum([]string{"json", "yaml"}, "")

options := offload.Options{Factory: f}
cmd := &cobra.Command{
Use: "namespace name",
Expand All @@ -96,6 +104,7 @@ func newOffloadNamespaceCommand(ctx context.Context, f *factory.Factory) *cobra.
PreRun: func(cmd *cobra.Command, args []string) {
options.PodOffloadingStrategy = offloadingv1alpha1.PodOffloadingStrategyType(podOffloadingStrategy.Value)
options.NamespaceMappingStrategy = offloadingv1alpha1.NamespaceMappingStrategyType(namespaceMappingStrategy.Value)
options.OutputFormat = outputFormat.Value
options.Printer.CheckErr(options.ParseClusterSelectors(selectors))
},

Expand All @@ -114,8 +123,12 @@ func newOffloadNamespaceCommand(ctx context.Context, f *factory.Factory) *cobra.
cmd.Flags().StringArrayVarP(&selectors, "selector", "l", []string{},
"The selector to filter the target clusters. Can be specified multiple times, defining alternative requirements (i.e., in logical OR)")

cmd.Flags().VarP(outputFormat, "output", "o",
"Output the resulting NamespaceOffloading resource, instead of applying it. Supported formats: json, yaml")

f.Printer.CheckErr(cmd.RegisterFlagCompletionFunc("pod-offloading-strategy", completion.Enumeration(podOffloadingStrategy.Allowed)))
f.Printer.CheckErr(cmd.RegisterFlagCompletionFunc("namespace-mapping-strategy", completion.Enumeration(namespaceMappingStrategy.Allowed)))
f.Printer.CheckErr(cmd.RegisterFlagCompletionFunc("output", completion.Enumeration(outputFormat.Allowed)))

return cmd
}
2 changes: 1 addition & 1 deletion docs/examples/global-ingress.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ kubectl run -it --rm curl --restart=Never --image=curlimages/curl:7.82.0 --comma
-- curl $HOSTNAME -v
```

```{admonition} Note:
```{admonition} Note
Launching this pod several times, you will see different IPs and different frontend pods answering in a round-robin fashion (as set in the *Gslb* policy).
```

Expand Down
17 changes: 16 additions & 1 deletion docs/usage/namespace-offloading.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,22 @@ A given namespace *foo* can be offloaded, leveraging the default configuration,
liqoctl offload namespace foo
```

Namespace offloading can be further configured in terms of the three main parameters presented below, each one exposed through a dedicated CLI flag.
Alternatively, the underlying *NamespaceOffloading* resource can be generated and output (either in *yaml* or *json* format) leveraging the dedicated `--output` flag:

```bash
liqoctl offload namespace foo --output yaml
```

Then, the resulting manifest can be applied with *kubectl*, or through automation tools (e.g., by means of GitOps approaches).

```{admonition} Note
Possible race conditions might occur in case a *NamespaceOffloading* resource is created at the same time (e.g., as a batch) as pods (or higher level abstractions such as *Deployments*), preventing them from being considered for offloading until the *NamespaceOffloading* resource is not processed.
This situation can be prevented manually labeling in advance the hosting namespace with the *liqo.io/scheduling-enabled=true* label, hence enabling the Liqo mutating webhook and causing pod creations to be rejected until pod offloading is possible.
Still, this causes no problems, as the Kubernetes abstractions (e.g., *Deployments*) ensure that the desired pods get eventually created correctly.
```

Regardless of the approach adopted, namespace offloading can be further configured in terms of the three main parameters presented below, each one exposed through a dedicated CLI flag.

### Namespace mapping strategy

Expand Down
35 changes: 35 additions & 0 deletions pkg/liqoctl/offload/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ package offload
import (
"context"
"fmt"
"os"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/printers"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

offloadingv1alpha1 "github.com/liqotech/liqo/apis/offloading/v1alpha1"
Expand All @@ -39,6 +41,8 @@ type Options struct {
NamespaceMappingStrategy offloadingv1alpha1.NamespaceMappingStrategyType
ClusterSelector [][]metav1.LabelSelectorRequirement

OutputFormat string

Timeout time.Duration
}

Expand Down Expand Up @@ -67,6 +71,12 @@ func (o *Options) Run(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, o.Timeout)
defer cancel()

// Output the NamespaceOffloading resource, instead of applying it.
if o.OutputFormat != "" {
o.Printer.CheckErr(o.output())
return nil
}

s := o.Printer.StartSpinner(fmt.Sprintf("Enabling namespace offloading for %q", o.Namespace))

nsoff := &offloadingv1alpha1.NamespaceOffloading{ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -104,6 +114,31 @@ func (o *Options) Run(ctx context.Context) error {
return nil
}

// output implements the logic to output the generated NamespaceOffloading resource.
func (o *Options) output() error {
var printer printers.ResourcePrinter
switch o.OutputFormat {
case "yaml":
printer = &printers.YAMLPrinter{}
case "json":
printer = &printers.JSONPrinter{}
default:
return fmt.Errorf("unsupported output format %q", o.OutputFormat)
}

nsoff := offloadingv1alpha1.NamespaceOffloading{
TypeMeta: metav1.TypeMeta{APIVersion: offloadingv1alpha1.GroupVersion.String(), Kind: "NamespaceOffloading"},
ObjectMeta: metav1.ObjectMeta{Name: consts.DefaultNamespaceOffloadingName, Namespace: o.Namespace},
Spec: offloadingv1alpha1.NamespaceOffloadingSpec{
PodOffloadingStrategy: o.PodOffloadingStrategy,
NamespaceMappingStrategy: o.NamespaceMappingStrategy,
ClusterSelector: toNodeSelector(o.ClusterSelector),
},
}

return printer.PrintObj(&nsoff, os.Stdout)
}

func toNodeSelector(selectors [][]metav1.LabelSelectorRequirement) corev1.NodeSelector {
terms := []corev1.NodeSelectorTerm{}

Expand Down
2 changes: 1 addition & 1 deletion pkg/liqoctl/wait/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func (w *Waiter) ForOffloading(ctx context.Context, namespace string) error {
s := w.Printer.StartSpinner(fmt.Sprintf("Waiting for offloading of namespace %q to complete", namespace))
noClusterSelected := false
var offload *offloadingv1alpha1.NamespaceOffloading
err := wait.PollImmediateUntilWithContext(ctx, 1*time.Second, func(ctx context.Context) (done bool, err error) {
err := wait.PollImmediateUntilWithContext(ctx, 100*time.Millisecond, func(ctx context.Context) (done bool, err error) {
offload, err = getters.GetOffloadingByNamespace(ctx, w.CRClient, namespace)
if err != nil {
return false, client.IgnoreNotFound(err)
Expand Down

0 comments on commit b7cf2a2

Please sign in to comment.