Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ snapcrafts:
must be in the current working directory and named 'concierge.yaml', or the path specified using
the '-c' flag.

There are 3 presets available by default: 'machine', 'k8s' and 'dev'.
Several presets are available by default to cover common charm development and testing scenarios.

Some aspects of presets and config files can be overridden using flags such as '--juju-channel'.
Each of the override flags has an environment variable equivalent, such as
Expand All @@ -49,6 +49,21 @@ snapcrafts:
- source: .github/concierge.png
destination: concierge.png
mode: 0644
- source: presets/crafts.yaml
destination: presets/crafts.yaml
mode: 0644
- source: presets/dev.yaml
destination: presets/dev.yaml
mode: 0644
- source: presets/k8s.yaml
destination: presets/k8s.yaml
mode: 0644
- source: presets/machine.yaml
destination: presets/machine.yaml
mode: 0644
- source: presets/microk8s.yaml
destination: presets/microk8s.yaml
mode: 0644

checksum:
name_template: "checksums.txt"
Expand Down
14 changes: 9 additions & 5 deletions cmd/prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"fmt"
"strings"

"github.com/canonical/concierge/internal/concierge"
"github.com/canonical/concierge/internal/config"
Expand All @@ -10,23 +11,26 @@ import (

// prepareCmd constructs the `prepare` subcommand
func prepareCmd() *cobra.Command {
presetNames := config.ValidPresets()
presetList := strings.Join(presetNames, ", ")

cmd := &cobra.Command{
Use: "prepare",
Short: "Provision the machine according to the configuration.",
Long: `Provision the machine according to the configuration.
Long: fmt.Sprintf(`Provision the machine according to the configuration.

Configuration is by flags/environment variables, or by configuration file. The configuration file
must be in the current working directory and named 'concierge.yaml', or the path specified using
the '-c' flag.

There are 3 presets available by default: 'machine', 'k8s' and 'dev'.
Available presets: %s.

Some aspects of presets and config files can be overridden using flags such as '--juju-channel'.
Each of the override flags has an environment variable equivalent,
Each of the override flags has an environment variable equivalent,
such as 'CONCIERGE_JUJU_CHANNEL'.

More information at https://github.com/canonical/concierge.
`,
`, presetList),
SilenceErrors: true,
SilenceUsage: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -60,7 +64,7 @@ More information at https://github.com/canonical/concierge.

flags := cmd.Flags()
flags.StringP("config", "c", "", "path to a specific config file to use")
flags.StringP("preset", "p", "", "config preset to use (k8s | machine | dev)")
flags.StringP("preset", "p", "", "config preset to use ("+strings.Join(presetNames, " | ")+")")
flags.Bool("disable-juju", false, "disable the installation and bootstrap of juju")
flags.String("juju-channel", "", "override the snap channel for juju")
flags.String("k8s-channel", "", "override snap channel for the k8s snap")
Expand Down
199 changes: 48 additions & 151 deletions internal/config/presets.go
Original file line number Diff line number Diff line change
@@ -1,162 +1,59 @@
package config

import "fmt"

// Preset returns a configuration preset by name.
func Preset(preset string) (*Config, error) {
switch preset {
case "k8s":
return k8sPreset, nil
case "microk8s":
return microk8sPreset, nil
case "machine":
return machinePreset, nil
case "dev":
return devPreset, nil
case "crafts":
return craftsPreset, nil
default:
return nil, fmt.Errorf("unknown preset '%s'", preset)
import (
"bytes"
"errors"
"fmt"
"io/fs"
"sort"
"strings"

"github.com/canonical/concierge/presets"
"github.com/spf13/viper"
)

// ValidPresets returns the sorted list of available preset names.
func ValidPresets() []string {
entries, err := presets.FS.ReadDir(".")
if err != nil {
return nil
}
}

// defaultJujuConfig is the default Juju config for all presets.
var defaultJujuConfig jujuConfig = jujuConfig{
Disable: false,
ModelDefaults: map[string]string{
"test-mode": "true",
"automatically-retry-hooks": "false",
},
}

// defaultPackages is the set of packages installed for all presets.
var defaultPackages []string = []string{
"gnome-keyring",
"python3-pip",
"python3-venv",
}

// defaultSnaps is the set of snaps installed for all presets.
var defaultSnaps map[string]SnapConfig = map[string]SnapConfig{
"charmcraft": {Channel: "latest/stable"},
"jq": {Channel: "latest/stable"},
"yq": {Channel: "latest/stable"},
}

// defaultLXDConfig is the standard LXD config used throughout presets.
var defaultLXDConfig lxdConfig = lxdConfig{
Enable: true,
Bootstrap: true,
}

// defaultMicroK8sConfig is the standard MicroK8s config used throughout presets.
var defaultMicroK8sConfig microk8sConfig = microk8sConfig{
Enable: true,
Bootstrap: true,
Addons: []string{
"hostpath-storage",
"dns",
"rbac",
"metallb:10.64.140.43-10.64.140.49",
},
}

// defaultK8sConfig is the standard K8s config used throughout presets.
var defaultK8sConfig k8sConfig = k8sConfig{
Enable: true,
Bootstrap: true,
BootstrapConstraints: map[string]string{"root-disk": "2G"},
Features: map[string]map[string]string{
"load-balancer": {
"l2-mode": "true",
"cidrs": "10.43.45.0/28",
},
"local-storage": {},
"network": {},
},
}

// machinePreset is a configuration preset designed to be used when testing
// machine charms.
var machinePreset *Config = &Config{
Juju: defaultJujuConfig,
Providers: providerConfig{
LXD: defaultLXDConfig,
},
Host: hostConfig{
Packages: defaultPackages,
Snaps: MergeMaps(defaultSnaps, map[string]SnapConfig{
"snapcraft": {Channel: "latest/stable"},
}),
},
var names []string
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(e.Name(), ".yaml") {
names = append(names, strings.TrimSuffix(e.Name(), ".yaml"))
}
}
sort.Strings(names)
return names
}

// k8sPreset is a configuration preset designed to be used when testing
// k8s charms.
var k8sPreset *Config = &Config{
Juju: defaultJujuConfig,
Providers: providerConfig{
// Enable LXD so charms can be built, but don't bootstrap onto it.
LXD: lxdConfig{Enable: true},
K8s: defaultK8sConfig,
},
Host: hostConfig{
Packages: defaultPackages,
Snaps: MergeMaps(defaultSnaps, map[string]SnapConfig{
"rockcraft": {Channel: "latest/stable"},
}),
},
// Preset returns a configuration preset by name.
func Preset(preset string) (*Config, error) {
filename := preset + ".yaml"
data, err := presets.FS.ReadFile(filename)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil, fmt.Errorf("unknown preset '%s'", preset)
}
return nil, fmt.Errorf("failed to read preset '%s': %w", preset, err)
}
return loadPreset(data)
}

// microk8sPreset is a configuration preset designed to be used when testing
// k8s charms.
var microk8sPreset *Config = &Config{
Juju: defaultJujuConfig,
Providers: providerConfig{
// Enable LXD so charms can be built, but don't bootstrap onto it.
LXD: lxdConfig{Enable: true},
MicroK8s: defaultMicroK8sConfig,
},
Host: hostConfig{
Packages: defaultPackages,
Snaps: MergeMaps(defaultSnaps, map[string]SnapConfig{
"rockcraft": {Channel: "latest/stable"},
}),
},
}
// loadPreset parses YAML data into a Config using a fresh Viper instance.
func loadPreset(data []byte) (*Config, error) {
v := viper.New()
v.SetConfigType("yaml")

// devPreset combines both the LXD and K8s presets, designed to be used by
// developers when iterating on charms.
var devPreset *Config = &Config{
Juju: defaultJujuConfig,
Providers: providerConfig{
LXD: defaultLXDConfig,
K8s: defaultK8sConfig,
},
Host: hostConfig{
Packages: defaultPackages,
Snaps: MergeMaps(defaultSnaps, map[string]SnapConfig{
"rockcraft": {Channel: "latest/stable"},
"snapcraft": {Channel: "latest/stable"},
"jhack": {Channel: "latest/stable", Connections: []string{"jhack:dot-local-share-juju"}},
}),
},
}
if err := v.ReadConfig(bytes.NewReader(data)); err != nil {
return nil, fmt.Errorf("failed to parse preset: %w", err)
}

// craftsPreset installs each of the crafts, and configures LXD, but disables Juju.
// Useful for workflows where only artifacts need to be built.
var craftsPreset *Config = &Config{
Juju: jujuConfig{
Disable: true,
},
Providers: providerConfig{
LXD: defaultLXDConfig,
},
Host: hostConfig{
Packages: defaultPackages,
Snaps: MergeMaps(defaultSnaps, map[string]SnapConfig{
"rockcraft": {Channel: "latest/stable"},
"snapcraft": {Channel: "latest/stable"},
}),
},
conf := &Config{}
if err := v.Unmarshal(conf); err != nil {
return nil, fmt.Errorf("failed to unmarshal preset: %w", err)
}
return conf, nil
}
Loading