Files
airshipctl/pkg/k8s/applier/executor.go
Ruslan Aliev 0c736af2e8 Implement render methods
Change-Id: I03b7aad33576eaa9ef7dfaabfb579ac90cc26a12
Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
2020-09-23 03:06:51 +00:00

149 lines
4.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 applier
import (
"io"
"time"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/cli-utils/pkg/common"
airshipv1 "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/errors"
"opendev.org/airship/airshipctl/pkg/events"
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
"opendev.org/airship/airshipctl/pkg/k8s/utils"
"opendev.org/airship/airshipctl/pkg/log"
"opendev.org/airship/airshipctl/pkg/phase/ifc"
)
// ExecutorOptions provide a way to configure executor
type ExecutorOptions struct {
BundleName string
ClusterName string
ExecutorDocument document.Document
ExecutorBundle document.Bundle
Kubeconfig kubeconfig.Interface
Helper ifc.Helper
}
var _ ifc.Executor = &Executor{}
// RegisterExecutor adds executor to phase executor registry
func RegisterExecutor(registry map[schema.GroupVersionKind]ifc.ExecutorFactory) error {
obj := &airshipv1.KubernetesApply{}
gvks, _, err := airshipv1.Scheme.ObjectKinds(obj)
if err != nil {
return err
}
registry[gvks[0]] = registerExecutor
return nil
}
// registerExecutor is here so that executor in theory can be used outside phases
func registerExecutor(cfg ifc.ExecutorConfig) (ifc.Executor, error) {
return NewExecutor(ExecutorOptions{
ClusterName: cfg.ClusterName,
BundleName: cfg.PhaseName,
Helper: cfg.Helper,
ExecutorBundle: cfg.ExecutorBundle,
ExecutorDocument: cfg.ExecutorDocument,
Kubeconfig: cfg.KubeConfig,
})
}
// Executor applies resources to kubernetes
type Executor struct {
Options ExecutorOptions
apiObject *airshipv1.KubernetesApply
cleanup kubeconfig.Cleanup
}
// NewExecutor returns instance of executor
func NewExecutor(opts ExecutorOptions) (*Executor, error) {
apiObj := &airshipv1.KubernetesApply{}
err := opts.ExecutorDocument.ToAPIObject(apiObj, airshipv1.Scheme)
if err != nil {
return nil, err
}
if opts.ExecutorBundle == nil {
return nil, ErrNilBundle{}
}
return &Executor{
Options: opts,
apiObject: apiObj,
}, nil
}
// Run executor, should be performed in separate go routine
func (e *Executor) Run(ch chan events.Event, runOpts ifc.RunOptions) {
applier, filteredBundle, err := e.prepareApplier(ch)
if err != nil {
handleError(ch, err)
close(ch)
return
}
defer e.cleanup()
dryRunStrategy := common.DryRunNone
if runOpts.DryRun {
dryRunStrategy = common.DryRunClient
}
applyOptions := ApplyOptions{
DryRunStrategy: dryRunStrategy,
Prune: e.apiObject.Config.PruneOptions.Prune,
BundleName: e.Options.BundleName,
WaitTimeout: time.Second * time.Duration(e.apiObject.Config.WaitOptions.Timeout),
}
applier.ApplyBundle(filteredBundle, applyOptions)
}
func (e *Executor) prepareApplier(ch chan events.Event) (*Applier, document.Bundle, error) {
log.Debug("Getting kubeconfig file information from kubeconfig provider")
path, cleanup, err := e.Options.Kubeconfig.GetFile()
if err != nil {
return nil, nil, err
}
log.Debug("Filtering out documents that shouldn't be applied to kubernetes from document bundle")
bundle, err := e.Options.ExecutorBundle.SelectBundle(document.NewDeployToK8sSelector())
if err != nil {
cleanup()
return nil, nil, err
}
// set up cleanup only if all calls up to here were successful
e.cleanup = cleanup
// Use cluster name as context in kubeconfig file
factory := utils.FactoryFromKubeConfig(path, e.Options.ClusterName)
streams := utils.Streams()
return NewApplier(ch, factory, streams), bundle, nil
}
// Validate document set
func (e *Executor) Validate() error {
return errors.ErrNotImplemented{}
}
// Render document set
func (e *Executor) Render(w io.Writer, o ifc.RenderOptions) error {
bundle, err := e.Options.ExecutorBundle.SelectBundle(o.FilterSelector)
if err != nil {
return err
}
return bundle.Write(w)
}