Merge "Reduce the number of unnecessary document.NewBundleByPath() calls"

This commit is contained in:
Zuul 2021-03-31 02:02:41 +00:00 committed by Gerrit Code Review
commit 9196dd089a
27 changed files with 250 additions and 95 deletions

View File

@ -78,22 +78,17 @@ func (cmd *GetKubeconfigCommand) RunE(cfgFactory config.Factory, writer io.Write
return err
}
wd, err := helper.WorkDir()
if err != nil {
return err
}
client, err := client.NewClient(helper.TargetPath(), log.DebugEnabled(), airshipv1.DefaultClusterctl())
if err != nil {
return err
}
kubeconf := kubeconfig.NewBuilder().
WithBundle(helper.PhaseBundleRoot()).
WithBundle(helper.PhaseConfigBundle()).
WithClusterctClient(client).
WithClusterMap(cMap).
WithClusterName(cmd.ClusterName).
WithTempRoot(wd).
WithTempRoot(helper.WorkDir()).
Build()
return kubeconf.Write(writer)

0
pkg/container/testdata/kustomization.yaml vendored Executable file
View File

View File

@ -23,6 +23,7 @@ import (
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/fs"
"opendev.org/airship/airshipctl/pkg/log"
)
@ -40,19 +41,19 @@ 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 {
bundlePath string
clusterName string
root string
bundle document.Bundle
clusterMap clustermap.ClusterMap
clusterctlClient client.Interface
fs fs.FileSystem
siteKubeconf *api.Config
}
// WithBundle allows to set path to bundle that should contain kubeconfig api object
func (b *Builder) WithBundle(bundlePath string) *Builder {
b.bundlePath = bundlePath
// WithBundle allows to set document.Bundle object that should contain kubeconfig api object
func (b *Builder) WithBundle(bundle document.Bundle) *Builder {
b.bundle = bundle
return b
}
@ -181,7 +182,7 @@ func (b *Builder) trySource(clusterID, dstContext string, source v1alpha1.Kubeco
getter = FromFile(source.FileSystem.Path, b.fs)
sourceContext = source.FileSystem.Context
case v1alpha1.KubeconfigSourceTypeBundle:
getter = FromBundle(b.bundlePath)
getter = FromBundle(b.bundle)
sourceContext = source.Bundle.Context
case v1alpha1.KubeconfigSourceTypeClusterAPI:
getter = b.fromClusterAPI(clusterID, source.ClusterAPI)

View File

@ -27,6 +27,7 @@ import (
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/fs"
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
"opendev.org/airship/airshipctl/testutil/clusterctl"
@ -85,8 +86,9 @@ func TestBuilderClusterctl(t *testing.T) {
parentUser := "parent_admin"
parentParentUser := "parent_parent_admin"
childUser := "child_user"
testBundlePath := "testdata"
kubeconfigPath := filepath.Join(testBundlePath, "kubeconfig-12341234")
testBundle, err := document.NewBundleByPath("testdata")
require.NoError(t, err)
kubeconfigPath := filepath.Join("testdata", "kubeconfig-12341234")
tests := []struct {
name string
@ -259,7 +261,7 @@ func TestBuilderClusterctl(t *testing.T) {
kube := kubeconfig.NewBuilder().
WithClusterMap(tt.clusterMap).
WithClusterName(tt.requestedClusterName).
WithBundle(testBundlePath).
WithBundle(testBundle).
WithTempRoot(tt.tempRoot).
WithClusterctClient(tt.clusterctlClient).
WithFilesytem(tt.fs).

View File

@ -122,20 +122,15 @@ func FromFile(path string, fSys fs.FileSystem) KubeSourceFunc {
}
// FromBundle returns KubeSource type, uses path to document bundle to find kubeconfig
func FromBundle(root string) KubeSourceFunc {
func FromBundle(bundle document.Bundle) KubeSourceFunc {
return func() ([]byte, error) {
docBundle, err := document.NewBundleByPath(root)
if err != nil {
return nil, err
}
config := &v1alpha1.KubeConfig{}
selector, err := document.NewSelector().ByObject(config, v1alpha1.Scheme)
if err != nil {
return nil, err
}
doc, err := docBundle.SelectOne(selector)
doc, err := bundle.SelectOne(selector)
if err != nil {
return nil, err
}

View File

@ -29,6 +29,7 @@ import (
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
"opendev.org/airship/airshipctl/pkg/clusterctl/client"
"opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/fs"
"opendev.org/airship/airshipctl/pkg/k8s/kubeconfig"
testfs "opendev.org/airship/airshipctl/testutil/fs"
@ -184,14 +185,14 @@ func TestFromBundle(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
kubeconf, err := kubeconfig.FromBundle(tt.rootPath)()
bundle, err := document.NewBundleByPath(tt.rootPath)
if tt.shouldFail {
require.Error(t, err)
assert.Nil(t, kubeconf)
} else {
require.NoError(t, err)
assert.Contains(t, string(kubeconf), tt.expectedContains)
return
}
kubeconf, err := kubeconfig.FromBundle(bundle)()
require.NoError(t, err)
assert.Contains(t, string(kubeconf), tt.expectedContains)
})
}
}

View File

@ -87,11 +87,6 @@ func (p *phase) Executor() (ifc.Executor, error) {
return nil, err
}
wd, err := p.helper.WorkDir()
if err != nil {
return nil, err
}
cctlClient, err := cctlclient.NewClient(
p.helper.PhaseBundleRoot(),
log.DebugEnabled(),
@ -101,9 +96,9 @@ func (p *phase) Executor() (ifc.Executor, error) {
}
kubeconf := kubeconfig.NewBuilder().
WithBundle(p.helper.PhaseBundleRoot()).
WithBundle(p.helper.PhaseConfigBundle()).
WithClusterMap(cMap).
WithTempRoot(wd).
WithTempRoot(p.helper.WorkDir()).
WithClusterctClient(cctlClient).
Build()

View File

@ -179,18 +179,14 @@ func (c *ContainerExecutor) Render(_ io.Writer, _ ifc.RenderOptions) error {
func (c *ContainerExecutor) setConfig() error {
if c.Container.ConfigRef != nil {
log.Printf("Config reference is specified, looking for the object in config ref: '%v'", c.Container.ConfigRef)
log.Printf("using bundle root %s", c.Helper.PhaseBundleRoot())
bundle, err := document.NewBundleByPath(c.Helper.PhaseBundleRoot())
if err != nil {
return err
}
log.Debugf("Config reference is specified, looking for the object in config ref: '%v'", c.Container.ConfigRef)
log.Debugf("using bundle root %s", c.Helper.PhaseBundleRoot())
gvk := c.Container.ConfigRef.GroupVersionKind()
selector := document.NewSelector().
ByName(c.Container.ConfigRef.Name).
ByNamespace(c.Container.ConfigRef.Namespace).
ByGvk(gvk.Group, gvk.Version, gvk.Kind)
doc, err := bundle.SelectOne(selector)
doc, err := c.Helper.PhaseConfigBundle().SelectOne(selector)
if err != nil {
return err
}

View File

@ -38,17 +38,16 @@ type Helper struct {
targetPath string
phaseRepoDir string
phaseEntryPointBasePath string
workDir string
inventory inventoryifc.Inventory
metadata *config.Metadata
config *config.Config
inventory inventoryifc.Inventory
metadata *config.Metadata
phaseConfigBundle document.Bundle
}
// NewHelper constructs metadata interface based on config
func NewHelper(cfg *config.Config) (ifc.Helper, error) {
helper := &Helper{
config: cfg,
}
helper := &Helper{}
var err error
helper.targetPath, err = cfg.CurrentContextTargetPath()
@ -63,20 +62,23 @@ func NewHelper(cfg *config.Config) (ifc.Helper, error) {
if err != nil {
return nil, err
}
helper.workDir, err = cfg.WorkDir()
if err != nil {
return nil, err
}
helper.phaseBundleRoot = filepath.Join(helper.targetPath, helper.phaseRepoDir, helper.metadata.PhaseMeta.Path)
helper.inventoryRoot = filepath.Join(helper.targetPath, helper.phaseRepoDir, helper.metadata.Inventory.Path)
helper.phaseEntryPointBasePath = filepath.Join(helper.targetPath, helper.phaseRepoDir,
helper.metadata.PhaseMeta.DocEntryPointPrefix)
helper.inventory = inventory.NewInventory(func() (*config.Config, error) { return cfg, nil })
if helper.phaseConfigBundle, err = document.NewBundleByPath(helper.phaseBundleRoot); err != nil {
return nil, err
}
return helper, nil
}
// Phase returns a phase APIObject based on phase selector
func (helper *Helper) Phase(phaseID ifc.ID) (*v1alpha1.Phase, error) {
bundle, err := document.NewBundleByPath(helper.phaseBundleRoot)
if err != nil {
return nil, err
}
phase := &v1alpha1.Phase{
ObjectMeta: v1.ObjectMeta{
Name: phaseID.Name,
@ -87,7 +89,7 @@ func (helper *Helper) Phase(phaseID ifc.ID) (*v1alpha1.Phase, error) {
if err != nil {
return nil, err
}
doc, err := bundle.SelectOne(selector)
doc, err := helper.phaseConfigBundle.SelectOne(selector)
if err != nil {
return nil, err
}
@ -101,11 +103,6 @@ func (helper *Helper) Phase(phaseID ifc.ID) (*v1alpha1.Phase, error) {
// Plan returns plan associated with a manifest
func (helper *Helper) Plan(planID ifc.ID) (*v1alpha1.PhasePlan, error) {
bundle, err := document.NewBundleByPath(helper.phaseBundleRoot)
if err != nil {
return nil, err
}
plan := &v1alpha1.PhasePlan{
ObjectMeta: v1.ObjectMeta{
Name: planID.Name,
@ -117,7 +114,7 @@ func (helper *Helper) Plan(planID ifc.ID) (*v1alpha1.PhasePlan, error) {
return nil, err
}
doc, err := bundle.SelectOne(selector)
doc, err := helper.phaseConfigBundle.SelectOne(selector)
if err != nil {
return nil, err
}
@ -130,18 +127,13 @@ func (helper *Helper) Plan(planID ifc.ID) (*v1alpha1.PhasePlan, error) {
// ListPhases returns all phases associated with manifest
func (helper *Helper) ListPhases(o ifc.ListPhaseOptions) ([]*v1alpha1.Phase, error) {
bundle, err := document.NewBundleByPath(helper.phaseBundleRoot)
if err != nil {
return nil, err
}
phase := &v1alpha1.Phase{}
selector, err := document.NewSelector().ByObject(phase, v1alpha1.Scheme)
if err != nil {
return nil, err
}
bundle, err = bundle.SelectBundle(selector)
bundle, err := helper.phaseConfigBundle.SelectBundle(selector)
if err != nil {
return nil, err
}
@ -210,18 +202,13 @@ func (helper *Helper) getDocsByPhasePlan(planID ifc.ID, bundle document.Bundle)
// ListPlans returns all phases associated with manifest
func (helper *Helper) ListPlans() ([]*v1alpha1.PhasePlan, error) {
bundle, err := document.NewBundleByPath(helper.phaseBundleRoot)
if err != nil {
return nil, err
}
plan := &v1alpha1.PhasePlan{}
selector, err := document.NewSelector().ByObject(plan, v1alpha1.Scheme)
if err != nil {
return nil, err
}
docs, err := bundle.Select(selector)
docs, err := helper.phaseConfigBundle.Select(selector)
if err != nil {
return nil, err
}
@ -239,18 +226,13 @@ func (helper *Helper) ListPlans() ([]*v1alpha1.PhasePlan, error) {
// ClusterMapAPIobj associated with the the manifest
func (helper *Helper) ClusterMapAPIobj() (*v1alpha1.ClusterMap, error) {
bundle, err := document.NewBundleByPath(helper.phaseBundleRoot)
if err != nil {
return nil, err
}
cMap := v1alpha1.DefaultClusterMap()
selector, err := document.NewSelector().ByObject(cMap, v1alpha1.Scheme)
if err != nil {
return nil, err
}
doc, err := bundle.SelectOne(selector)
doc, err := helper.phaseConfigBundle.SelectOne(selector)
if err != nil {
return nil, err
}
@ -272,10 +254,6 @@ func (helper *Helper) ClusterMap() (clustermap.ClusterMap, error) {
// ExecutorDoc returns executor document associated with phase
func (helper *Helper) ExecutorDoc(phaseID ifc.ID) (document.Document, error) {
bundle, err := document.NewBundleByPath(helper.phaseBundleRoot)
if err != nil {
return nil, err
}
phaseObj, err := helper.Phase(phaseID)
if err != nil {
return nil, err
@ -293,7 +271,7 @@ func (helper *Helper) ExecutorDoc(phaseID ifc.ID) (document.Document, error) {
ByGvk(refGVK.Group, refGVK.Version, refGVK.Kind).
ByName(phaseConfig.ExecutorRef.Name).
ByNamespace(phaseConfig.ExecutorRef.Namespace)
return bundle.SelectOne(selector)
return helper.phaseConfigBundle.SelectOne(selector)
}
// TargetPath returns manifest root
@ -324,12 +302,17 @@ func (helper *Helper) PhaseEntryPointBasePath() string {
return helper.phaseEntryPointBasePath
}
// WorkDir return working directory for aisrhipctl, creates it, if doesn't exist
func (helper *Helper) WorkDir() (string, error) {
return helper.config.WorkDir()
// WorkDir return working directory for airshipctl
func (helper *Helper) WorkDir() string {
return helper.workDir
}
// Inventory return inventory interface
func (helper *Helper) Inventory() (inventoryifc.Inventory, error) {
return helper.inventory, nil
}
// PhaseConfigBundle returns bundle based on phaseBundleRoot
func (helper *Helper) PhaseConfigBundle() document.Bundle {
return helper.phaseConfigBundle
}

View File

@ -41,6 +41,7 @@ func TestHelperPhase(t *testing.T) {
testCases := []struct {
name string
errContains string
helperErr bool
phaseID ifc.ID
config func(t *testing.T) *config.Config
@ -82,6 +83,7 @@ func TestHelperPhase(t *testing.T) {
return conf
},
errContains: "no such file or directory",
helperErr: true,
},
}
@ -89,9 +91,11 @@ func TestHelperPhase(t *testing.T) {
tt := test
t.Run(tt.name, func(t *testing.T) {
helper, err := phase.NewHelper(tt.config(t))
require.NoError(t, err)
if tt.helperErr {
require.Error(t, err)
return
}
require.NotNil(t, helper)
actualPhase, actualErr := helper.Phase(tt.phaseID)
if tt.errContains != "" {
require.Error(t, actualErr)
@ -112,6 +116,7 @@ func TestHelperPlan(t *testing.T) {
expectedPlan *v1alpha1.PhasePlan
planID ifc.ID
config func(t *testing.T) *config.Config
bundleErr bool
}{
{
name: "Valid Phase Plan",
@ -158,6 +163,7 @@ func TestHelperPlan(t *testing.T) {
return conf
},
errContains: "no such file or directory",
bundleErr: true,
},
}
@ -165,6 +171,10 @@ func TestHelperPlan(t *testing.T) {
tt := test
t.Run(tt.name, func(t *testing.T) {
helper, err := phase.NewHelper(tt.config(t))
if tt.bundleErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.NotNil(t, helper)
@ -187,6 +197,7 @@ func TestHelperListPhases(t *testing.T) {
phaseLen int
config func(t *testing.T) *config.Config
options ifc.ListPhaseOptions
bundleErr bool
}{
{
name: "Success phase list",
@ -201,6 +212,7 @@ func TestHelperListPhases(t *testing.T) {
return conf
},
errContains: "no such file or directory",
bundleErr: true,
},
{
name: "Success 0 phases",
@ -236,6 +248,10 @@ func TestHelperListPhases(t *testing.T) {
tt := test
t.Run(tt.name, func(t *testing.T) {
helper, err := phase.NewHelper(tt.config(t))
if tt.bundleErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.NotNil(t, helper)
@ -255,6 +271,7 @@ func TestHelperListPlans(t *testing.T) {
testCases := []struct {
name string
errContains string
bundleErr bool
expectedLen int
config func(t *testing.T) *config.Config
}{
@ -271,6 +288,7 @@ func TestHelperListPlans(t *testing.T) {
return conf
},
errContains: "no such file or directory",
bundleErr: true,
},
{
name: "Success 0 plans",
@ -287,6 +305,10 @@ func TestHelperListPlans(t *testing.T) {
tt := test
t.Run(tt.name, func(t *testing.T) {
helper, err := phase.NewHelper(tt.config(t))
if tt.bundleErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.NotNil(t, helper)
@ -306,6 +328,7 @@ func TestHelperClusterMapAPI(t *testing.T) {
testCases := []struct {
name string
errContains string
helperErr bool
expectedCMap *v1alpha1.ClusterMap
config func(t *testing.T) *config.Config
}{
@ -347,6 +370,7 @@ func TestHelperClusterMapAPI(t *testing.T) {
return conf
},
errContains: "no such file or directory",
helperErr: true,
},
{
name: "Error no cluster map",
@ -363,6 +387,10 @@ func TestHelperClusterMapAPI(t *testing.T) {
tt := test
t.Run(tt.name, func(t *testing.T) {
helper, err := phase.NewHelper(tt.config(t))
if tt.helperErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.NotNil(t, helper)
@ -423,6 +451,7 @@ func TestHelperExecutorDoc(t *testing.T) {
name string
errContains string
expectedExecutor string
helperErr bool
phaseID ifc.ID
config func(t *testing.T) *config.Config
@ -447,6 +476,7 @@ func TestHelperExecutorDoc(t *testing.T) {
return conf
},
errContains: "no such file or directory",
helperErr: true,
},
{
name: "Error get phase without executor",
@ -462,6 +492,10 @@ func TestHelperExecutorDoc(t *testing.T) {
tt := test
t.Run(tt.name, func(t *testing.T) {
helper, err := phase.NewHelper(tt.config(t))
if tt.helperErr {
require.Error(t, err)
return
}
require.NoError(t, err)
actualDoc, actualErr := helper.ExecutorDoc(tt.phaseID)
@ -535,8 +569,7 @@ func TestHelperWorkdir(t *testing.T) {
helper, err := phase.NewHelper(testConfig(t))
require.NoError(t, err)
require.NotNil(t, helper)
workDir, err := helper.WorkDir()
assert.NoError(t, err)
workDir := helper.WorkDir()
assert.Greater(t, len(workDir), 0)
}

View File

@ -26,7 +26,7 @@ type Helper interface {
TargetPath() string
PhaseRepoDir() string
DocEntryPointPrefix() string
WorkDir() (string, error)
WorkDir() string
Phase(phaseID ID) (*v1alpha1.Phase, error)
Plan(planID ID) (*v1alpha1.PhasePlan, error)
ListPhases(o ListPhaseOptions) ([]*v1alpha1.Phase, error)
@ -37,4 +37,5 @@ type Helper interface {
PhaseBundleRoot() string
Inventory() (ifc.Inventory, error)
PhaseEntryPointBasePath() string
PhaseConfigBundle() document.Bundle
}

View File

@ -104,12 +104,7 @@ func (fo *RenderCommand) RunE(cfgFactory config.Factory, out io.Writer) error {
}
func renderConfigBundle(out io.Writer, h ifc.Helper, sel document.Selector) error {
bundle, err := document.NewBundleByPath(h.PhaseBundleRoot())
if err != nil {
return err
}
bundle, err = bundle.SelectBundle(sel)
bundle, err := h.PhaseConfigBundle().SelectBundle(sel)
if err != nil {
return err
}

View File

@ -0,0 +1,4 @@
inventory:
path: "manifests/site/inventory"
phase:
path: "valid_site/phases"

View File

@ -0,0 +1,10 @@
apiVersion: airshipit.org/v1alpha1
kind: Phase
metadata:
name: capi_init
config:
executorRef:
apiVersion: airshipit.org/v1alpha1
kind: Clusterctl
name: clusterctl-v1
documentEntryPoint: valid_site/phases

View File

@ -0,0 +1,12 @@
apiVersion: airshipit.org/v1alpha1
kind: ClusterMap
metadata:
name: clusterctl-v1
map:
target:
parent: ephemeral
kubeconfigSources:
- type: bundle
ephemeral:
kubeconfigSources:
- type: bundle

View File

@ -0,0 +1,12 @@
apiVersion: airshipit.org/v1alpha1
kind: Clusterctl
metadata:
name: clusterctl-v1
action: init
init-options:
core-provider: "cluster-api:v0.3.3"
providers:
- name: "cluster-api"
type: "CoreProvider"
versions:
v0.3.3: manifests/function/capi/v0.3.3

View File

@ -0,0 +1,10 @@
apiVersion: airshipit.org/v1alpha1
kind: Phase
metadata:
name: kube_apply
config:
executorRef:
apiVersion: airshipit.org/v1alpha1
kind: KubernetesApply
name: kubernetes-apply
documentEntryPoint: valid_site/phases

View File

@ -0,0 +1,12 @@
---
apiVersion: airshipit.org/v1alpha1
kind: KubernetesApply
metadata:
labels:
airshipit.org/deploy-k8s: "false"
name: kubernetes-apply
config:
waitOptions:
timeout: 600
pruneOptions:
prune: false

View File

@ -0,0 +1,11 @@
resources:
- phaseplan.yaml
- some_phase.yaml
- some_exc.yaml
- capi_init.yaml
- clusterctl.yaml
- kubernetes_apply.yaml
- cluster_map.yaml
- phase_no_docentrypoint.yaml
- no_executor_phase.yaml
- kubeapply_phase.yaml

View File

@ -0,0 +1,7 @@
apiVersion: airshipit.org/v1alpha1
kind: Phase
metadata:
name: no_executor_phase
config:
documentEntryPoint: valid_site/phases

View File

@ -0,0 +1,9 @@
apiVersion: airshipit.org/v1alpha1
kind: Phase
metadata:
name: no_entry_point
config:
executorRef:
apiVersion: airshipit.org/v1alpha1
kind: SomeExecutor
name: executor-name

View File

@ -0,0 +1,37 @@
apiVersion: airshipit.org/v1alpha1
kind: PhasePlan
metadata:
name: phasePlan
phases:
- name: remotedirect
- name: initinfra
- name: some_phase
- name: capi_init
---
apiVersion: airshipit.org/v1alpha1
kind: PhasePlan
metadata:
name: init
phases:
- name: capi_init
---
apiVersion: airshipit.org/v1alpha1
kind: PhasePlan
metadata:
name: some_plan
phases:
- name: some_phase
---
apiVersion: airshipit.org/v1alpha1
kind: PhasePlan
metadata:
name: plan_invalid_phase
phases:
- name: no_entry_point
---
apiVersion: airshipit.org/v1alpha1
kind: PhasePlan
metadata:
name: phase_not_exist
phases:
- name: non_existent_name

View File

@ -0,0 +1,13 @@
apiVersion: airshipit.org/v1alpha1
kind: SomeExecutor
metadata:
labels:
airshipit.org/deploy-k8s: "false"
name: executor-name
init-options:
core-provider: "cluster-api:v0.3.3"
providers:
- name: "cluster-api"
type: "CoreProvider"
versions:
v0.3.3: manifests/function/capi/v0.3.3

View File

@ -0,0 +1,10 @@
apiVersion: airshipit.org/v1alpha1
kind: Phase
metadata:
name: some_phase
clusterName: some_cluster
config:
executorRef:
apiVersion: airshipit.org/v1alpha1
kind: Does not exist
name: executor-name

View File

@ -0,0 +1,3 @@
phase:
path: "valid_site_with_doc_prefix/phases"
docEntryPointPrefix: "valid_site_with_doc_prefix/phases"

View File

@ -0,0 +1,2 @@
resources:
- sample.yaml

View File

@ -0,0 +1,6 @@
apiVersion: airshipit.org/v1alpha1
kind: Phase
metadata:
name: sample
config:
documentEntryPoint: entrypoint