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

Commit

Permalink
#7: Add support for descriptor includes
Browse files Browse the repository at this point in the history
  • Loading branch information
Wulf-Thilo Schreiter committed Mar 16, 2019
1 parent 45f83e5 commit 274a835
Show file tree
Hide file tree
Showing 41 changed files with 4,347 additions and 30 deletions.
7 changes: 7 additions & 0 deletions docs/project_descriptor.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ ProjectDescriptor Structur:
| __token_key__ | The token key to access rancher with (**placed from cattleclt configuration**) |
| __cluster_name__ | The name of the cluster the project is part of (**placed from cattleclt configuration**) |
| __cluster_id__ | The ID of the cluster the project is part of (**read from rancher**) |
| __includes__ | A list of includes containing project descriptors **OPTIONAL** |

#### include

| Field | Description |
|----------|--------------------------------------------|
| __file__ | The file (relative of absolute) to include |

#### namespaces

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ require (
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/gorilla/websocket v1.4.0 // indirect
github.com/imdario/mergo v0.3.7
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/pkg/errors v0.8.1 // indirect
github.com/rancher/norman v0.0.0-20190129215722-196df5ed9da3
github.com/rancher/types v0.0.0-20190129233033-68de51b62acf
github.com/russross/blackfriday v2.0.0+incompatible // indirect
github.com/sergi/go-diff v1.0.0
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/sirupsen/logrus v1.3.0
github.com/spf13/afero v1.2.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe h1:CHRGQ8V7OlCYtwaKPJi3iA7J+YdNKdo8j7nG5IgDhjs=
Expand Down Expand Up @@ -62,6 +64,8 @@ github.com/rancher/types v0.0.0-20190129233033-68de51b62acf h1:eXRYm8z7pcY0REsvY
github.com/rancher/types v0.0.0-20190129233033-68de51b62acf/go.mod h1:ePTc7xKI37jRSwgLsg63ITTADceptutuNVG8Fj33QaE=
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 h1:/vdW8Cb7EXrkqWGufVMES1OH2sU9gKVb2n9/1y5NMBY=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
Expand Down
13 changes: 12 additions & 1 deletion internal/pkg/assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import (
"path/filepath"
"reflect"
"runtime"
"strings"
"testing"

"github.com/sergi/go-diff/diffmatchpatch"
)

var Update = flag.Bool("update", false, "update .golden files")
Expand Down Expand Up @@ -70,7 +73,15 @@ func NotOk(tb testing.TB, err error, expecteError string) {
func Equals(tb testing.TB, exp, act interface{}) {
if !reflect.DeepEqual(exp, act) {
_, file, line, _ := runtime.Caller(1)
fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)

dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(fmt.Sprint(act), fmt.Sprint(exp), true)
fmt.Printf(
"\033[31m%s:%d:\ndiff:\033[39m\n\n\t%s\n\n",
filepath.Base(file),
line,
strings.Replace(dmp.DiffPrettyText(diffs), "\n", "\n\t", -1),
)
tb.FailNow()
}
}
Expand Down
136 changes: 136 additions & 0 deletions internal/pkg/rancher/merge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright © 2019 Bitgrip <berlin@bitgrip.de>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rancher

import (
"github.com/imdario/mergo"
)

// MergeProject merge two projects.
// the result represents the parent + all fields of child
// which have no equivalent Name in parent
func MergeProject(child Project, parent Project) (Project, error) {
var dst Project
if err := mergo.Merge(&dst, parent); err != nil {
return parent, err
}
dst.Namespaces = mergeNamespaces(child.Namespaces, dst.Namespaces)
dst.Resources.Certificates = mergeCertificates(child.Resources.Certificates, parent.Resources.Certificates)
dst.Resources.ConfigMaps = mergeConfigMaps(child.Resources.ConfigMaps, parent.Resources.ConfigMaps)
dst.Resources.DockerCredentials = mergeDockerCredentials(child.Resources.DockerCredentials, parent.Resources.DockerCredentials)
dst.Resources.Secrets = mergeConfigMaps(child.Resources.Secrets, parent.Resources.Secrets)
dst.StorageClasses = mergeStorageClasses(child.StorageClasses, parent.StorageClasses)
dst.PersistentVolumes = mergePersistentVolumes(child.PersistentVolumes, parent.PersistentVolumes)
dst.Apps = mergeApps(child.Apps, parent.Apps)
return dst, nil
}

func mergeNamespaces(childNamespaces, parentNamespaces []Namespace) []Namespace {
dst := parentNamespaces
CHILD_LOOP:
for _, childNamespace := range childNamespaces {
for _, parentNamespace := range parentNamespaces {
if childNamespace.Name == parentNamespace.Name {
continue CHILD_LOOP
}
}
dst = append(dst, childNamespace)
}
return dst
}

func mergeCertificates(childCertificates, parentCertificates []Certificate) []Certificate {
dst := parentCertificates
CHILD_LOOP:
for _, childCertificate := range childCertificates {
for _, parentCertificate := range parentCertificates {
if childCertificate.Name == parentCertificate.Name {
continue CHILD_LOOP
}
}
dst = append(dst, childCertificate)
}
return dst
}

func mergeConfigMaps(childConfigMaps, parentConfigMaps []ConfigMap) []ConfigMap {
dst := parentConfigMaps
CHILD_LOOP:
for _, childConfigMap := range childConfigMaps {
for _, parentConfigMap := range parentConfigMaps {
if childConfigMap.Name == parentConfigMap.Name {
continue CHILD_LOOP
}
}
dst = append(dst, childConfigMap)
}
return dst
}

func mergeDockerCredentials(childDockerCredentials, parentDockerCredentials []DockerCredential) []DockerCredential {
dst := parentDockerCredentials
CHILD_LOOP:
for _, childDockerCredential := range childDockerCredentials {
for _, parentDockerCredential := range parentDockerCredentials {
if childDockerCredential.Name == parentDockerCredential.Name {
continue CHILD_LOOP
}
}
dst = append(dst, childDockerCredential)
}
return dst
}

func mergeStorageClasses(childStorageClasses, parentStorageClasses []StorageClass) []StorageClass {
dst := parentStorageClasses
CHILD_LOOP:
for _, childStorageClass := range childStorageClasses {
for _, parentStorageClass := range parentStorageClasses {
if childStorageClass.Name == parentStorageClass.Name {
continue CHILD_LOOP
}
}
dst = append(dst, childStorageClass)
}
return dst
}

func mergePersistentVolumes(childPersistentVolumes, parentPersistentVolumes []PersistentVolume) []PersistentVolume {
dst := parentPersistentVolumes
CHILD_LOOP:
for _, childPersistentVolume := range childPersistentVolumes {
for _, parentPersistentVolume := range parentPersistentVolumes {
if childPersistentVolume.Name == parentPersistentVolume.Name {
continue CHILD_LOOP
}
}
dst = append(dst, childPersistentVolume)
}
return dst
}

func mergeApps(childApps, parentApps []App) []App {
dst := parentApps
CHILD_LOOP:
for _, childApp := range childApps {
for _, parentApp := range parentApps {
if childApp.Name == parentApp.Name {
continue CHILD_LOOP
}
}
dst = append(dst, childApp)
}
return dst
}
45 changes: 45 additions & 0 deletions internal/pkg/rancher/merge_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright © 2019 Bitgrip <berlin@bitgrip.de>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package rancher

import (
"io/ioutil"
"testing"

"github.com/bitgrip/cattlectl/internal/pkg/assert"
yaml "gopkg.in/yaml.v2"
)

func TestMergeProjects(t *testing.T) {
testName := "simple-include"
child := readTestdataProject(t, "include/simple/child.yaml")
parent := readTestdataProject(t, "include/simple/parent.yaml")
merged, err := MergeProject(child, parent)
assert.Ok(t, err)

actual, err := yaml.Marshal(merged)
assert.Ok(t, err)
assert.AssertGoldenFile(t, testName, actual)
}

func readTestdataProject(t *testing.T, testdataFile string) Project {
project := Project{}
fileContent, err := ioutil.ReadFile("testdata/" + testdataFile)
assert.Ok(t, err)

err = yaml.Unmarshal(fileContent, &project)
assert.Ok(t, err)
return project
}
37 changes: 28 additions & 9 deletions internal/pkg/rancher/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@

package rancher

// Cluster is WIP
type Cluster struct {
ApiVersion string `yaml:"api_version"`
APIVersion string `yaml:"api_version"`
Kind string
Metadata ClusterMetadata
StorageClasses []StorageClass `yaml:"storage_classes,omitempty"`
PersistentVolumes []PersistentVolume `yaml:"storage_class,omitempty"`
Projects []Project
}

// ClusterMetadata is WIP
type ClusterMetadata struct {
Name string
ID string `yaml:"id,omitempty"`
RancherUrl string `yaml:"rancher_url,omitempty"`
RancherURL string `yaml:"rancher_url,omitempty"`
AccessKey string `yaml:"access_key,omitempty"`
SecretKey string `yaml:"secret_key,omitempty"`
TokenKey string `yaml:"token_key,omitempty"`
}

// Project is a subsection of a cluster
type Project struct {
APIVersion string `yaml:"api_version"`
Kind string
Expand All @@ -43,53 +46,67 @@ type Project struct {
Apps []App
}

// ProjectMetadata the meta informations about a Project
type ProjectMetadata struct {
Name string
ID string `yaml:"id,omitempty"`
RancherURL string `yaml:"rancher_url,omitempty"`
AccessKey string `yaml:"access_key,omitempty"`
SecretKey string `yaml:"secret_key,omitempty"`
TokenKey string `yaml:"token_key,omitempty"`
ClusterName string `yaml:"cluster_name,omitempty"`
ClusterID string `yaml:"cluster_id,omitempty"`
ID string `yaml:"id,omitempty"`
RancherURL string `yaml:"rancher_url,omitempty"`
AccessKey string `yaml:"access_key,omitempty"`
SecretKey string `yaml:"secret_key,omitempty"`
TokenKey string `yaml:"token_key,omitempty"`
ClusterName string `yaml:"cluster_name,omitempty"`
ClusterID string `yaml:"cluster_id,omitempty"`
Includes []Include `yaml:"includes,omitempty"`
}

// Include is used to merge multiple descriptors into one
type Include struct {
File string `yaml:"file"`
}

// Namespace is a subsection of a Project and is represented in K8S as namespace
type Namespace struct {
Name string
}

// Resources of a Project
type Resources struct {
Certificates []Certificate `yaml:"certificates,omitempty"`
ConfigMaps []ConfigMap `yaml:"config_maps,omitempty"`
DockerCredentials []DockerCredential `yaml:"docker_credentials,omitempty"`
Secrets []ConfigMap `yaml:"secrets,omitempty"`
}

// Certificate TLS certs used e.g. for https endpoints
type Certificate struct {
Name string
Key string
Certs string
Namespace string `yaml:"namespace,omitempty"`
}

// ConfigMap data structure used for K8S configmaps and secrets
type ConfigMap struct {
Name string
Data map[string]string
Namespace string `yaml:"namespace,omitempty"`
}

//DockerCredential to access docker registries
type DockerCredential struct {
Name string `yaml:"name,omitempty"`
Namespace string `yaml:"namespace,omitempty"`
Registries []RegistryCredential `yaml:"registries,omitempty"`
}

// RegistryCredential credentials of one docker registry
type RegistryCredential struct {
Name string `yaml:"name,omitempty"`
Password string `yaml:"password,omitempty"`
Username string `yaml:"username,omitempty"`
}

// StorageClass represent a K8S StorageClass
type StorageClass struct {
Name string
Provisioner string
Expand All @@ -99,6 +116,7 @@ type StorageClass struct {
MountOptions []string `yaml:"mount_options,omitempty"`
}

// PersistentVolume represent a K8S PersistentVolume
type PersistentVolume struct {
Name string
Type string
Expand All @@ -110,6 +128,7 @@ type PersistentVolume struct {
InitScript string `yaml:"init_script"`
}

// App deployment using a Helm- or Rancher-Chart
type App struct {
Name string
Catalog string
Expand Down
Loading

0 comments on commit 274a835

Please sign in to comment.