Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
f99f146af2 | |||
e72a8a2e9c | |||
0f73aa3125 | |||
7dc5d509f7 | |||
a9b75c48c4 | |||
6ea3a923cc | |||
6cd1af015b | |||
68a031d0be | |||
7ba68c2854 | |||
1dd8fef4b3 | |||
6a2417c361 | |||
ad316d1f49 |
11
.github/dependabot.yml
vendored
Normal file
11
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "gomod"
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
6
Makefile
6
Makefile
@@ -49,7 +49,11 @@ help:
|
|||||||
|
|
||||||
build: pull katenary
|
build: pull katenary
|
||||||
|
|
||||||
build-all: pull dist dist/katenary-linux-amd64 dist/katenary-linux-arm64 dist/katenary.exe dist/katenary-darwin-amd64 dist/katenary-freebsd-amd64 dist/katenary-freebsd-arm64
|
build-all:
|
||||||
|
rm -f dist/*
|
||||||
|
$(MAKE) _build-all
|
||||||
|
|
||||||
|
_build-all: pull dist dist/katenary-linux-amd64 dist/katenary-linux-arm64 dist/katenary.exe dist/katenary-darwin-amd64 dist/katenary-freebsd-amd64 dist/katenary-freebsd-arm64
|
||||||
|
|
||||||
pull:
|
pull:
|
||||||
ifneq ($(GO),local)
|
ifneq ($(GO),local)
|
||||||
|
15
cmd/utils.go
15
cmd/utils.go
@@ -93,13 +93,20 @@ func detectGitVersion() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Convert(composeFile, appVersion, appName, chartDir string, force bool) {
|
func Convert(composeFile, appVersion, appName, chartDir string, force bool) {
|
||||||
composeFound := FindComposeFile()
|
if len(composeFile) == 0 {
|
||||||
|
fmt.Println("No compose file given")
|
||||||
|
return
|
||||||
|
}
|
||||||
_, err := os.Stat(ComposeFile)
|
_, err := os.Stat(ComposeFile)
|
||||||
if !composeFound && err != nil {
|
if err != nil {
|
||||||
fmt.Println("No compose file found")
|
fmt.Println("No compose file found")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the compose file now
|
||||||
|
p := compose.NewParser(composeFile)
|
||||||
|
p.Parse(appName)
|
||||||
|
|
||||||
dirname := filepath.Join(chartDir, appName)
|
dirname := filepath.Join(chartDir, appName)
|
||||||
if _, err := os.Stat(dirname); err == nil && !force {
|
if _, err := os.Stat(dirname); err == nil && !force {
|
||||||
response := ""
|
response := ""
|
||||||
@@ -130,10 +137,6 @@ func Convert(composeFile, appVersion, appName, chartDir string, force bool) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the compose file now
|
|
||||||
p := compose.NewParser(ComposeFile)
|
|
||||||
p.Parse(appName)
|
|
||||||
|
|
||||||
// start generator
|
// start generator
|
||||||
generator.Generate(p, Version, appName, appVersion, ComposeFile, dirname)
|
generator.Generate(p, Version, appName, appVersion, ComposeFile, dirname)
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/shlex"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,6 +55,13 @@ func (p *Parser) Parse(appname string) {
|
|||||||
services := make(map[string][]string)
|
services := make(map[string][]string)
|
||||||
// get the service list, to be sure that everything is ok
|
// get the service list, to be sure that everything is ok
|
||||||
|
|
||||||
|
// fix ugly types
|
||||||
|
for _, s := range p.Data.Services {
|
||||||
|
parseEnv(s)
|
||||||
|
parseCommand(s)
|
||||||
|
parseEnvFiles(s)
|
||||||
|
}
|
||||||
|
|
||||||
c := p.Data
|
c := p.Data
|
||||||
for name, s := range c.Services {
|
for name, s := range c.Services {
|
||||||
if portlabel, ok := s.Labels[helm.LABEL_PORT]; ok {
|
if portlabel, ok := s.Labels[helm.LABEL_PORT]; ok {
|
||||||
@@ -94,6 +102,22 @@ func (p *Parser) Parse(appname string) {
|
|||||||
log.Fatal(strings.Join(missing, "\n"))
|
log.Fatal(strings.Join(missing, "\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if all "image" properties are set
|
||||||
|
missing = []string{}
|
||||||
|
for name, s := range c.Services {
|
||||||
|
if s.Image == "" {
|
||||||
|
missing = append(missing, fmt.Sprintf(
|
||||||
|
"The service \"%s\" hasn't got "+
|
||||||
|
"an image property - please "+
|
||||||
|
"append an image property in the docker-compose file",
|
||||||
|
name,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(missing) > 0 {
|
||||||
|
log.Fatal(strings.Join(missing, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
// check the build element
|
// check the build element
|
||||||
for name, s := range c.Services {
|
for name, s := range c.Services {
|
||||||
if s.RawBuild == nil {
|
if s.RawBuild == nil {
|
||||||
@@ -105,4 +129,83 @@ func (p *Parser) Parse(appname string) {
|
|||||||
" for the \"" + name + "\" service \x1b[0m")
|
" for the \"" + name + "\" service \x1b[0m")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// manage environment variables, if the type is map[string]string so we can use it, else we need to split "=" sign
|
||||||
|
// and apply this in env variable
|
||||||
|
func parseEnv(s *Service) {
|
||||||
|
env := make(map[string]string)
|
||||||
|
if s.RawEnvironment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch s.RawEnvironment.(type) {
|
||||||
|
case map[string]string:
|
||||||
|
env = s.RawEnvironment.(map[string]string)
|
||||||
|
case map[string]interface{}:
|
||||||
|
for k, v := range s.RawEnvironment.(map[string]interface{}) {
|
||||||
|
// force to string
|
||||||
|
env[k] = fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
case []interface{}:
|
||||||
|
for _, v := range s.RawEnvironment.([]interface{}) {
|
||||||
|
// Splot the value of the env variable with "="
|
||||||
|
parts := strings.Split(v.(string), "=")
|
||||||
|
env[parts[0]] = parts[1]
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
parts := strings.Split(s.RawEnvironment.(string), "=")
|
||||||
|
env[parts[0]] = parts[1]
|
||||||
|
default:
|
||||||
|
log.Printf("%+v, %T", s.RawEnvironment, s.RawEnvironment)
|
||||||
|
log.Fatal("Environment type not supported")
|
||||||
|
}
|
||||||
|
s.Environment = env
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCommand(s *Service) {
|
||||||
|
|
||||||
|
if s.RawCommand == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// following the command type, it can be a "slice" or a simple sting, so we need to check it
|
||||||
|
switch s.RawCommand.(type) {
|
||||||
|
case string:
|
||||||
|
// use shlex to parse the command
|
||||||
|
command, err := shlex.Split(s.RawCommand.(string))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
s.Command = command
|
||||||
|
case []string:
|
||||||
|
s.Command = s.RawCommand.([]string)
|
||||||
|
case []interface{}:
|
||||||
|
for _, v := range s.RawCommand.([]interface{}) {
|
||||||
|
s.Command = append(s.Command, v.(string))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Printf("%+v %T", s.RawCommand, s.RawCommand)
|
||||||
|
log.Fatal("Command type not supported")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEnvFiles(s *Service) {
|
||||||
|
// Same than parseEnv, but for env files
|
||||||
|
if s.RawEnvFiles == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
envfiles := make([]string, 0)
|
||||||
|
switch s.RawEnvFiles.(type) {
|
||||||
|
case []string:
|
||||||
|
envfiles = s.RawEnvFiles.([]string)
|
||||||
|
case []interface{}:
|
||||||
|
for _, v := range s.RawEnvFiles.([]interface{}) {
|
||||||
|
envfiles = append(envfiles, v.(string))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Printf("%+v %T", s.RawEnvFiles, s.RawEnvFiles)
|
||||||
|
log.Fatal("EnvFile type not supported")
|
||||||
|
}
|
||||||
|
s.EnvFiles = envfiles
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,9 @@
|
|||||||
package compose
|
package compose
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"katenary/logger"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
const DOCKER_COMPOSE_YML1 = `
|
const DOCKER_COMPOSE_YML1 = `
|
||||||
version: "3"
|
version: "3"
|
||||||
@@ -29,8 +32,20 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
katenary.io/ports: "5432"
|
katenary.io/ports: "5432"
|
||||||
|
|
||||||
|
commander1:
|
||||||
|
image: foo
|
||||||
|
command: ["/bin/sh", "-c", "echo 'hello world'"]
|
||||||
|
|
||||||
|
commander2:
|
||||||
|
image: foo
|
||||||
|
command: echo "hello world"
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
logger.NOLOG = true
|
||||||
|
}
|
||||||
|
|
||||||
func TestParser(t *testing.T) {
|
func TestParser(t *testing.T) {
|
||||||
p := NewParser("", DOCKER_COMPOSE_YML1)
|
p := NewParser("", DOCKER_COMPOSE_YML1)
|
||||||
p.Parse("test")
|
p.Parse("test")
|
||||||
@@ -85,5 +100,39 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseCommand(t *testing.T) {
|
||||||
|
p := NewParser("", DOCKER_COMPOSE_YML1)
|
||||||
|
p.Parse("test")
|
||||||
|
|
||||||
|
for name, s := range p.Data.Services {
|
||||||
|
if name == "commander1" {
|
||||||
|
t.Log(s.Command)
|
||||||
|
if len(s.Command) != 3 {
|
||||||
|
t.Errorf("Expected 3 command, got %d", len(s.Command))
|
||||||
|
}
|
||||||
|
if s.Command[0] != "/bin/sh" {
|
||||||
|
t.Errorf("Expected /bin/sh, got %s", s.Command[0])
|
||||||
|
}
|
||||||
|
if s.Command[1] != "-c" {
|
||||||
|
t.Errorf("Expected -c, got %s", s.Command[1])
|
||||||
|
}
|
||||||
|
if s.Command[2] != "echo 'hello world'" {
|
||||||
|
t.Errorf("Expected echo 'hello world', got %s", s.Command[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if name == "commander2" {
|
||||||
|
t.Log(s.Command)
|
||||||
|
if len(s.Command) != 2 {
|
||||||
|
t.Errorf("Expected 1 command, got %d", len(s.Command))
|
||||||
|
}
|
||||||
|
if s.Command[0] != "echo" {
|
||||||
|
t.Errorf("Expected echo, got %s", s.Command[0])
|
||||||
|
}
|
||||||
|
if s.Command[1] != "hello world" {
|
||||||
|
t.Errorf("Expected hello world, got %s", s.Command[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -28,13 +28,16 @@ type HealthCheck struct {
|
|||||||
type Service struct {
|
type Service struct {
|
||||||
Image string `yaml:"image"`
|
Image string `yaml:"image"`
|
||||||
Ports []string `yaml:"ports"`
|
Ports []string `yaml:"ports"`
|
||||||
Environment map[string]string `yaml:"environment"`
|
Environment map[string]string `yaml:"-"`
|
||||||
|
RawEnvironment interface{} `yaml:"environment"`
|
||||||
Labels map[string]string `yaml:"labels"`
|
Labels map[string]string `yaml:"labels"`
|
||||||
DependsOn []string `yaml:"depends_on"`
|
DependsOn []string `yaml:"depends_on"`
|
||||||
Volumes []string `yaml:"volumes"`
|
Volumes []string `yaml:"volumes"`
|
||||||
Expose []int `yaml:"expose"`
|
Expose []int `yaml:"expose"`
|
||||||
EnvFiles []string `yaml:"env_file"`
|
EnvFiles []string `yaml:"-"`
|
||||||
|
RawEnvFiles interface{} `yaml:"env_file"`
|
||||||
RawBuild interface{} `yaml:"build"`
|
RawBuild interface{} `yaml:"build"`
|
||||||
HealthCheck *HealthCheck `yaml:"healthcheck"`
|
HealthCheck *HealthCheck `yaml:"healthcheck"`
|
||||||
Command []string `yaml:"command"`
|
Command []string `yaml:"-"`
|
||||||
|
RawCommand interface{} `yaml:"command"`
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"katenary/compose"
|
"katenary/compose"
|
||||||
"katenary/helm"
|
"katenary/helm"
|
||||||
|
"katenary/logger"
|
||||||
"log"
|
"log"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -63,12 +64,13 @@ func CreateReplicaObject(name string, s *compose.Service, linked map[string]*com
|
|||||||
|
|
||||||
// This function will try to yied deployment and services based on a service from the compose file structure.
|
// This function will try to yied deployment and services based on a service from the compose file structure.
|
||||||
func parseService(name string, s *compose.Service, linked map[string]*compose.Service, ret chan interface{}) {
|
func parseService(name string, s *compose.Service, linked map[string]*compose.Service, ret chan interface{}) {
|
||||||
Magenta(ICON_PACKAGE+" Generating deployment for ", name)
|
logger.Magenta(ICON_PACKAGE+" Generating deployment for ", name)
|
||||||
|
|
||||||
o := helm.NewDeployment(name)
|
o := helm.NewDeployment(name)
|
||||||
|
|
||||||
container := helm.NewContainer(name, s.Image, s.Environment, s.Labels)
|
container := helm.NewContainer(name, s.Image, s.Environment, s.Labels)
|
||||||
prepareContainer(container, s, name)
|
prepareContainer(container, s, name)
|
||||||
|
prepareEnvFromFiles(name, s, container, ret)
|
||||||
|
|
||||||
// Set the container to the deployment
|
// Set the container to the deployment
|
||||||
o.Spec.Template.Spec.Containers = []*helm.Container{container}
|
o.Spec.Template.Spec.Containers = []*helm.Container{container}
|
||||||
@@ -91,6 +93,7 @@ func parseService(name string, s *compose.Service, linked map[string]*compose.Se
|
|||||||
for lname, link := range linked {
|
for lname, link := range linked {
|
||||||
container := helm.NewContainer(lname, link.Image, link.Environment, link.Labels)
|
container := helm.NewContainer(lname, link.Image, link.Environment, link.Labels)
|
||||||
prepareContainer(container, link, lname)
|
prepareContainer(container, link, lname)
|
||||||
|
prepareEnvFromFiles(lname, link, container, ret)
|
||||||
o.Spec.Template.Spec.Containers = append(o.Spec.Template.Spec.Containers, container)
|
o.Spec.Template.Spec.Containers = append(o.Spec.Template.Spec.Containers, container)
|
||||||
o.Spec.Template.Spec.Volumes = append(o.Spec.Template.Spec.Volumes, prepareVolumes(name, lname, link, container, madePVC, ret)...)
|
o.Spec.Template.Spec.Volumes = append(o.Spec.Template.Spec.Volumes, prepareVolumes(name, lname, link, container, madePVC, ret)...)
|
||||||
o.Spec.Template.Spec.InitContainers = append(o.Spec.Template.Spec.InitContainers, prepareInitContainers(lname, link, container)...)
|
o.Spec.Template.Spec.InitContainers = append(o.Spec.Template.Spec.InitContainers, prepareInitContainers(lname, link, container)...)
|
||||||
@@ -128,6 +131,13 @@ func parseService(name string, s *compose.Service, linked map[string]*compose.Se
|
|||||||
if len(s.Ports) == 0 {
|
if len(s.Ports) == 0 {
|
||||||
// alert any current or **future** waiters that this service is not exposed
|
// alert any current or **future** waiters that this service is not exposed
|
||||||
go func() {
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
// recover from panic
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
// log the stack trace
|
||||||
|
fmt.Println(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-time.Tick(1 * time.Millisecond):
|
case <-time.Tick(1 * time.Millisecond):
|
||||||
@@ -158,6 +168,10 @@ func parseService(name string, s *compose.Service, linked map[string]*compose.Se
|
|||||||
|
|
||||||
// prepareContainer assigns image, command, env, and labels to a container.
|
// prepareContainer assigns image, command, env, and labels to a container.
|
||||||
func prepareContainer(container *helm.Container, service *compose.Service, servicename string) {
|
func prepareContainer(container *helm.Container, service *compose.Service, servicename string) {
|
||||||
|
// if there is no image name, this should fail!
|
||||||
|
if service.Image == "" {
|
||||||
|
log.Fatal(ICON_PACKAGE+" No image name for service ", servicename)
|
||||||
|
}
|
||||||
container.Image = "{{ .Values." + servicename + ".image }}"
|
container.Image = "{{ .Values." + servicename + ".image }}"
|
||||||
container.Command = service.Command
|
container.Command = service.Command
|
||||||
Values[servicename] = map[string]interface{}{
|
Values[servicename] = map[string]interface{}{
|
||||||
@@ -171,7 +185,7 @@ func prepareContainer(container *helm.Container, service *compose.Service, servi
|
|||||||
func generateServicesAndIngresses(name string, s *compose.Service) []interface{} {
|
func generateServicesAndIngresses(name string, s *compose.Service) []interface{} {
|
||||||
|
|
||||||
ret := make([]interface{}, 0) // can handle helm.Service or helm.Ingress
|
ret := make([]interface{}, 0) // can handle helm.Service or helm.Ingress
|
||||||
Magenta(ICON_SERVICE+" Generating service for ", name)
|
logger.Magenta(ICON_SERVICE+" Generating service for ", name)
|
||||||
ks := helm.NewService(name)
|
ks := helm.NewService(name)
|
||||||
|
|
||||||
for i, p := range s.Ports {
|
for i, p := range s.Ports {
|
||||||
@@ -194,13 +208,13 @@ func generateServicesAndIngresses(name string, s *compose.Service) []interface{}
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("The given port \"%v\" as ingress port in \"%s\" service is not an integer\n", v, name)
|
log.Fatalf("The given port \"%v\" as ingress port in \"%s\" service is not an integer\n", v, name)
|
||||||
}
|
}
|
||||||
Cyanf(ICON_INGRESS+" Create an ingress for port %d on %s service\n", port, name)
|
logger.Cyanf(ICON_INGRESS+" Create an ingress for port %d on %s service\n", port, name)
|
||||||
ing := createIngress(name, port, s)
|
ing := createIngress(name, port, s)
|
||||||
ret = append(ret, ing)
|
ret = append(ret, ing)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.Expose) > 0 {
|
if len(s.Expose) > 0 {
|
||||||
Magenta(ICON_SERVICE+" Generating service for ", name+"-external")
|
logger.Magenta(ICON_SERVICE+" Generating service for ", name+"-external")
|
||||||
ks := helm.NewService(name + "-external")
|
ks := helm.NewService(name + "-external")
|
||||||
ks.Spec.Type = "NodePort"
|
ks.Spec.Type = "NodePort"
|
||||||
for _, p := range s.Expose {
|
for _, p := range s.Expose {
|
||||||
@@ -311,10 +325,10 @@ func buildCMFromPath(path string) *helm.ConfigMap {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "An error occured reading volume path %s\n", err.Error())
|
fmt.Fprintf(os.Stderr, "An error occured reading volume path %s\n", err.Error())
|
||||||
} else {
|
} else {
|
||||||
ActivateColors = true
|
logger.ActivateColors = true
|
||||||
Yellowf("Warning, %s is a directory, at this time we only "+
|
logger.Yellowf("Warning, %s is a directory, at this time we only "+
|
||||||
"can create configmap for first level file list\n", f)
|
"can create configmap for first level file list\n", f)
|
||||||
ActivateColors = false
|
logger.ActivateColors = false
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -374,8 +388,15 @@ func prepareVolumes(deployment, name string, s *compose.Service, container *helm
|
|||||||
if v, ok := s.Labels[helm.LABEL_VOL_CM]; ok {
|
if v, ok := s.Labels[helm.LABEL_VOL_CM]; ok {
|
||||||
configMapsVolumes = strings.Split(v, ",")
|
configMapsVolumes = strings.Split(v, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, volume := range s.Volumes {
|
for _, volume := range s.Volumes {
|
||||||
|
|
||||||
parts := strings.Split(volume, ":")
|
parts := strings.Split(volume, ":")
|
||||||
|
if len(parts) == 1 {
|
||||||
|
// this is a volume declaration for Docker only, avoid it
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
volname := parts[0]
|
volname := parts[0]
|
||||||
volepath := parts[1]
|
volepath := parts[1]
|
||||||
|
|
||||||
@@ -390,9 +411,9 @@ func prepareVolumes(deployment, name string, s *compose.Service, container *helm
|
|||||||
|
|
||||||
if !isCM && (strings.HasPrefix(volname, ".") || strings.HasPrefix(volname, "/")) {
|
if !isCM && (strings.HasPrefix(volname, ".") || strings.HasPrefix(volname, "/")) {
|
||||||
// local volume cannt be mounted
|
// local volume cannt be mounted
|
||||||
ActivateColors = true
|
logger.ActivateColors = true
|
||||||
Redf("You cannot, at this time, have local volume in %s deployment\n", name)
|
logger.Redf("You cannot, at this time, have local volume in %s deployment\n", name)
|
||||||
ActivateColors = false
|
logger.ActivateColors = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if isCM {
|
if isCM {
|
||||||
@@ -467,7 +488,7 @@ func prepareVolumes(deployment, name string, s *compose.Service, container *helm
|
|||||||
"mountPath": volepath,
|
"mountPath": volepath,
|
||||||
})
|
})
|
||||||
|
|
||||||
Yellow(ICON_STORE+" Generate volume values", volname, "for container named", name, "in deployment", deployment)
|
logger.Yellow(ICON_STORE+" Generate volume values", volname, "for container named", name, "in deployment", deployment)
|
||||||
locker.Lock()
|
locker.Lock()
|
||||||
if _, ok := VolumeValues[deployment]; !ok {
|
if _, ok := VolumeValues[deployment]; !ok {
|
||||||
VolumeValues[deployment] = make(map[string]map[string]interface{})
|
VolumeValues[deployment] = make(map[string]map[string]interface{})
|
||||||
@@ -619,16 +640,16 @@ func prepareEnvFromFiles(name string, s *compose.Service, container *helm.Contai
|
|||||||
}
|
}
|
||||||
var store helm.InlineConfig
|
var store helm.InlineConfig
|
||||||
if !isSecret {
|
if !isSecret {
|
||||||
Bluef(ICON_CONF+" Generating configMap %s\n", cf)
|
logger.Bluef(ICON_CONF+" Generating configMap %s\n", cf)
|
||||||
store = helm.NewConfigMap(cf)
|
store = helm.NewConfigMap(cf)
|
||||||
} else {
|
} else {
|
||||||
Bluef(ICON_SECRET+" Generating secret %s\n", cf)
|
logger.Bluef(ICON_SECRET+" Generating secret %s\n", cf)
|
||||||
store = helm.NewSecret(cf)
|
store = helm.NewSecret(cf)
|
||||||
}
|
}
|
||||||
if err := store.AddEnvFile(envfile); err != nil {
|
if err := store.AddEnvFile(envfile); err != nil {
|
||||||
ActivateColors = true
|
logger.ActivateColors = true
|
||||||
Red(err.Error())
|
logger.Red(err.Error())
|
||||||
ActivateColors = false
|
logger.ActivateColors = false
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"katenary/compose"
|
"katenary/compose"
|
||||||
"katenary/helm"
|
"katenary/helm"
|
||||||
|
"katenary/logger"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -71,11 +72,30 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
katenary.io/same-pod: http3
|
katenary.io/same-pod: http3
|
||||||
|
|
||||||
|
# unmapped volumes
|
||||||
|
novol:
|
||||||
|
image: nginx
|
||||||
|
volumes:
|
||||||
|
- /tmp/data
|
||||||
|
labels:
|
||||||
|
katenary.io/ports: 80
|
||||||
|
|
||||||
|
# use = sign for environment variables
|
||||||
|
eqenv:
|
||||||
|
image: nginx
|
||||||
|
environment:
|
||||||
|
- SOME_ENV_VAR=some_value
|
||||||
|
- ANOTHER_ENV_VAR=another_value
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
driver: local
|
driver: local
|
||||||
`
|
`
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
logger.NOLOG = true
|
||||||
|
}
|
||||||
|
|
||||||
func setUp(t *testing.T) (string, *compose.Parser) {
|
func setUp(t *testing.T) (string, *compose.Parser) {
|
||||||
p := compose.NewParser("", DOCKER_COMPOSE_YML)
|
p := compose.NewParser("", DOCKER_COMPOSE_YML)
|
||||||
p.Parse("testapp")
|
p.Parse("testapp")
|
||||||
@@ -263,3 +283,54 @@ func TestIngress(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check unmapped volumes
|
||||||
|
func TestUnmappedVolumes(t *testing.T) {
|
||||||
|
tmp, p := setUp(t)
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
for name := range p.Data.Services {
|
||||||
|
if name == "novol" {
|
||||||
|
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
||||||
|
fp, _ := os.Open(path)
|
||||||
|
defer fp.Close()
|
||||||
|
lines, _ := ioutil.ReadAll(fp)
|
||||||
|
for _, line := range strings.Split(string(lines), "\n") {
|
||||||
|
if strings.Contains(line, "novol-data") {
|
||||||
|
t.Error("novol service should not have a volume")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if service using equal sign for environment works
|
||||||
|
func TestEqualSignOnEnv(t *testing.T) {
|
||||||
|
tmp, p := setUp(t)
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
|
||||||
|
// if the name is eqenv, the service should habe environment
|
||||||
|
for name, _ := range p.Data.Services {
|
||||||
|
if name == "eqenv" {
|
||||||
|
path := filepath.Join(tmp, "templates", name+".deployment.yaml")
|
||||||
|
fp, _ := os.Open(path)
|
||||||
|
defer fp.Close()
|
||||||
|
lines, _ := ioutil.ReadAll(fp)
|
||||||
|
match := 0
|
||||||
|
for _, line := range strings.Split(string(lines), "\n") {
|
||||||
|
// we must find the line with the environment variable name
|
||||||
|
if strings.Contains(line, "SOME_ENV_VAR") {
|
||||||
|
// we must find the line with the environment variable value
|
||||||
|
match++
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "ANOTHER_ENV_VAR") {
|
||||||
|
// we must find the line with the environment variable value
|
||||||
|
match++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if match != 2 {
|
||||||
|
t.Error("eqenv service should have 2 environment variables")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -23,7 +23,6 @@ fi
|
|||||||
|
|
||||||
BIN_URL="$BASE/katenary-$OS-$ARCH"
|
BIN_URL="$BASE/katenary-$OS-$ARCH"
|
||||||
|
|
||||||
INSTALL_TYPE="global"
|
|
||||||
if [ "$INSTALL_TYPE" = "local" ]; then
|
if [ "$INSTALL_TYPE" = "local" ]; then
|
||||||
echo "Installing to local directory, installing in $HOME/.local/bin"
|
echo "Installing to local directory, installing in $HOME/.local/bin"
|
||||||
BIN_PATH="$HOME/.local/bin"
|
BIN_PATH="$HOME/.local/bin"
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
package generator
|
package logger
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestColor(t *testing.T) {
|
func TestColor(t *testing.T) {
|
||||||
|
NOLOG = false
|
||||||
Red("Red text")
|
Red("Red text")
|
||||||
Grey("Grey text")
|
Grey("Grey text")
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
package generator
|
package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
type Color int
|
type Color int
|
||||||
|
|
||||||
var ActivateColors = false
|
var ActivateColors = false
|
||||||
|
var NOLOG = false
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GREY Color = 30 + iota
|
GREY Color = 30 + iota
|
||||||
@@ -23,6 +24,9 @@ const (
|
|||||||
var waiter = sync.Mutex{}
|
var waiter = sync.Mutex{}
|
||||||
|
|
||||||
func color(c Color, args ...interface{}) {
|
func color(c Color, args ...interface{}) {
|
||||||
|
if NOLOG {
|
||||||
|
return
|
||||||
|
}
|
||||||
if !ActivateColors {
|
if !ActivateColors {
|
||||||
fmt.Println(args...)
|
fmt.Println(args...)
|
||||||
return
|
return
|
||||||
@@ -35,6 +39,9 @@ func color(c Color, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func colorf(c Color, format string, args ...interface{}) {
|
func colorf(c Color, format string, args ...interface{}) {
|
||||||
|
if NOLOG {
|
||||||
|
return
|
||||||
|
}
|
||||||
if !ActivateColors {
|
if !ActivateColors {
|
||||||
fmt.Printf(format, args...)
|
fmt.Printf(format, args...)
|
||||||
return
|
return
|
Reference in New Issue
Block a user