Skip to content
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