Skip to content

Commit

Permalink
Merge pull request #144 from SteveRuble/filesystem-charts
Browse files Browse the repository at this point in the history
feat: Support local charts on file system
  • Loading branch information
Sami Alajrami authored Dec 17, 2018
2 parents 897fd9e + 1ae3814 commit 4855cef
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 16 deletions.
13 changes: 10 additions & 3 deletions decision_maker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"regexp"
"strconv"
"strings"
)
Expand Down Expand Up @@ -268,7 +269,7 @@ func reInstallRelease(r *release, rs releaseState) {

installCmd := command{
Cmd: "bash",
Args: []string{"-c", "helm install " + r.Chart + " --version " + r.Version + " -n " + r.Name + " --namespace " + r.Namespace + getValuesFiles(r) + getSetValues(r) + getSetStringValues(r) + getWait(r) + getDesiredTillerNamespaceFlag(r) + getTLSFlags(r) + getTimeout(r) + getNoHooks(r) + getDryRunFlags()},
Args: []string{"-c", "helm install " + r.Chart+ " --version " + r.Version + " -n " + r.Name + " --namespace " + r.Namespace + getValuesFiles(r) + getSetValues(r) + getSetStringValues(r) + getWait(r) + getDesiredTillerNamespaceFlag(r) + getTLSFlags(r) + getTimeout(r) + getNoHooks(r) + getDryRunFlags()},
Description: "installing release [ " + r.Name + " ] in namespace [[ " + r.Namespace + " ]] using Tiller in [ " + getDesiredTillerNamespace(r) + " ]",
}
outcome.addCommand(installCmd, r.Priority, r)
Expand All @@ -283,13 +284,19 @@ func logDecision(decision string, priority int) {
}

// extractChartName extracts the Helm chart name from full chart name in the desired state.
// example: it extracts "chartY" from "repoX/chartY"
// example: it extracts "chartY" from "repoX/chartY" and "chartZ" from "c:\charts\chartZ"
func extractChartName(releaseChart string) string {

return strings.TrimSpace(strings.Split(releaseChart, "/")[1])
m := chartNameExtractor.FindStringSubmatch(releaseChart)
if len(m) == 2 {
return m[1]
}

return ""
}

var chartNameExtractor = regexp.MustCompile(`[\\/]([^\\/]+)$`)

// getNoHooks returns the no-hooks flag for install/upgrade commands
func getNoHooks(r *release) string {
if r.NoHooks {
Expand Down
15 changes: 13 additions & 2 deletions docs/how_to/use_local_charts.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ version: v1.3.0-rc

# use local helm charts

You can use your locally developed charts. But first, you have to serve them on localhost using helm's `serve` option.
You can use your locally developed charts.

## Served by Helm

You can serve them on localhost using helm's `serve` option.

```toml
...
Expand All @@ -28,4 +32,11 @@ helmRepos:

...

```
```

## From file system

If you use a file path (relative to the DSF, or absolute) for the ```chart``` attribute
helmsman will try to resolve that chart from the local file system. The chart on the
local file system must have a version matching the version specified in the DSF.

45 changes: 36 additions & 9 deletions helm_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package main
import (
"encoding/json"
"log"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"

"github.com/Praqma/helmsman/gcs"
version "github.com/hashicorp/go-version"
"github.com/hashicorp/go-version"
)

var currentState map[string]releaseState
Expand Down Expand Up @@ -211,18 +212,44 @@ func getNSTLSFlags(ns string) string {
// Valid charts are the ones that can be found in the defined repos.
// This function uses Helm search to verify if the chart can be found or not.
func validateReleaseCharts(apps map[string]*release) (bool, string) {
versionExtractor := regexp.MustCompile(`version:\s?(.*)`)

for app, r := range apps {
cmd := command{
Cmd: "bash",
Args: []string{"-c", "helm search " + r.Chart + " --version " + strconv.Quote(r.Version) + " -l"},
Description: "validating if chart " + r.Chart + "-" + r.Version + " is available in the defined repos.",
}

if exitCode, result := cmd.exec(debug, verbose); exitCode != 0 || strings.Contains(result, "No results found") {
return false, "ERROR: chart " + r.Chart + "-" + r.Version + " is specified for " +
"app [" + app + "] but is not found in the defined repos."
isLocal := filepath.IsAbs(r.Chart)
if isLocal {
cmd := command{
Cmd: "bash",
Args: []string{"-c", "helm inspect chart " + r.Chart},
Description: "validating if chart at " + r.Chart + " is available.",
}

if exitCode, output := cmd.exec(debug, verbose); exitCode != 0 {
maybeRepo := filepath.Base(filepath.Dir(r.Chart))
return false, "ERROR: chart at " + r.Chart + " for app [" + app + "] could not be found. Did you mean to add a repo named '" + maybeRepo +"'?"
} else {
matches := versionExtractor.FindStringSubmatch(output)
if len(matches) == 2 {
version := matches[1]
if r.Version != version {
return false, "ERROR: chart " + r.Chart + " with version " + r.Version + " is specified for " +
"app [" + app + "] but the chart found at that path has version " + version + " which does not match."
}
}
}
} else {
cmd := command{
Cmd: "bash",
Args: []string{"-c", "helm search " + r.Chart + " --version " + strconv.Quote(r.Version) + " -l"},
Description: "validating if chart " + r.Chart + "-" + r.Version + " is available in the defined repos.",
}

if exitCode, result := cmd.exec(debug, verbose); exitCode != 0 || strings.Contains(result, "No results found") {
return false, "ERROR: chart " + r.Chart + "-" + r.Version + " is specified for " +
"app [" + app + "] but is not found in the defined repos."
}
}

}
return true, ""
}
Expand Down
2 changes: 1 addition & 1 deletion release.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"os"
"strings"

version "github.com/hashicorp/go-version"
"github.com/hashicorp/go-version"
)

// release type representing Helm releases which are described in the desired state
Expand Down
19 changes: 18 additions & 1 deletion utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func toFile(file string, s *state) {

func resolvePaths(relativeToFile string, s *state) {
dir := filepath.Dir(relativeToFile)

for k, v := range s.Apps {
if v.ValuesFile != "" {
v.ValuesFile, _ = filepath.Abs(filepath.Join(dir, v.ValuesFile))
Expand All @@ -156,9 +157,25 @@ func resolvePaths(relativeToFile string, s *state) {
for i, f := range v.SecretsFiles {
v.SecretsFiles[i], _ = filepath.Abs(filepath.Join(dir, f))
}

if v.Chart != "" {
var repoOrDir = filepath.Dir(v.Chart)
_, isRepo := s.HelmRepos[repoOrDir]
if !isRepo {
// if there is no repo for the chart, we assume it's intended to be a local path

// support env vars in path
v.Chart = os.ExpandEnv(v.Chart)
// respect absolute paths to charts but resolve relative paths
if !filepath.IsAbs(v.Chart) {
v.Chart, _ = filepath.Abs(filepath.Join(dir, v.Chart))
}
}
}

s.Apps[k] = v
}
//resolving paths for k8s certificate files
// resolving paths for k8s certificate files
for k, v := range s.Certificates {
if _, err := url.ParseRequestURI(v); err != nil {
v, _ = filepath.Abs(filepath.Join(dir, v))
Expand Down

0 comments on commit 4855cef

Please sign in to comment.