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

Commit

Permalink
Release 0.1.4 (#27)
Browse files Browse the repository at this point in the history
* Check for exactly one version argument to build script (#25)
* Add before-generate and after-generate hooks (#26)
* Bumped version to 0.1.4
  • Loading branch information
timfpark authored Jan 29, 2019
1 parent 3818e84 commit a76ea4b
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Let's look at the `infra` directory. This directory defines the common applicat

In this case, it will build resource manifests for both Elasticsearch / FluentD / Kibana (EFK) log management and Prometheus / Grafana metrics monitoring stacks using components in an external git repo. Fabrikate enables linking out to components in an external repo like this as a way of sharing common subcomponents between deployment projects.

Looking at the [backing repo](https://github.com/timfpark/fabrikate/elasticsearch-fluentd-kibana) for the EFK component, we can see that it also defines a `component.json`:
Looking at the [backing repo](https://github.com/timfpark/fabrikate-elasticsearch-fluentd-kibana) for the EFK component, we can see that it also defines a `component.json`:

```
{
Expand Down
19 changes: 5 additions & 14 deletions cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,22 @@ import (
func Generate(startPath string, environment string) (components []core.Component, err error) {
// Iterate through component tree and generate
components, err = core.IterateComponentTree(startPath, environment, func(path string, component *core.Component) (err error) {

var generator core.Generator
switch component.Generator {
case "helm":
component.Manifest, err = generators.GenerateHelmComponent(component)
generator = &generators.HelmGenerator{}
case "static":
component.Manifest, err = generators.GenerateStaticComponent(component)
generator = &generators.StaticGenerator{}
}

return err
return component.Generate(generator)
})

// Delete the old version, so we don't end up with a mishmash of two builds.
generationPath := path.Join(startPath, "generated", environment)
os.RemoveAll(generationPath)

// TODO: need to push component yaml out to {path}/generated directory
for _, component := range components {
componentGenerationPath := path.Join(generationPath, component.LogicalPath)
err := os.MkdirAll(componentGenerationPath, 0755)
Expand Down Expand Up @@ -78,14 +79,4 @@ var generateCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(generateCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// generateCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// generateCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
6 changes: 6 additions & 0 deletions cmd/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ func TestGenerateYAML(t *testing.T) {

checkComponentLengthsAgainstExpected(t, components, expectedLengths)
}

func TestGenerateWithHooks(t *testing.T) {
_, err := Generate("../test/fixtures/generate-hooks", "prod")

assert.Nil(t, err)
}
14 changes: 8 additions & 6 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,24 @@ import (
"github.com/spf13/cobra"
)

// Install installs the component at the given path and all of its subcomponents.
func Install(path string) (err error) {
_, err = core.IterateComponentTree(path, "", func(path string, component *core.Component) (err error) {
log.Info(emoji.Sprintf(":point_right: starting install for component: %s", component.Name))
if err := component.Install(path); err != nil {
return err
}

var generator core.Generator

switch component.Generator {
case "helm":
err = generators.InstallHelmComponent(component)
generator = &generators.HelmGenerator{}
}

if err == nil {
log.Info(emoji.Sprintf(":point_left: finished install for component: %s", component.Name))
if err := component.Install(path, generator); err != nil {
return err
}

log.Info(emoji.Sprintf(":point_left: finished install for component: %s", component.Name))

return err
})

Expand Down
6 changes: 6 additions & 0 deletions cmd/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ func TestInstallYAML(t *testing.T) {

assert.Nil(t, err)
}

func TestInstallWithHooks(t *testing.T) {
err := Install("../test/fixtures/install-hooks")

assert.Nil(t, err)
}
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
log.Println("fab version 0.1.3")
log.Println("fab version 0.1.4")
},
}

Expand Down
128 changes: 106 additions & 22 deletions core/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"path"
"strings"

"github.com/kyokomi/emoji"
"github.com/pkg/errors"
Expand All @@ -15,17 +16,19 @@ import (
)

type Component struct {
Name string
Source string
Method string
Name string
Config ComponentConfig
Generator string
Hooks map[string][]string
Source string
Method string
Path string
Repo string

Generator string
Subcomponents []Component
Repo string
Path string
PhysicalPath string
LogicalPath string
Config ComponentConfig

PhysicalPath string
LogicalPath string

Manifest string
}
Expand Down Expand Up @@ -112,21 +115,26 @@ func (c *Component) RelativePathTo() string {
}
}

func (c *Component) Install(componentPath string) (err error) {
for _, subcomponent := range c.Subcomponents {
if subcomponent.Method == "git" {
componentsPath := fmt.Sprintf("%s/components", componentPath)
if err := exec.Command("mkdir", "-p", componentsPath).Run(); err != nil {
return err
}
func (c *Component) ExecuteHook(hook string) (err error) {
if c.Hooks[hook] == nil {
return nil
}

subcomponentPath := path.Join(componentPath, subcomponent.RelativePathTo())
if err = exec.Command("rm", "-rf", subcomponentPath).Run(); err != nil {
return err
}
log.Infof("executing hooks for: %s", hook)

for _, command := range c.Hooks[hook] {
log.Infof("executing command: %s", command)
commandComponents := strings.Fields(command)
if len(commandComponents) != 0 {
commandExecutable := commandComponents[0]
commandArgs := commandComponents[1:len(commandComponents)]
cmd := exec.Command(commandExecutable, commandArgs...)
cmd.Dir = c.PhysicalPath
if err := cmd.Run(); err != nil {
if ee, ok := err.(*exec.ExitError); ok {
log.Errorf("hook command failed with: %s\n", ee.Stderr)
}

log.Println(emoji.Sprintf(":helicopter: installing component %s with git from %s", subcomponent.Name, subcomponent.Source))
if err = exec.Command("git", "clone", subcomponent.Source, subcomponentPath).Run(); err != nil {
return err
}
}
Expand All @@ -135,6 +143,82 @@ func (c *Component) Install(componentPath string) (err error) {
return nil
}

func (c *Component) BeforeGenerate() (err error) {
return c.ExecuteHook("before-generate")
}

func (c *Component) AfterGenerate() (err error) {
return c.ExecuteHook("after-generate")
}

func (c *Component) BeforeInstall() (err error) {
return c.ExecuteHook("before-install")
}

func (c *Component) AfterInstall() (err error) {
return c.ExecuteHook("after-install")
}

func (c *Component) InstallComponent(componentPath string) (err error) {
if c.Method == "git" {
componentsPath := fmt.Sprintf("%s/components", componentPath)
if err := exec.Command("mkdir", "-p", componentsPath).Run(); err != nil {
return err
}

subcomponentPath := path.Join(componentPath, c.RelativePathTo())
if err = exec.Command("rm", "-rf", subcomponentPath).Run(); err != nil {
return err
}

log.Println(emoji.Sprintf(":helicopter: installing component %s with git from %s", c.Name, c.Source))
if err = exec.Command("git", "clone", c.Source, subcomponentPath).Run(); err != nil {
return err
}
}

return nil
}

func (c *Component) Install(componentPath string, generator Generator) (err error) {
if err := c.BeforeInstall(); err != nil {
return err
}

for _, subcomponent := range c.Subcomponents {
if err := subcomponent.InstallComponent(componentPath); err != nil {
return err
}
}

if generator != nil {
if err := generator.Install(c); err != nil {
return err
}
}

return c.AfterInstall()
}

func (c *Component) Generate(generator Generator) (err error) {
if err := c.BeforeGenerate(); err != nil {
return err
}

if generator != nil {
c.Manifest, err = generator.Generate(c)
} else {
c.Manifest = ""
err = nil
}

if err != nil {
return err
}

return c.AfterGenerate()
}

type ComponentIteration func(path string, component *Component) (err error)

// IterateComponentTree is a general function used for iterating a deployment tree for installing, generating, etc.
Expand Down
6 changes: 6 additions & 0 deletions core/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package core

type Generator interface {
Generate(component *Component) (manifest string, err error)
Install(component *Component) (err error)
}
12 changes: 7 additions & 5 deletions generators/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"gopkg.in/yaml.v2"
)

type HelmGenerator struct{}

func AddNamespaceToManifests(manifests string, namespace string) (namespacedManifests string, err error) {
splitManifest := strings.Split(manifests, "\n---")

Expand Down Expand Up @@ -45,15 +47,15 @@ func AddNamespaceToManifests(manifests string, namespace string) (namespacedMani
return namespacedManifests, nil
}

func MakeHelmRepoPath(component *core.Component) string {
func (hg *HelmGenerator) MakeHelmRepoPath(component *core.Component) string {
if len(component.Repo) == 0 {
return component.PhysicalPath
} else {
return path.Join(component.PhysicalPath, "helm_repos", component.Name)
}
}

func GenerateHelmComponent(component *core.Component) (manifest string, err error) {
func (hg *HelmGenerator) Generate(component *core.Component) (manifest string, err error) {
log.Println(emoji.Sprintf(":truck: generating component '%s' with helm with repo %s", component.Name, component.Repo))

configYaml, err := yaml.Marshal(&component.Config.Config)
Expand All @@ -62,7 +64,7 @@ func GenerateHelmComponent(component *core.Component) (manifest string, err erro
return "", err
}

helmRepoPath := MakeHelmRepoPath(component)
helmRepoPath := hg.MakeHelmRepoPath(component)
absHelmRepoPath, err := filepath.Abs(helmRepoPath)
if err != nil {
return "", err
Expand Down Expand Up @@ -106,12 +108,12 @@ func GenerateHelmComponent(component *core.Component) (manifest string, err erro
return stringManifests, err
}

func InstallHelmComponent(component *core.Component) (err error) {
func (hg *HelmGenerator) Install(component *core.Component) (err error) {
if len(component.Repo) == 0 {
return nil
}

helmRepoPath := MakeHelmRepoPath(component)
helmRepoPath := hg.MakeHelmRepoPath(component)
if err := exec.Command("rm", "-rf", helmRepoPath).Run(); err != nil {
return err
}
Expand Down
8 changes: 7 additions & 1 deletion generators/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (
log "github.com/sirupsen/logrus"
)

func GenerateStaticComponent(component *core.Component) (manifest string, err error) {
type StaticGenerator struct{}

func (sg *StaticGenerator) Generate(component *core.Component) (manifest string, err error) {
log.Println(emoji.Sprintf(":truck: generating component '%s' statically from path %s", component.Name, component.Path))

staticPath := path.Join(component.PhysicalPath, component.Path)
Expand All @@ -30,3 +32,7 @@ func GenerateStaticComponent(component *core.Component) (manifest string, err er

return manifests, err
}

func (hg *StaticGenerator) Install(component *core.Component) (err error) {
return nil
}
8 changes: 8 additions & 0 deletions test/fixtures/generate-hooks/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "generate-hooks",
"hooks": {
"before-generate": ["touch before-generate"],
"after-generate": ["rm before-generate"]
},
"subcomponents": []
}
19 changes: 19 additions & 0 deletions test/fixtures/install-hooks/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "istio",
"generator": "static",
"path": "./manifests",
"hooks": {
"before-install": [
"wget https://github.com/istio/istio/releases/download/1.0.5/istio-1.0.5-linux.tar.gz",
"tar xvf istio-1.0.5-linux.tar.gz"
],
"after-install": ["rm istio-1.0.5-linux.tar.gz", "rm -rf istio-1.0.5"]
},
"subcomponents": [
{
"name": "istio",
"generator": "helm",
"path": "./istio-1.0.5/install/kubernetes/helm/istio"
}
]
}

0 comments on commit a76ea4b

Please sign in to comment.