Skip to content
This repository has been archived by the owner on May 12, 2022. It is now read-only.

Commit

Permalink
Bring back local charts via the command line as --chart-path
Browse files Browse the repository at this point in the history
  • Loading branch information
John Esmet committed Jan 17, 2019
1 parent d6f262c commit bf6a8d0
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 44 deletions.
80 changes: 65 additions & 15 deletions ankh/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -825,14 +825,19 @@ func main() {
}

app.Command("explain", "Explain how an Ankh file would be applied to a Kubernetes cluster", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [--chart]"
cmd.Spec = "[-f] [--chart] [--chart-path]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
chart := cmd.StringOpt("chart", "", "Limits the explain command to only the specified chart")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")

cmd.Action = func() {
ctx.AnkhFilePath = *ankhFilePath
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Explain

execute(ctx)
Expand All @@ -841,19 +846,24 @@ func main() {
})

app.Command("apply", "Apply an Ankh file to a Kubernetes cluster", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [--dry-run] [--chart] [--slack] [--slack-message] [--filter...]"
cmd.Spec = "[-f] [--dry-run] [--chart] [--chart-path] [--slack] [--slack-message] [--filter...]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
dryRun := cmd.BoolOpt("dry-run", false, "Perform a dry-run and don't actually apply anything to a cluster")
chart := cmd.StringOpt("chart", "", "Limits the apply command to only the specified chart")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
slackChannel := cmd.StringOpt("s slack", "", "Send slack message to specified slack channel about application update")
slackMessageOverride := cmd.StringOpt("m slack-message", "", "Override the default slack message being sent")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action.")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action")

cmd.Action = func() {
ctx.AnkhFilePath = *ankhFilePath
ctx.DryRun = *dryRun
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Apply
ctx.SlackChannel = *slackChannel
ctx.SlackMessageOverride = *slackMessageOverride
Expand All @@ -869,18 +879,23 @@ func main() {
})

app.Command("rollback", "Rollback deployments associated with a templated Ankh file from Kubernetes", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [--dry-run] [--chart] [--slack] [--slack-message]"
cmd.Spec = "[-f] [--dry-run] [--chart] [--chart-path] [--slack] [--slack-message]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
dryRun := cmd.BoolOpt("dry-run", false, "Perform a dry-run and don't actually rollback anything to a cluster")
chart := cmd.StringOpt("chart", "", "Limits the rollback command to only the specified chart")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
slackChannel := cmd.StringOpt("s slack", "", "Send slack message to specified slack channel about application update")
slackMessageOverride := cmd.StringOpt("m slack-message", "", "Override the default slack message being sent")

cmd.Action = func() {
ctx.AnkhFilePath = *ankhFilePath
ctx.DryRun = *dryRun
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Rollback
ctx.SlackChannel = *slackChannel
ctx.SlackMessageOverride = *slackMessageOverride
Expand Down Expand Up @@ -912,17 +927,22 @@ func main() {
})

app.Command("diff", "Diff against live objects associated with a templated Ankh file from Kubernetes", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [--chart] [--filter...]"
cmd.Spec = "[-f] [--chart] [--chart-path] [--filter...]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
chart := cmd.StringOpt("chart", "", "Limits the apply command to only the specified chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action.")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action")

cmd.Action = func() {
setLogLevel(ctx, logrus.InfoLevel)
ctx.AnkhFilePath = *ankhFilePath
ctx.DryRun = false
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Diff
filters := []string{}
for _, filter := range *filter {
Expand All @@ -936,18 +956,23 @@ func main() {
})

app.Command("get", "Get objects associated with a templated Ankh file from Kubernetes", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [--chart] [--filter...] [EXTRA...]"
cmd.Spec = "[-f] [--chart] [--chart-path] [--filter...] [EXTRA...]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
chart := cmd.StringOpt("chart", "", "Limits the apply command to only the specified chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action.")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action")
extra := cmd.StringsArg("EXTRA", []string{}, "Extra arguments to pass to `kubectl`, which can be specified after `--` eg: `ankh ... get -- -o json`")

cmd.Action = func() {
setLogLevel(ctx, logrus.InfoLevel)
ctx.AnkhFilePath = *ankhFilePath
ctx.DryRun = false
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Get
filters := []string{}
for _, filter := range *filter {
Expand All @@ -965,10 +990,11 @@ func main() {
})

app.Command("pods", "Get pods associated with a templated Ankh file from Kubernetes", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [-w] [-d] [--chart] [EXTRA...]"
cmd.Spec = "[-f] [-w] [-d] [--chart] [--chart-path] [EXTRA...]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
chart := cmd.StringOpt("chart", "", "Limits the apply command to only the specified chart")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
watch := cmd.BoolOpt("w watch", false, "Watch for updates (ie: pass -w to kubectl)")
describe := cmd.BoolOpt("d describe", false, "Use `kubectl describe ...` instead of `kubectl get -o wide ...` for pods")
extra := cmd.StringsArg("EXTRA", []string{}, "Extra arguments to pass to `kubectl`, which can be specified after `--` eg: `ankh ... get -- -o json`")
Expand All @@ -979,6 +1005,10 @@ func main() {
ctx.DryRun = false
ctx.Describe = *describe
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Pods
for _, e := range *extra {
ctx.Logger.Debugf("Appending extra arg: %+v", e)
Expand All @@ -995,13 +1025,14 @@ func main() {
})

app.Command("logs", "Get logs for pods associated with a templated Ankh file from Kubernetes", func(cmd *cli.Cmd) {
cmd.Spec = "[-c] [-f] [--filename] [--previous] [--tail] [--chart] [CONTAINER]"
cmd.Spec = "[-c] [-f] [--filename] [--previous] [--tail] [--chart] [--chart-path] [CONTAINER]"

ankhFilePath := cmd.StringOpt("filename", "ankh.yaml", "Config file name")
numTailLines := cmd.IntOpt("t tail", 10, "The number of most recent log lines to see. Pass 0 to receive all log lines available from Kubernetes, which is subject to its own retential policy.")
follow := cmd.BoolOpt("f", false, "Follow logs")
previous := cmd.BoolOpt("p previous", false, "Get logs for the previously terminated container, if any")
chart := cmd.StringOpt("chart", "", "Limits the apply command to only the specified chart")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
container := cmd.StringOpt("c container", "", "The container to exec on. Required when there is more than one container running in the pods associated with the templated Ankh file.")
containerArg := cmd.StringArg("CONTAINER", "", "The container to get logs for. Required when there is more than one container running in the pods associated with the templated Ankh file.")

Expand All @@ -1010,6 +1041,10 @@ func main() {
ctx.AnkhFilePath = *ankhFilePath
ctx.DryRun = false
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Logs
if *follow {
ctx.ExtraArgs = append(ctx.ExtraArgs, "-f")
Expand Down Expand Up @@ -1038,10 +1073,11 @@ func main() {
})

app.Command("exec", "Exec a command on pods associated with a templated Ankh file from Kubernetes", func(cmd *cli.Cmd) {
cmd.Spec = "[-c] [--filename] [--chart] [PASSTHROUGH...]"
cmd.Spec = "[-c] [--filename] [--chart] [--chart-path] [PASSTHROUGH...]"

ankhFilePath := cmd.StringOpt("filename", "ankh.yaml", "Config file name")
chart := cmd.StringOpt("chart", "", "Limits the apply command to only the specified chart")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
container := cmd.StringOpt("c container", "", "The container to exec on. Required when there is more than one container running in the pods associated with the templated Ankh file.")
extra := cmd.StringsArg("PASSTHROUGH", []string{}, "Pass-through arguments to provide to `kubectl` after `exec`, which can be specified after `--` eg: `ankh ... get -- -o json`")

Expand All @@ -1050,6 +1086,10 @@ func main() {
ctx.AnkhFilePath = *ankhFilePath
ctx.DryRun = false
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Exec
if *container != "" {
ctx.ExtraArgs = append(ctx.ExtraArgs, []string{"-c", *container}...)
Expand All @@ -1068,15 +1108,20 @@ func main() {
})

app.Command("lint", "Lint an Ankh file, checking for possible errors or mistakes", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [--chart] [--filter...]"
cmd.Spec = "[-f] [--chart] [--chart-path] [--filter...]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
chart := cmd.StringOpt("chart", "", "Limits the lint command to only the specified chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action.")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action")

cmd.Action = func() {
ctx.AnkhFilePath = *ankhFilePath
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Lint
filters := []string{}
for _, filter := range *filter {
Expand All @@ -1090,15 +1135,20 @@ func main() {
})

app.Command("template", "Output the results of templating an Ankh file", func(cmd *cli.Cmd) {
cmd.Spec = "[-f] [--chart] [--filter...]"
cmd.Spec = "[-f] [--chart] [--chart-path] [--filter...]"

ankhFilePath := cmd.StringOpt("f filename", "ankh.yaml", "Config file name")
chart := cmd.StringOpt("chart", "", "Limits the template command to only the specified chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action.")
chartPath := cmd.StringOpt("chart-path", "", "Use a local chart directory instead of a remote, versioned chart")
filter := cmd.StringsOpt("filter", []string{}, "Kubernetes object kinds to include for the action. The entries in this list are case insensitive. Any object whose `kind:` does not match this filter will be excluded from the action")

cmd.Action = func() {
ctx.AnkhFilePath = *ankhFilePath
ctx.Chart = *chart
if *chartPath != "" {
ctx.Chart = *chartPath
ctx.LocalChart = true
}
ctx.Mode = ankh.Template
filters := []string{}
for _, filter := range *filter {
Expand Down
51 changes: 43 additions & 8 deletions context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,10 @@ type ExecutionContext struct {
AnkhConfig, OriginalAnkhConfig AnkhConfig

AnkhFilePath string
// Overrides:
// Chart may be a single chart in the charts array, or a local chart path
// Namespace may override a value present in the AnkhFile
Chart string
Tag *string
Namespace *string
Chart string
LocalChart bool
Tag *string
Namespace *string

Mode Mode

Expand Down Expand Up @@ -342,10 +340,46 @@ func GetAnkhFile(ctx *ExecutionContext) (AnkhFile, error) {
return getAnkhFileForChart(ctx, ctx.Chart)
}

type HelmChart struct {
Name string
}

func readChartDirectory(chartDir string) (*HelmChart, error) {
chartYamlPath := filepath.Join(chartDir, "Chart.yaml")
chartYaml, err := ioutil.ReadFile(chartYamlPath)
if err != nil {
return nil, err
}
helmChart := HelmChart{}
err = yaml.Unmarshal(chartYaml, &helmChart)
if err != nil {
return nil, err
}
if helmChart.Name == "" {
return nil, fmt.Errorf("Did not find any `name` in %v", chartYamlPath)
}
return &helmChart, nil
}

func getAnkhFileForChart(ctx *ExecutionContext, singleChart string) (AnkhFile, error) {
versionOverride := ""
ankhFile := AnkhFile{}

if ctx.LocalChart {
// The user wants to use a local chart. Interpret singleChart as a directory.
ctx.Logger.Infof("Using chart directory %v", singleChart)
helmChart, err := readChartDirectory(singleChart)
if err != nil {
return AnkhFile{}, fmt.Errorf("Could not use \"%v\" as a local chart directory: %v", singleChart, err)
}

ankhFile = AnkhFile{
Charts: []Chart{
Chart{Path: singleChart, Name: helmChart.Name},
},
}
return ankhFile, nil
}

var ankhFile AnkhFile
if _, err := os.Stat(ctx.AnkhFilePath); err == nil {
ctx.Logger.Infof("Reading Ankh file %v", ctx.AnkhFilePath)
ankhFile, err = ParseAnkhFile(ctx.AnkhFilePath)
Expand All @@ -357,6 +391,7 @@ func getAnkhFileForChart(ctx *ExecutionContext, singleChart string) (AnkhFile, e

// The single chart argument may have a version override in the format `name@version`
// Extract that now if possible.
versionOverride := ""
tokens := strings.Split(singleChart, "@")
if len(tokens) > 2 {
ctx.Logger.Fatalf("Invalid chart '%v'. Too many `@` characters found. Chart must either be a name with no `@`, or in the combined `name@version` format", singleChart)
Expand Down
21 changes: 0 additions & 21 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -392,27 +392,6 @@ func ArrayDedup(a []string) []string {
return keys
}

type HelmChart struct {
Name string
}

func ReadChartDirectory(chartDir string) (*HelmChart, error) {
chartYamlPath := filepath.Join(chartDir, "Chart.yaml")
chartYaml, err := ioutil.ReadFile(chartYamlPath)
if err != nil {
return nil, err
}
helmChart := HelmChart{}
err = yaml.Unmarshal(chartYaml, &helmChart)
if err != nil {
return nil, err
}
if helmChart.Name == "" {
return nil, fmt.Errorf("Did not find any `name` in %v", chartYamlPath)
}
return &helmChart, nil
}

func compareTokens(t1, t2 string) int {
// split on most things are are not a numeric. this will
// allow us to mostly compare by parsed numbers, and
Expand Down

0 comments on commit bf6a8d0

Please sign in to comment.