Skip to content

Commit

Permalink
feat: enable STDIN apply and destroy using RG inventory (#2709)
Browse files Browse the repository at this point in the history
This commit enables actuation from STDIN using inventory information
that is stored in a ResourceGroup file.

This feature is currently behind a feature gate and will be exposed to
users as a CLI flag in a future commit/PR.
  • Loading branch information
rquitales authored Feb 14, 2022
1 parent 5169954 commit 10868bd
Show file tree
Hide file tree
Showing 11 changed files with 401 additions and 49 deletions.
3 changes: 2 additions & 1 deletion internal/cmdapply/cmdapply.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ type Runner struct {
pruneTimeout time.Duration
inventoryPolicyString string
dryRun bool
rgFile string
printStatusEvents bool

inventoryPolicy inventory.InventoryPolicy
Expand Down Expand Up @@ -166,7 +167,7 @@ func (r *Runner) runE(c *cobra.Command, args []string) error {
}
}

objs, inv, err := live.Load(r.factory, path, c.InOrStdin())
objs, inv, err := live.Load(r.factory, path, r.rgFile, c.InOrStdin())
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion internal/cmddestroy/cmddestroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ type Runner struct {
output string
inventoryPolicyString string
dryRun bool
rgFile string
printStatusEvents bool

inventoryPolicy inventory.InventoryPolicy
Expand Down Expand Up @@ -128,7 +129,7 @@ func (r *Runner) runE(c *cobra.Command, args []string) error {
}
}

_, inv, err := live.Load(r.factory, path, c.InOrStdin())
_, inv, err := live.Load(r.factory, path, r.rgFile, c.InOrStdin())
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cmdmigrate/migratecmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ func (mr *MigrateRunner) migrateObjs(rgInvClient inventory.InventoryClient,
}
}

_, inv, err := live.Load(mr.factory, path, reader)
_, inv, err := live.Load(mr.factory, path, mr.rgFile, reader)
if err != nil {
return err
}
Expand Down
19 changes: 12 additions & 7 deletions internal/pkg/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,23 +741,28 @@ func ReadRGFile(path, filename string) (*rgfilev1alpha1.ResourceGroup, error) {
}
defer f.Close()

rg := &rgfilev1alpha1.ResourceGroup{}
c, err := io.ReadAll(f)
rg, err := DecodeRGFile(f)
if err != nil {
return nil, &RGError{
Path: types.UniquePath(path),
Err: err,
}
}
return rg, nil
}

// DecodeRGFile converts a string reader into structured a ResourceGroup object.
func DecodeRGFile(in io.Reader) (*rgfilev1alpha1.ResourceGroup, error) {
rg := &rgfilev1alpha1.ResourceGroup{}
c, err := io.ReadAll(in)
if err != nil {
return rg, err
}

d := yaml.NewDecoder(bytes.NewBuffer(c))
d.KnownFields(true)
if err := d.Decode(rg); err != nil {
return nil, &RGError{
Path: types.UniquePath(path),
Err: err,
}
return rg, err
}
return rg, nil

}
52 changes: 52 additions & 0 deletions internal/testutil/pkgbuilder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"text/template"

kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
rgfilev1alpha1 "github.com/GoogleContainerTools/kpt/pkg/api/resourcegroup/v1alpha1"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
Expand Down Expand Up @@ -92,13 +93,21 @@ var (
type pkg struct {
Kptfile *Kptfile

RGFile *RGFile

resources []resourceInfoWithMutators

files map[string]string

subPkgs []*SubPkg
}

// WithRGFile configures the current package to have a resourcegroup file.
func (rp *RootPkg) WithRGFile(rg *RGFile) *RootPkg {
rp.pkg.RGFile = rg
return rp
}

// withKptfile configures the current package to have a Kptfile. Only
// zero or one Kptfiles are accepted.
func (p *pkg) withKptfile(kf ...*Kptfile) {
Expand Down Expand Up @@ -300,6 +309,22 @@ func (sp *SubPkg) WithSubPackages(ps ...*SubPkg) *SubPkg {
return sp
}

// RGFile represents a minimal resourcegroup.
type RGFile struct {
Name, Namespace, ID string
}

func NewRGFile() *RGFile {
return &RGFile{}
}

func (rg *RGFile) WithInventory(inv Inventory) *RGFile {
rg.Name = inv.Name
rg.Namespace = inv.Namespace
rg.ID = inv.ID
return rg
}

// Kptfile represents the Kptfile of a package.
type Kptfile struct {
Upstream *Upstream
Expand Down Expand Up @@ -476,6 +501,16 @@ func buildPkg(pkgPath string, pkg *pkg, pkgName string, reposInfo ReposInfo) err
}
}

if pkg.RGFile != nil {
content := buildRGFile(pkg)

err := ioutil.WriteFile(filepath.Join(pkgPath, rgfilev1alpha1.RGFileName),
[]byte(content), 0600)
if err != nil {
return err
}
}

for _, ri := range pkg.resources {
m := ri.resourceInfo.manifest
r := yaml.MustParse(m)
Expand Down Expand Up @@ -510,6 +545,23 @@ func buildPkg(pkgPath string, pkg *pkg, pkgName string, reposInfo ReposInfo) err
return nil
}

// buildRGFile creates a ResourceGroup inventory file.
func buildRGFile(pkg *pkg) string {
tmp := rgfilev1alpha1.ResourceGroup{ResourceMeta: rgfilev1alpha1.DefaultMeta}
tmp.ObjectMeta.Name = pkg.RGFile.Name
tmp.ObjectMeta.Namespace = pkg.RGFile.Namespace
if pkg.RGFile.ID != "" {
tmp.ObjectMeta.Labels = map[string]string{rgfilev1alpha1.RGInventoryIDLabel: pkg.RGFile.ID}
}

b, err := yaml.MarshalWithOptions(tmp, &yaml.EncoderOptions{SeqIndent: yaml.WideSequenceStyle})
if err != nil {
panic(err)
}

return string(b)
}

// TODO: Consider using the Kptfile struct for this instead of a template.
var kptfileTemplate = `apiVersion: kpt.dev/v1
kind: Kptfile
Expand Down
7 changes: 7 additions & 0 deletions pkg/api/kptfile/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,10 @@ type Inventory struct {
Labels map[string]string `yaml:"labels,omitempty" json:"labels,omitempty"`
Annotations map[string]string `yaml:"annotations,omitempty" json:"annotations,omitempty"`
}

func (i Inventory) IsValid() bool {
// Name and Namespace are required inventory fields, so we check these 2 fields.
// InventoryID is an optional field since we only store it locally if the user
// specifies one.
return i.Name != "" && i.Namespace != ""
}
Loading

0 comments on commit 10868bd

Please sign in to comment.