
Change-Id: I6943cddee52bcb605ce63adc21ce56f6afaadc5b Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
170 lines
5.3 KiB
Go
170 lines
5.3 KiB
Go
/*
|
|
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 main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
|
v1 "k8s.io/client-go/applyconfigurations/core/v1"
|
|
"k8s.io/klog/v2"
|
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
"sigs.k8s.io/cli-utils/cmd/flagutils"
|
|
"sigs.k8s.io/cli-utils/cmd/printers"
|
|
"sigs.k8s.io/cli-utils/pkg/apply"
|
|
"sigs.k8s.io/cli-utils/pkg/common"
|
|
"sigs.k8s.io/cli-utils/pkg/errors"
|
|
"sigs.k8s.io/cli-utils/pkg/inventory"
|
|
"sigs.k8s.io/cli-utils/pkg/util/factory"
|
|
"sigs.k8s.io/kustomize/kyaml/fn/framework"
|
|
"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
|
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
|
|
"opendev.org/airship/airshipctl/krm-functions/applier/image/poller"
|
|
"opendev.org/airship/airshipctl/krm-functions/applier/image/types"
|
|
)
|
|
|
|
const (
|
|
airshipNamespace = "airshipit"
|
|
)
|
|
|
|
// Config is an extension of ApplyConfig struct with added streams
|
|
type Config struct {
|
|
*types.ApplyConfig
|
|
Streams genericclioptions.IOStreams
|
|
}
|
|
|
|
func factoryFromKubeConfig(path, context string) cmdutil.Factory {
|
|
kf := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
|
|
kf.KubeConfig = &path
|
|
kf.Context = &context
|
|
return cmdutil.NewFactory(cmdutil.NewMatchVersionFlags(&factory.CachingRESTClientGetter{Delegate: kf}))
|
|
}
|
|
|
|
func appendInventoryInfo(obj []*unstructured.Unstructured, name string) (*unstructured.Unstructured, []*unstructured.Unstructured, error) {
|
|
namespace := fmt.Sprintf("%s-%s", airshipNamespace, name)
|
|
cmObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(v1.ConfigMap(fmt.Sprintf("inventory-%s",
|
|
common.RandomStr()), namespace).WithLabels(map[string]string{common.InventoryLabel: name}))
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
namespaceObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(v1.Namespace(namespace))
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return &unstructured.Unstructured{Object: cmObj}, append(obj, &unstructured.Unstructured{Object: namespaceObj}), nil
|
|
}
|
|
|
|
// Run prepares config, applier and performs apply process
|
|
func (c *Config) Run(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
|
|
if c.Debug {
|
|
if err := flag.Set("v", "2"); err != nil {
|
|
klog.V(2).Infof("unable to set debug flag: %v\n", err)
|
|
}
|
|
}
|
|
|
|
var objs []*unstructured.Unstructured
|
|
for _, node := range nodes {
|
|
m, err := node.Map()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
objs = append(objs, &unstructured.Unstructured{Object: m})
|
|
}
|
|
|
|
f := factoryFromKubeConfig(c.Kubeconfig, c.Context)
|
|
statusPoller, err := poller.NewStatusPoller(f, c.WaitOptions.Conditions...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
invFactory := inventory.ClusterInventoryClientFactory{}
|
|
invClient, err := invFactory.NewInventoryClient(f)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
applier, err := apply.NewApplier(f, invClient, statusPoller)
|
|
inv, obj, err := inventory.SplitUnstructureds(objs)
|
|
if err != nil {
|
|
klog.V(2).Infoln("injecting auto generated inventory object")
|
|
inv, obj, err = appendInventoryInfo(obj, c.PhaseName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
opts := c.toCliOptions()
|
|
err = printers.GetPrinter(printers.DefaultPrinter(), c.Streams).Print(
|
|
applier.Run(context.Background(), inventory.WrapInventoryInfoObj(inv), obj, opts), opts.DryRunStrategy, true)
|
|
klog.V(2).Infoln("applier channel closed")
|
|
errors.CheckErr(c.Streams.ErrOut, err, "applier")
|
|
return nil, err
|
|
}
|
|
|
|
func (c *Config) toCliOptions() apply.Options {
|
|
dryRunStrategy := common.DryRunNone
|
|
if c.DryRun {
|
|
dryRunStrategy = common.DryRunClient
|
|
}
|
|
timeout := time.Second * time.Duration(c.WaitOptions.Timeout)
|
|
pollInterval := time.Second * time.Duration(c.WaitOptions.PollInterval)
|
|
|
|
var emitStatusEvents bool
|
|
// if wait timeout is 0, we don't want to status poller to emit any events,
|
|
// this should disable waiting for resources
|
|
if timeout != time.Duration(0) {
|
|
emitStatusEvents = true
|
|
}
|
|
|
|
inventoryPolicy, err := flagutils.ConvertInventoryPolicy(c.InventoryPolicy)
|
|
if err != nil {
|
|
klog.V(2).Infof("%s or force-adopt, using the default one (strict)", err.Error())
|
|
}
|
|
|
|
return apply.Options{
|
|
DryRunStrategy: dryRunStrategy,
|
|
NoPrune: !c.PruneOptions.Prune,
|
|
EmitStatusEvents: emitStatusEvents,
|
|
ReconcileTimeout: timeout,
|
|
PollInterval: pollInterval,
|
|
InventoryPolicy: inventoryPolicy,
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
cfg := &Config{ApplyConfig: &types.ApplyConfig{}}
|
|
cmd := command.Build(framework.SimpleProcessor{Filter: kio.FilterFunc(cfg.Run), Config: cfg.ApplyConfig},
|
|
command.StandaloneDisabled, false)
|
|
cfg.Streams = genericclioptions.IOStreams{In: cmd.InOrStdin(), Out: cmd.ErrOrStderr(), ErrOut: cmd.ErrOrStderr()}
|
|
|
|
klog.InitFlags(nil)
|
|
klog.SetOutput(cmd.ErrOrStderr())
|
|
defer klog.Flush()
|
|
|
|
if err := cmd.Execute(); err != nil {
|
|
_, _ = fmt.Fprintln(cmd.ErrOrStderr())
|
|
os.Exit(1)
|
|
}
|
|
}
|