Skip to content

Commit

Permalink
#208. ADD packager/compose.go: Created compose logic for imported com…
Browse files Browse the repository at this point in the history
…ponents and nested import components. UPDATE types.go: Added ZarfImport type with a path variable as the associated type with ZarfComponent.Import field (this sets up sha verification additions in the future, still need team imput). UPDATE Packager/Common.go: pulled confirming optional component logic out of getValidComponents to play with composed package validation (need to validate expected behavior). UPDATE Packager/Create.go: Replaced the initial compose logic with call to GetComposedAssets(). ADD examples/compose-example: a simple composition example for explicit example.
  • Loading branch information
mike-winberry committed Feb 28, 2022
1 parent c602e49 commit 116bc26
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 35 deletions.
5 changes: 5 additions & 0 deletions cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ func GetSeedImages() []string {
}
}

// SetSeedImages sets the list of image string specified in the package.
func SetSeedImages(seedImages []string) {
config.Seed = seedImages
}

func GetPackageName() string {
metadata := GetMetaData()
if metadata.Uncompressed {
Expand Down
31 changes: 18 additions & 13 deletions cli/internal/packager/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,7 @@ func getValidComponents(allComponents []types.ZarfComponent, requestedComponentN
}
}
} else {
// Present the users with the component details one more time
displayComponent := component
displayComponent.Description = ""
content, _ := yaml.Marshal(displayComponent)
utils.ColorPrintYAML(string(content))
message.Question(fmt.Sprintf("%s: %s", component.Name, component.Description))

// Since no requested components were provided, prompt the user
prompt := &survey.Confirm{
Message: "Deploy this component?",
Default: component.Default,
}
_ = survey.AskOne(prompt, &confirmComponent)
confirmComponent = ConfirmOptionalComponent(component)
}
}

Expand Down Expand Up @@ -150,6 +138,23 @@ func getValidComponents(allComponents []types.ZarfComponent, requestedComponentN
return validComponentsList
}

// Confirm optional component
func ConfirmOptionalComponent(component types.ZarfComponent) (confirmComponent bool) {
displayComponent := component
displayComponent.Description = ""
content, _ := yaml.Marshal(displayComponent)
utils.ColorPrintYAML(string(content))
message.Question(fmt.Sprintf("%s: %s", component.Name, component.Description))

// Since no requested components were provided, prompt the user
prompt := &survey.Confirm{
Message: "Deploy this component?",
Default: component.Default,
}
_ = survey.AskOne(prompt, &confirmComponent)
return confirmComponent
}

// HandleIfURL If provided package is a URL download it to a temp directory
func HandleIfURL(packagePath string, shasum string, insecureDeploy bool) (string, func()) {
// Check if the user gave us a remote package
Expand Down
94 changes: 94 additions & 0 deletions cli/internal/packager/compose.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package packager

import (
"github.com/defenseunicorns/zarf/cli/config"
"github.com/defenseunicorns/zarf/cli/internal/utils"
"github.com/defenseunicorns/zarf/cli/types"
)

func GetComposedAssets() (components []types.ZarfComponent, seedImages []string) {
for _, component := range config.GetComponents() {
// Build components list by expanding imported components.
if hasSubPackage(&component) {
importedComponents, importedImages := getSubPackageAssets(component)
components = append(components, importedComponents...)
seedImages = append(seedImages, importedImages...)

} else {
components = append(components, component)
}
}
// Update the parent package config with the expanded sub components and seed images.
// This is important when the deploy package is created.
config.SetComponents(components)
config.SetSeedImages(seedImages)
return components, seedImages
}

// Get the sub package components/seed images to add to parent assets, recurses on sub imports.
func getSubPackageAssets(importComponent types.ZarfComponent) (components []types.ZarfComponent, seedImages []string) {
importedPackage := getSubPackage(&importComponent)
seedImages = importedPackage.Seed
for _, componentToCompose := range importedPackage.Components {
if hasSubPackage(&componentToCompose) {
subComp, subImage := getSubPackageAssets(componentToCompose)
components = append(components, subComp...)
seedImages = append(seedImages, subImage...)
} else {
prepComponentToCompose(&componentToCompose, importedPackage.Metadata.Name, importComponent.Import.Path)
components = append(components, componentToCompose)
}
}
return components, seedImages
}

// Confirms inclusion of SubPackage. Need team input.
func shouldAddImportedPackage(component *types.ZarfComponent) bool {
return hasSubPackage(component) && (component.Required || ConfirmOptionalComponent(*component))
}

// returns true if import has url
func hasSubPackage(component *types.ZarfComponent) bool {
return len(component.Import.Path) > 0
}

// Reads the locally imported zarf.yaml
func getSubPackage(component *types.ZarfComponent) (importedPackage types.ZarfPackage) {
utils.ReadYaml(component.Import.Path+"zarf.yaml", &importedPackage)
return importedPackage
}

// Updates the name and sets all local asset paths relative to the importing package.
func prepComponentToCompose(component *types.ZarfComponent, parentPackageName string, importPath string) {
component.Name = parentPackageName + "-" + component.Name

// Add import path to local component files.
for idx, file := range component.Files {
if !utils.IsUrl(file.Source) {
component.Files[idx].Source = importPath + file.Source
}
}

// Add import path to local chart values files.
for chartIndex, chart := range component.Charts {
for valuesIndex, valuesFile := range chart.ValuesFiles {
if !utils.IsUrl(valuesFile) {
component.Charts[chartIndex].ValuesFiles[valuesIndex] = importPath + valuesFile
}
}
}

// Add import path to local manifest files and kustomizations
for manifestIndex, manifest := range component.Manifests {
for fileIndex, file := range manifest.Files {
if !utils.IsUrl(file) {
component.Manifests[manifestIndex].Files[fileIndex] = importPath + file
}
}
for kustomizationIndex, kustomization := range manifest.Kustomizations {
if !utils.IsUrl(kustomization) {
component.Manifests[manifestIndex].Kustomizations[kustomizationIndex] = importPath + kustomization
}
}
}
}
18 changes: 1 addition & 17 deletions cli/internal/packager/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,13 @@ func Create() {
tempPath := createPaths()
defer tempPath.clean()

components, seedImages := GetComposedAssets()
packageName := config.GetPackageName()
dataInjections := config.GetDataInjections()
seedImages := config.GetSeedImages()
components := []types.ZarfComponent{}
configFile := tempPath.base + "/zarf.yaml"

config.SetAcrch()

for _, component := range config.GetComponents() {
if len(component.Import) > 0 {
importedPackage := types.ZarfPackage{}
utils.ReadYaml(component.Import+"zarf.yaml", &importedPackage)
seedImages = append(seedImages, importedPackage.Seed...)
for _, composedComponent := range importedPackage.Components {
composedComponent.Name = importedPackage.Metadata.Name + "-" + composedComponent.Name
components = append(components, composedComponent)
}
} else {
components = append(components, component)
}
}
config.SetComponents(components)

// Save the transformed config
if err := config.BuildConfig(configFile); err != nil {
message.Fatalf(err, "Unable to write the %s file", configFile)
Expand Down
9 changes: 7 additions & 2 deletions cli/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ type ZarfComponent struct {
// Scripts are custom commands that run before or after package deployment
Scripts ZarfComponentScripts `yaml:"scripts,omitempty"`

// Import refers to another zarf.yml package.
Import string `yaml:"import,omitempty"`
// Import refers to another zarf.yaml package.
Import ZarfImport `yaml:"import,omitempty"`
}

// ZarfManifest defines raw manifests Zarf will deploy as a helm chart
Expand Down Expand Up @@ -144,3 +144,8 @@ type ZarfDeployOptions struct {
Components string
ApplianceMode bool
}

// ZarfImport structure for including imported zarf packages
type ZarfImport struct {
Path string `yaml:"path"`
}
14 changes: 14 additions & 0 deletions examples/compose-example/zarf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
kind: ZarfPackageConfig
metadata:
name: compose-example
description: "Demo Zarf package composability"

components:
- name: flux
required: false
import:
path: '../flux/'
- name: games
required: true
import:
path: '../game/'
3 changes: 0 additions & 3 deletions examples/game/zarf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ metadata:
description: "Demo Zarf appliance mode with some dos games"

components:
- name: flux
required: false
import: '../flux/'
- name: baseline
required: true
manifests:
Expand Down

0 comments on commit 116bc26

Please sign in to comment.