f8f6f8be27
This commit moves Write function to separate yaml package, and makes it available to anyone for dumping documents in single file, with correct yaml separators '---', '...'. This will allow, for example dumping of filtered from bundle documents to disk or any writer, like Stdout, for debugging purposes. Specifically it will be used as part of `airshipctl cluster initinfra` command as a buffer for delivering resources to kubernetes cluster. Change-Id: I780e3f2d2ff446b8787153f500d04d10487ed71b
241 lines
7.0 KiB
Go
241 lines
7.0 KiB
Go
package document
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct"
|
|
"sigs.k8s.io/kustomize/v3/k8sdeps/transformer"
|
|
"sigs.k8s.io/kustomize/v3/k8sdeps/validator"
|
|
"sigs.k8s.io/kustomize/v3/pkg/fs"
|
|
"sigs.k8s.io/kustomize/v3/pkg/gvk"
|
|
"sigs.k8s.io/kustomize/v3/pkg/loader"
|
|
"sigs.k8s.io/kustomize/v3/pkg/plugins"
|
|
"sigs.k8s.io/kustomize/v3/pkg/resmap"
|
|
"sigs.k8s.io/kustomize/v3/pkg/resource"
|
|
"sigs.k8s.io/kustomize/v3/pkg/target"
|
|
"sigs.k8s.io/kustomize/v3/pkg/types"
|
|
|
|
utilyaml "opendev.org/airship/airshipctl/pkg/util/yaml"
|
|
)
|
|
|
|
// KustomizeBuildOptions contain the options for running a Kustomize build on a bundle
|
|
type KustomizeBuildOptions struct {
|
|
KustomizationPath string
|
|
OutputPath string
|
|
LoadRestrictor loader.LoadRestrictorFunc
|
|
OutOrder int
|
|
}
|
|
|
|
// BundleFactory contains the objects within a bundle
|
|
type BundleFactory struct {
|
|
KustomizeBuildOptions
|
|
resmap.ResMap
|
|
fs.FileSystem
|
|
}
|
|
|
|
// Bundle interface provides the specification for a bundle implementation
|
|
type Bundle interface {
|
|
Write(out io.Writer) error
|
|
GetKustomizeResourceMap() resmap.ResMap
|
|
SetKustomizeResourceMap(resmap.ResMap) error
|
|
GetKustomizeBuildOptions() KustomizeBuildOptions
|
|
SetKustomizeBuildOptions(KustomizeBuildOptions) error
|
|
SetFileSystem(fs.FileSystem) error
|
|
GetFileSystem() fs.FileSystem
|
|
Select(selector types.Selector) ([]Document, error)
|
|
GetByGvk(string, string, string) ([]Document, error)
|
|
GetByName(string) (Document, error)
|
|
GetByAnnotation(string) ([]Document, error)
|
|
GetByLabel(string) ([]Document, error)
|
|
GetAllDocuments() ([]Document, error)
|
|
}
|
|
|
|
// NewBundle is a convenience function to create a new bundle
|
|
// Over time, it will evolve to support allowing more control
|
|
// for kustomize plugins
|
|
func NewBundle(fSys fs.FileSystem, kustomizePath string, outputPath string) (Bundle, error) {
|
|
|
|
var options = KustomizeBuildOptions{
|
|
KustomizationPath: kustomizePath,
|
|
OutputPath: outputPath,
|
|
LoadRestrictor: loader.RestrictionRootOnly,
|
|
OutOrder: 0,
|
|
}
|
|
|
|
// init an empty bundle factory
|
|
var bundle Bundle = &BundleFactory{}
|
|
|
|
// set the fs and build options we will use
|
|
bundle.SetFileSystem(fSys)
|
|
bundle.SetKustomizeBuildOptions(options)
|
|
|
|
// boiler plate to allow us to run Kustomize build
|
|
uf := kunstruct.NewKunstructuredFactoryImpl()
|
|
pf := transformer.NewFactoryImpl()
|
|
rf := resmap.NewFactory(resource.NewFactory(uf), pf)
|
|
v := validator.NewKustValidator()
|
|
|
|
pluginConfig := plugins.DefaultPluginConfig()
|
|
pl := plugins.NewLoader(pluginConfig, rf)
|
|
|
|
ldr, err := loader.NewLoader(
|
|
bundle.GetKustomizeBuildOptions().LoadRestrictor, v, bundle.GetKustomizeBuildOptions().KustomizationPath, fSys)
|
|
if err != nil {
|
|
return bundle, err
|
|
}
|
|
defer ldr.Cleanup()
|
|
kt, err := target.NewKustTarget(ldr, rf, pf, pl)
|
|
if err != nil {
|
|
return bundle, err
|
|
}
|
|
|
|
// build a resource map of kustomize rendered objects
|
|
m, err := kt.MakeCustomizedResMap()
|
|
bundle.SetKustomizeResourceMap(m)
|
|
if err != nil {
|
|
return bundle, err
|
|
}
|
|
|
|
return bundle, nil
|
|
|
|
}
|
|
|
|
// GetKustomizeResourceMap returns a Kustomize Resource Map for this bundle
|
|
func (b *BundleFactory) GetKustomizeResourceMap() resmap.ResMap {
|
|
return b.ResMap
|
|
}
|
|
|
|
// SetKustomizeResourceMap allows us to set the populated resource map for this bundle. In
|
|
// the future, it may modify it before saving it.
|
|
func (b *BundleFactory) SetKustomizeResourceMap(r resmap.ResMap) error {
|
|
b.ResMap = r
|
|
return nil
|
|
}
|
|
|
|
// GetKustomizeBuildOptions returns the build options object used to generate the resource map
|
|
// for this bundle
|
|
func (b *BundleFactory) GetKustomizeBuildOptions() KustomizeBuildOptions {
|
|
return b.KustomizeBuildOptions
|
|
}
|
|
|
|
// SetKustomizeBuildOptions sets the build options to be used for this bundle. In
|
|
// the future, it may perform some basic validations.
|
|
func (b *BundleFactory) SetKustomizeBuildOptions(k KustomizeBuildOptions) error {
|
|
b.KustomizeBuildOptions = k
|
|
return nil
|
|
}
|
|
|
|
// SetFileSystem sets the filesystem that will be used by this bundle
|
|
func (b *BundleFactory) SetFileSystem(fSys fs.FileSystem) error {
|
|
b.FileSystem = fSys
|
|
return nil
|
|
}
|
|
|
|
// GetFileSystem gets the filesystem that will be used by this bundle
|
|
func (b *BundleFactory) GetFileSystem() fs.FileSystem {
|
|
return b.FileSystem
|
|
}
|
|
|
|
// GetAllDocuments returns all documents in this bundle
|
|
func (b *BundleFactory) GetAllDocuments() ([]Document, error) {
|
|
docSet := []Document{}
|
|
for _, res := range b.ResMap.Resources() {
|
|
// Construct Bundle document for each resource returned
|
|
doc, err := NewDocument(res)
|
|
if err != nil {
|
|
return docSet, err
|
|
}
|
|
docSet = append(docSet, doc)
|
|
}
|
|
return docSet, nil
|
|
}
|
|
|
|
// GetByName finds a document by name, error if more than one document found
|
|
// or if no documents found
|
|
func (b *BundleFactory) GetByName(name string) (Document, error) {
|
|
resSet := []*resource.Resource{}
|
|
for _, res := range b.ResMap.Resources() {
|
|
if res.GetName() == name {
|
|
resSet = append(resSet, res)
|
|
}
|
|
}
|
|
// alanmeadows(TODO): improve this and other error potentials by
|
|
// by adding strongly typed errors
|
|
switch found := len(resSet); {
|
|
case found == 0:
|
|
return &DocumentFactory{}, fmt.Errorf("No documents found with name %s", name)
|
|
case found > 1:
|
|
return &DocumentFactory{}, fmt.Errorf("More than one document found with name %s", name)
|
|
default:
|
|
return NewDocument(resSet[0])
|
|
}
|
|
}
|
|
|
|
// Select offers a direct interface to pass a Kustomize Selector to the bundle
|
|
// returning Documents that match the criteria
|
|
func (b *BundleFactory) Select(selector types.Selector) ([]Document, error) {
|
|
|
|
// use the kustomize select method
|
|
resources, err := b.ResMap.Select(selector)
|
|
if err != nil {
|
|
return []Document{}, err
|
|
}
|
|
|
|
// Construct Bundle document for each resource returned
|
|
docSet := []Document{}
|
|
for _, res := range resources {
|
|
doc, err := NewDocument(res)
|
|
if err != nil {
|
|
return docSet, err
|
|
}
|
|
docSet = append(docSet, doc)
|
|
}
|
|
return docSet, err
|
|
}
|
|
|
|
// GetByAnnotation is a convenience method to get documents for a particular annotation
|
|
func (b *BundleFactory) GetByAnnotation(annotation string) ([]Document, error) {
|
|
|
|
// Construct kustomize annotation selector
|
|
selector := types.Selector{AnnotationSelector: annotation}
|
|
|
|
// pass it to the selector
|
|
return b.Select(selector)
|
|
|
|
}
|
|
|
|
// GetByLabel is a convenience method to get documents for a particular label
|
|
func (b *BundleFactory) GetByLabel(label string) ([]Document, error) {
|
|
|
|
// Construct kustomize annotation selector
|
|
selector := types.Selector{LabelSelector: label}
|
|
|
|
// pass it to the selector
|
|
return b.Select(selector)
|
|
|
|
}
|
|
|
|
// GetByGvk is a convenience method to get documents for a particular Gvk tuple
|
|
func (b *BundleFactory) GetByGvk(group, version, kind string) ([]Document, error) {
|
|
|
|
// Construct kustomize gvk object
|
|
g := gvk.Gvk{Group: group, Version: version, Kind: kind}
|
|
|
|
// pass it to the selector
|
|
selector := types.Selector{Gvk: g}
|
|
return b.Select(selector)
|
|
|
|
}
|
|
|
|
// Write will write out the entire bundle resource map
|
|
func (b *BundleFactory) Write(out io.Writer) error {
|
|
for _, res := range b.ResMap.Resources() {
|
|
err := utilyaml.WriteOut(out, res)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|