2021-11-30 12:04:28 +01:00
package generator
import (
"fmt"
2021-12-02 15:42:01 +01:00
"io/ioutil"
2022-04-05 08:05:33 +02:00
"katenary/compose"
2021-12-01 08:31:51 +01:00
"katenary/helm"
2022-04-01 10:43:08 +02:00
"katenary/logger"
2021-12-01 16:50:32 +01:00
"log"
2022-04-05 09:17:18 +02:00
"net/url"
2021-11-30 15:35:32 +01:00
"os"
2021-12-02 15:42:01 +01:00
"path/filepath"
2021-11-30 12:04:28 +01:00
"strconv"
"strings"
"sync"
2022-02-14 14:37:09 +01:00
2022-04-03 16:08:00 +02:00
"github.com/compose-spec/compose-go/types"
2021-11-30 12:04:28 +01:00
)
2021-12-02 10:21:05 +00:00
const (
ICON_PACKAGE = "📦"
ICON_SERVICE = "🔌"
ICON_SECRET = "🔏"
ICON_CONF = "📝"
ICON_STORE = "⚡"
ICON_INGRESS = "🌐"
)
2021-11-30 15:45:36 +01:00
// Values is kept in memory to create a values.yaml file.
2022-04-04 13:52:28 +02:00
var (
Values = make ( map [ string ] map [ string ] interface { } )
VolumeValues = make ( map [ string ] map [ string ] map [ string ] interface { } )
EmptyDirs = [ ] string { }
servicesMap = make ( map [ string ] int )
serviceWaiters = make ( map [ string ] [ ] chan int )
locker = & sync . Mutex { }
dependScript = `
2021-11-30 12:04:28 +01:00
OK = 0
echo "Checking __service__ port"
while [ $ OK != 1 ] ; do
echo - n "."
2022-05-05 11:33:02 +02:00
nc - z ` + helm.ReleaseNameTpl + ` - __service__ __port__ 2 > & 1 > / dev / null && OK = 1 || sleep 1
2021-11-30 12:04:28 +01:00
done
echo
echo "Done"
`
2022-04-04 13:52:28 +02:00
madeDeployments = make ( map [ string ] helm . Deployment , 0 )
)
2022-02-16 17:40:11 +01:00
2021-11-30 15:45:36 +01:00
// Create a Deployment for a given compose.Service. It returns a list of objects: a Deployment and a possible Service (kubernetes represnetation as maps).
2022-04-03 16:08:00 +02:00
func CreateReplicaObject ( name string , s types . ServiceConfig , linked map [ string ] types . ServiceConfig ) chan interface { } {
2022-04-04 13:52:28 +02:00
ret := make ( chan interface { } , len ( s . Ports ) + len ( s . Expose ) + 2 )
2022-02-16 17:40:11 +01:00
go parseService ( name , s , linked , ret )
2021-12-02 10:21:05 +00:00
return ret
}
// This function will try to yied deployment and services based on a service from the compose file structure.
2022-04-03 16:08:00 +02:00
func parseService ( name string , s types . ServiceConfig , linked map [ string ] types . ServiceConfig , ret chan interface { } ) {
2022-04-01 10:43:08 +02:00
logger . Magenta ( ICON_PACKAGE + " Generating deployment for " , name )
2021-11-30 12:04:28 +01:00
2022-04-05 09:17:18 +02:00
deployment := helm . NewDeployment ( name )
2022-02-16 17:40:11 +01:00
2021-11-30 12:04:28 +01:00
container := helm . NewContainer ( name , s . Image , s . Environment , s . Labels )
2022-03-31 14:12:20 +02:00
prepareContainer ( container , s , name )
2022-04-01 10:43:08 +02:00
prepareEnvFromFiles ( name , s , container , ret )
2021-12-02 10:21:05 +00:00
2022-05-05 11:33:02 +02:00
// Set the containers to the deployment
2022-04-05 09:17:18 +02:00
deployment . Spec . Template . Spec . Containers = [ ] * helm . Container { container }
2021-11-30 17:29:42 +01:00
2021-12-02 10:21:05 +00:00
// Prepare volumes
2022-02-16 17:40:11 +01:00
madePVC := make ( map [ string ] bool )
2022-04-05 09:17:18 +02:00
deployment . Spec . Template . Spec . Volumes = prepareVolumes ( name , name , s , container , madePVC , ret )
2022-02-16 17:40:11 +01:00
// Now, for "depends_on" section, it's a bit tricky to get dependencies, see the function below.
2022-04-05 09:17:18 +02:00
deployment . Spec . Template . Spec . InitContainers = prepareInitContainers ( name , s , container )
2021-12-02 15:42:01 +01:00
2022-02-14 14:37:09 +01:00
// Add selectors
selectors := buildSelector ( name , s )
2022-04-05 09:17:18 +02:00
deployment . Spec . Selector = map [ string ] interface { } {
2022-02-14 14:37:09 +01:00
"matchLabels" : selectors ,
2021-11-30 12:04:28 +01:00
}
2022-04-05 09:17:18 +02:00
deployment . Spec . Template . Metadata . Labels = selectors
2021-11-30 12:04:28 +01:00
2022-02-16 17:40:11 +01:00
// Now, the linked services
for lname , link := range linked {
container := helm . NewContainer ( lname , link . Image , link . Environment , link . Labels )
2022-03-31 14:12:20 +02:00
prepareContainer ( container , link , lname )
2022-04-01 10:43:08 +02:00
prepareEnvFromFiles ( lname , link , container , ret )
2022-04-05 09:17:18 +02:00
deployment . Spec . Template . Spec . Containers = append ( deployment . Spec . Template . Spec . Containers , container )
deployment . Spec . Template . Spec . Volumes = append ( deployment . Spec . Template . Spec . Volumes , prepareVolumes ( name , lname , link , container , madePVC , ret ) ... )
deployment . Spec . Template . Spec . InitContainers = append ( deployment . Spec . Template . Spec . InitContainers , prepareInitContainers ( lname , link , container ) ... )
2022-02-16 17:40:11 +01:00
//append ports and expose ports to the deployment, to be able to generate them in the Service file
if len ( link . Ports ) > 0 || len ( link . Expose ) > 0 {
s . Ports = append ( s . Ports , link . Ports ... )
s . Expose = append ( s . Expose , link . Expose ... )
}
}
// Remove duplicates in volumes
volumes := make ( [ ] map [ string ] interface { } , 0 )
done := make ( map [ string ] bool )
2022-04-05 09:17:18 +02:00
for _ , vol := range deployment . Spec . Template . Spec . Volumes {
2022-02-16 17:40:11 +01:00
name := vol [ "name" ] . ( string )
if _ , ok := done [ name ] ; ok {
continue
} else {
done [ name ] = true
volumes = append ( volumes , vol )
}
}
2022-04-05 09:17:18 +02:00
deployment . Spec . Template . Spec . Volumes = volumes
2021-11-30 12:04:28 +01:00
2022-02-14 14:37:09 +01:00
// Then, create Services and possible Ingresses for ingress labels, "ports" and "expose" section
2021-11-30 12:04:28 +01:00
if len ( s . Ports ) > 0 || len ( s . Expose ) > 0 {
2022-02-14 14:37:09 +01:00
for _ , s := range generateServicesAndIngresses ( name , s ) {
2021-12-02 10:21:05 +00:00
ret <- s
}
2021-11-30 12:04:28 +01:00
}
2021-12-02 10:21:05 +00:00
// add the volumes in Values
2021-11-30 17:29:42 +01:00
if len ( VolumeValues [ name ] ) > 0 {
2022-04-05 08:05:33 +02:00
AddValues ( name , map [ string ] interface { } { "persistence" : VolumeValues [ name ] } )
2021-11-30 17:29:42 +01:00
}
2021-12-02 10:21:05 +00:00
// the deployment is ready, give it
2022-04-05 09:17:18 +02:00
ret <- deployment
2021-11-30 15:35:32 +01:00
2021-12-02 10:21:05 +00:00
// and then, we can say that it's the end
ret <- nil
2021-11-30 12:04:28 +01:00
}
2022-03-31 14:12:20 +02:00
// prepareContainer assigns image, command, env, and labels to a container.
2022-04-03 16:08:00 +02:00
func prepareContainer ( container * helm . Container , service types . ServiceConfig , servicename string ) {
2022-04-01 08:04:37 +02:00
// if there is no image name, this should fail!
if service . Image == "" {
log . Fatal ( ICON_PACKAGE + " No image name for service " , servicename )
}
2022-03-31 14:12:20 +02:00
container . Image = "{{ .Values." + servicename + ".image }}"
container . Command = service . Command
2022-04-05 08:05:33 +02:00
AddValues ( servicename , map [ string ] interface { } { "image" : service . Image } )
2022-03-31 14:12:20 +02:00
prepareProbes ( servicename , service , container )
generateContainerPorts ( service , servicename , container )
}
2021-11-30 15:45:36 +01:00
// Create a service (k8s).
2022-04-03 16:08:00 +02:00
func generateServicesAndIngresses ( name string , s types . ServiceConfig ) [ ] interface { } {
2021-11-30 12:04:28 +01:00
2022-02-14 14:37:09 +01:00
ret := make ( [ ] interface { } , 0 ) // can handle helm.Service or helm.Ingress
2022-04-01 10:43:08 +02:00
logger . Magenta ( ICON_SERVICE + " Generating service for " , name )
2021-12-01 15:17:34 +01:00
ks := helm . NewService ( name )
2021-11-30 15:35:32 +01:00
2022-04-04 09:53:36 +02:00
for _ , p := range s . Ports {
2022-04-04 13:52:28 +02:00
target := int ( p . Target )
ks . Spec . Ports = append ( ks . Spec . Ports , helm . NewServicePort ( target , target ) )
2021-11-30 12:04:28 +01:00
}
ks . Spec . Selector = buildSelector ( name , s )
2021-12-01 08:31:51 +01:00
ret = append ( ret , ks )
2021-12-02 14:56:51 +01:00
if v , ok := s . Labels [ helm . LABEL_INGRESS ] ; ok {
2021-12-02 10:21:05 +00:00
port , err := strconv . Atoi ( v )
if err != nil {
2021-12-05 09:05:48 +01:00
log . Fatalf ( "The given port \"%v\" as ingress port in \"%s\" service is not an integer\n" , v , name )
2021-12-02 10:21:05 +00:00
}
2022-04-01 10:43:08 +02:00
logger . Cyanf ( ICON_INGRESS + " Create an ingress for port %d on %s service\n" , port , name )
2021-12-02 10:21:05 +00:00
ing := createIngress ( name , port , s )
2021-12-01 08:31:51 +01:00
ret = append ( ret , ing )
2021-11-30 12:04:28 +01:00
}
2021-12-01 16:50:32 +01:00
if len ( s . Expose ) > 0 {
2022-04-01 10:43:08 +02:00
logger . Magenta ( ICON_SERVICE + " Generating service for " , name + "-external" )
2021-12-01 16:50:32 +01:00
ks := helm . NewService ( name + "-external" )
ks . Spec . Type = "NodePort"
2022-04-03 16:08:00 +02:00
for _ , expose := range s . Expose {
p , _ := strconv . Atoi ( expose )
2021-12-01 16:50:32 +01:00
ks . Spec . Ports = append ( ks . Spec . Ports , helm . NewServicePort ( p , p ) )
}
ks . Spec . Selector = buildSelector ( name , s )
ret = append ( ret , ks )
}
2021-12-01 08:31:51 +01:00
return ret
2021-11-30 12:04:28 +01:00
}
2021-11-30 15:45:36 +01:00
// Create an ingress.
2022-04-03 16:08:00 +02:00
func createIngress ( name string , port int , s types . ServiceConfig ) * helm . Ingress {
2021-11-30 12:04:28 +01:00
ingress := helm . NewIngress ( name )
2022-04-05 08:05:33 +02:00
ingressVal := map [ string ] interface { } {
2021-11-30 15:35:32 +01:00
"class" : "nginx" ,
2021-12-02 10:21:05 +00:00
"host" : name + "." + helm . Appname + ".tld" ,
2021-11-30 12:04:28 +01:00
"enabled" : false ,
}
2022-04-05 08:05:33 +02:00
AddValues ( name , map [ string ] interface { } { "ingress" : ingressVal } )
2021-11-30 12:04:28 +01:00
ingress . Spec . Rules = [ ] helm . IngressRule {
{
Host : fmt . Sprintf ( "{{ .Values.%s.ingress.host }}" , name ) ,
Http : helm . IngressHttp {
Paths : [ ] helm . IngressPath { {
Path : "/" ,
PathType : "Prefix" ,
2022-02-16 10:37:46 +01:00
Backend : & helm . IngressBackend {
2021-11-30 12:04:28 +01:00
Service : helm . IngressService {
2022-05-05 11:33:02 +02:00
Name : helm . ReleaseNameTpl + "-" + name ,
2021-11-30 12:04:28 +01:00
Port : map [ string ] interface { } {
"number" : port ,
} ,
} ,
} ,
} } ,
} ,
} ,
}
2021-11-30 15:35:32 +01:00
ingress . SetIngressClass ( name )
2021-11-30 12:04:28 +01:00
2021-12-01 08:31:51 +01:00
return ingress
2021-11-30 12:04:28 +01:00
}
2022-02-14 14:37:09 +01:00
// Build the selector for the service.
2022-04-03 16:08:00 +02:00
func buildSelector ( name string , s types . ServiceConfig ) map [ string ] string {
2021-11-30 12:04:28 +01:00
return map [ string ] string {
"katenary.io/component" : name ,
2022-05-05 11:33:02 +02:00
"katenary.io/release" : helm . ReleaseNameTpl ,
2021-11-30 12:04:28 +01:00
}
}
2021-12-02 15:42:01 +01:00
2022-02-14 14:37:09 +01:00
// buildCMFromPath generates a ConfigMap from a path.
2021-12-02 15:42:01 +01:00
func buildCMFromPath ( path string ) * helm . ConfigMap {
stat , err := os . Stat ( path )
if err != nil {
return nil
}
files := make ( map [ string ] string , 0 )
if stat . IsDir ( ) {
found , _ := filepath . Glob ( path + "/*" )
for _ , f := range found {
if s , err := os . Stat ( f ) ; err != nil || s . IsDir ( ) {
if err != nil {
fmt . Fprintf ( os . Stderr , "An error occured reading volume path %s\n" , err . Error ( ) )
} else {
2022-04-01 10:43:08 +02:00
logger . ActivateColors = true
logger . Yellowf ( "Warning, %s is a directory, at this time we only " +
2021-12-02 15:42:01 +01:00
"can create configmap for first level file list\n" , f )
2022-04-01 10:43:08 +02:00
logger . ActivateColors = false
2021-12-02 15:42:01 +01:00
}
continue
}
_ , filename := filepath . Split ( f )
c , _ := ioutil . ReadFile ( f )
files [ filename ] = string ( c )
}
}
cm := helm . NewConfigMap ( "" )
cm . Data = files
return cm
}
2022-02-14 14:37:09 +01:00
// generateContainerPorts add the container ports of a service.
2022-04-03 16:08:00 +02:00
func generateContainerPorts ( s types . ServiceConfig , name string , container * helm . Container ) {
2022-02-14 14:37:09 +01:00
exists := make ( map [ int ] string )
for _ , port := range s . Ports {
portName := name
for _ , n := range exists {
if name == n {
2022-04-03 16:08:00 +02:00
portName = fmt . Sprintf ( "%s-%d" , name , port . Target )
2022-02-14 14:37:09 +01:00
}
}
container . Ports = append ( container . Ports , & helm . ContainerPort {
Name : portName ,
2022-04-03 16:08:00 +02:00
ContainerPort : int ( port . Target ) ,
2022-02-14 14:37:09 +01:00
} )
2022-04-03 16:08:00 +02:00
exists [ int ( port . Target ) ] = name
2022-02-14 14:37:09 +01:00
}
// manage the "expose" section to be a NodePort in Kubernetes
2022-04-03 16:08:00 +02:00
for _ , expose := range s . Expose {
port , _ := strconv . Atoi ( expose )
2022-02-14 14:37:09 +01:00
if _ , exist := exists [ port ] ; exist {
continue
}
container . Ports = append ( container . Ports , & helm . ContainerPort {
Name : name ,
ContainerPort : port ,
} )
}
}
// prepareVolumes add the volumes of a service.
2022-04-03 16:08:00 +02:00
func prepareVolumes ( deployment , name string , s types . ServiceConfig , container * helm . Container , madePVC map [ string ] bool , ret chan interface { } ) [ ] map [ string ] interface { } {
2022-02-14 14:37:09 +01:00
volumes := make ( [ ] map [ string ] interface { } , 0 )
mountPoints := make ( [ ] interface { } , 0 )
configMapsVolumes := make ( [ ] string , 0 )
if v , ok := s . Labels [ helm . LABEL_VOL_CM ] ; ok {
configMapsVolumes = strings . Split ( v , "," )
}
2022-04-01 09:22:00 +02:00
2022-04-03 16:08:00 +02:00
for _ , vol := range s . Volumes {
2022-04-01 09:22:00 +02:00
2022-04-03 16:08:00 +02:00
volname := vol . Source
volepath := vol . Target
2022-02-14 14:37:09 +01:00
2022-04-05 09:33:49 +02:00
if volname == "" {
logger . ActivateColors = true
logger . Yellowf ( "Warning, volume source to %s is empty for %s -- skipping\n" , volepath , name )
logger . ActivateColors = false
continue
}
2022-02-14 14:37:09 +01:00
isCM := false
for _ , cmVol := range configMapsVolumes {
cmVol = strings . TrimSpace ( cmVol )
if volname == cmVol {
isCM = true
break
}
}
if ! isCM && ( strings . HasPrefix ( volname , "." ) || strings . HasPrefix ( volname , "/" ) ) {
// local volume cannt be mounted
2022-04-01 10:43:08 +02:00
logger . ActivateColors = true
logger . Redf ( "You cannot, at this time, have local volume in %s deployment\n" , name )
logger . ActivateColors = false
2022-02-14 14:37:09 +01:00
continue
}
if isCM {
2022-02-17 11:38:23 +01:00
// check if the volname path points on a file, if so, we need to add subvolume to the interface
2022-04-04 13:52:28 +02:00
stat , err := os . Stat ( volname )
if err != nil {
logger . ActivateColors = true
logger . Redf ( "An error occured reading volume path %s\n" , err . Error ( ) )
logger . ActivateColors = false
continue
}
2022-02-17 11:38:23 +01:00
pointToFile := ""
if ! stat . IsDir ( ) {
pointToFile = filepath . Base ( volname )
volname = filepath . Dir ( volname )
}
2022-02-14 14:37:09 +01:00
// the volume is a path and it's explicitally asked to be a configmap in labels
cm := buildCMFromPath ( volname )
volname = strings . Replace ( volname , "./" , "" , 1 )
2022-02-17 11:04:04 +01:00
volname = strings . ReplaceAll ( volname , "/" , "-" )
2022-02-14 14:37:09 +01:00
volname = strings . ReplaceAll ( volname , "." , "-" )
2022-05-05 11:33:02 +02:00
cm . K8sBase . Metadata . Name = helm . ReleaseNameTpl + "-" + volname + "-" + name
2022-02-17 11:38:23 +01:00
2022-02-14 14:37:09 +01:00
// build a configmap from the volume path
volumes = append ( volumes , map [ string ] interface { } {
"name" : volname ,
"configMap" : map [ string ] string {
"name" : cm . K8sBase . Metadata . Name ,
} ,
} )
2022-02-17 11:38:23 +01:00
if len ( pointToFile ) > 0 {
mountPoints = append ( mountPoints , map [ string ] interface { } {
"name" : volname ,
"mountPath" : volepath ,
"subPath" : pointToFile ,
} )
} else {
mountPoints = append ( mountPoints , map [ string ] interface { } {
"name" : volname ,
"mountPath" : volepath ,
} )
}
2022-02-14 14:37:09 +01:00
ret <- cm
} else {
// rmove minus sign from volume name
volname = strings . ReplaceAll ( volname , "-" , "" )
2022-02-16 17:40:11 +01:00
isEmptyDir := false
for _ , v := range EmptyDirs {
v = strings . ReplaceAll ( v , "-" , "" )
if v == volname {
volumes = append ( volumes , map [ string ] interface { } {
"name" : volname ,
"emptyDir" : map [ string ] string { } ,
} )
2022-02-17 10:43:07 +01:00
mountPoints = append ( mountPoints , map [ string ] interface { } {
"name" : volname ,
"mountPath" : volepath ,
} )
container . VolumeMounts = mountPoints
2022-02-16 17:40:11 +01:00
isEmptyDir = true
break
}
}
if isEmptyDir {
continue
}
2022-02-14 14:37:09 +01:00
volumes = append ( volumes , map [ string ] interface { } {
"name" : volname ,
"persistentVolumeClaim" : map [ string ] string {
2022-05-05 11:33:02 +02:00
"claimName" : helm . ReleaseNameTpl + "-" + volname ,
2022-02-14 14:37:09 +01:00
} ,
} )
mountPoints = append ( mountPoints , map [ string ] interface { } {
"name" : volname ,
"mountPath" : volepath ,
} )
2022-04-01 10:43:08 +02:00
logger . Yellow ( ICON_STORE + " Generate volume values" , volname , "for container named" , name , "in deployment" , deployment )
2022-04-05 08:05:33 +02:00
AddVolumeValues ( deployment , volname , map [ string ] interface { } {
2022-02-14 14:37:09 +01:00
"enabled" : false ,
"capacity" : "1Gi" ,
2022-04-05 08:05:33 +02:00
} )
2022-02-16 17:40:11 +01:00
if _ , ok := madePVC [ deployment + volname ] ; ! ok {
madePVC [ deployment + volname ] = true
pvc := helm . NewPVC ( deployment , volname )
ret <- pvc
}
2022-02-14 14:37:09 +01:00
}
}
container . VolumeMounts = mountPoints
return volumes
}
// prepareInitContainers add the init containers of a service.
2022-04-03 16:08:00 +02:00
func prepareInitContainers ( name string , s types . ServiceConfig , container * helm . Container ) [ ] * helm . Container {
2022-02-14 14:37:09 +01:00
// We need to detect others services, but we probably not have parsed them yet, so
// we will wait for them for a while.
initContainers := make ( [ ] * helm . Container , 0 )
2022-04-03 16:09:33 +02:00
for dp := range s . DependsOn {
2022-02-14 14:37:09 +01:00
c := helm . NewContainer ( "check-" + dp , "busybox" , nil , s . Labels )
command := strings . ReplaceAll ( strings . TrimSpace ( dependScript ) , "__service__" , dp )
foundPort := - 1
2022-04-04 09:53:36 +02:00
locker . Lock ( )
if defaultPort , ok := servicesMap [ dp ] ; ! ok {
logger . Redf ( "Error while getting port for service %s\n" , dp )
os . Exit ( 1 )
2022-02-14 14:37:09 +01:00
} else {
foundPort = defaultPort
}
2022-04-04 13:52:28 +02:00
locker . Unlock ( )
2022-02-14 14:37:09 +01:00
if foundPort == - 1 {
log . Fatalf (
"ERROR, the %s service is waiting for %s port number, " +
"but it is never discovered. You must declare at least one port in " +
"the \"ports\" section of the service in the docker-compose file" ,
name ,
dp ,
)
}
command = strings . ReplaceAll ( command , "__port__" , strconv . Itoa ( foundPort ) )
c . Command = [ ] string {
"sh" ,
"-c" ,
command ,
}
initContainers = append ( initContainers , c )
}
return initContainers
}
// prepareProbes generate http/tcp/command probes for a service.
2022-04-03 16:08:00 +02:00
func prepareProbes ( name string , s types . ServiceConfig , container * helm . Container ) {
2022-04-05 09:17:18 +02:00
// first, check if there is no label for the probe
if check , ok := s . Labels [ helm . LABEL_HEALTHCHECK ] ; ok {
check = strings . TrimSpace ( check )
// get the port of the "url" check
if checkurl , err := url . Parse ( check ) ; err == nil {
if err == nil {
container . LivenessProbe = buildProtoProbe ( checkurl )
}
} else {
// it's a command
2022-05-05 09:24:51 +02:00
container . LivenessProbe = helm . NewProbe ( 0 , 0 , 0 , 0 )
container . LivenessProbe . Exec = & helm . Exec {
Command : [ ] string {
"sh" ,
"-c" ,
check ,
2022-04-05 09:17:18 +02:00
} ,
}
}
return // label overrides everything
}
// if not, we will use the default one
if s . HealthCheck != nil {
container . LivenessProbe = buildCommandProbe ( s )
}
}
2022-05-05 11:33:02 +02:00
// buildProtoProbe builds a probe from a url that can be http or tcp.
2022-04-05 09:17:18 +02:00
func buildProtoProbe ( u * url . URL ) * helm . Probe {
2022-05-05 09:24:51 +02:00
probe := helm . NewProbe ( 0 , 0 , 0 , 0 )
2022-04-05 09:17:18 +02:00
port , err := strconv . Atoi ( u . Port ( ) )
if err != nil {
port = 80
}
2022-05-05 09:24:51 +02:00
path := "/"
if u . Path != "" {
path = u . Path
}
2022-04-05 09:17:18 +02:00
switch u . Scheme {
case "http" , "https" :
probe . HttpGet = & helm . HttpGet {
2022-05-05 09:24:51 +02:00
Path : path ,
2022-04-05 09:17:18 +02:00
Port : port ,
}
case "tcp" :
probe . TCP = & helm . TCP {
Port : port ,
}
default :
logger . Redf ( "Error while parsing healthcheck url %s\n" , u . String ( ) )
os . Exit ( 1 )
}
2022-05-05 09:24:51 +02:00
return probe
2022-04-05 09:17:18 +02:00
}
func buildCommandProbe ( s types . ServiceConfig ) * helm . Probe {
// Get the first element of the command from ServiceConfig
first := s . HealthCheck . Test [ 0 ]
2022-05-05 09:24:51 +02:00
p := helm . NewProbe ( 0 , 0 , 0 , 0 )
2022-04-05 09:17:18 +02:00
switch first {
case "CMD" , "CMD-SHELL" :
// CMD or CMD-SHELL
2022-05-05 09:24:51 +02:00
p . Exec = & helm . Exec {
Command : s . HealthCheck . Test [ 1 : ] ,
2022-04-05 09:17:18 +02:00
}
2022-05-05 09:24:51 +02:00
return p
2022-04-05 09:17:18 +02:00
default :
// badly made but it should work...
2022-05-05 09:24:51 +02:00
p . Exec = & helm . Exec {
Command : [ ] string ( s . HealthCheck . Test ) ,
2022-04-05 09:17:18 +02:00
}
2022-05-05 09:24:51 +02:00
return p
2022-04-05 09:17:18 +02:00
}
2022-02-14 14:37:09 +01:00
}
// prepareEnvFromFiles generate configMap or secrets from environment files.
2022-04-03 16:08:00 +02:00
func prepareEnvFromFiles ( name string , s types . ServiceConfig , container * helm . Container , ret chan interface { } ) {
2022-02-14 14:37:09 +01:00
// prepare secrets
secretsFiles := make ( [ ] string , 0 )
if v , ok := s . Labels [ helm . LABEL_ENV_SECRET ] ; ok {
secretsFiles = strings . Split ( v , "," )
}
// manage environment files (env_file in compose)
2022-04-03 16:08:00 +02:00
for _ , envfile := range s . EnvFile {
2022-02-14 14:37:09 +01:00
f := strings . ReplaceAll ( envfile , "_" , "-" )
f = strings . ReplaceAll ( f , ".env" , "" )
f = strings . ReplaceAll ( f , "." , "" )
f = strings . ReplaceAll ( f , "/" , "" )
cf := f + "-" + name
isSecret := false
for _ , s := range secretsFiles {
if s == envfile {
isSecret = true
}
}
var store helm . InlineConfig
if ! isSecret {
2022-04-01 10:43:08 +02:00
logger . Bluef ( ICON_CONF + " Generating configMap %s\n" , cf )
2022-02-14 14:37:09 +01:00
store = helm . NewConfigMap ( cf )
} else {
2022-04-01 10:43:08 +02:00
logger . Bluef ( ICON_SECRET + " Generating secret %s\n" , cf )
2022-02-14 14:37:09 +01:00
store = helm . NewSecret ( cf )
}
2022-04-05 08:05:33 +02:00
envfile = filepath . Join ( compose . GetCurrentDir ( ) , envfile )
2022-02-14 14:37:09 +01:00
if err := store . AddEnvFile ( envfile ) ; err != nil {
2022-04-01 10:43:08 +02:00
logger . ActivateColors = true
logger . Red ( err . Error ( ) )
logger . ActivateColors = false
2022-02-14 14:37:09 +01:00
os . Exit ( 2 )
}
section := "configMapRef"
if isSecret {
section = "secretRef"
}
container . EnvFrom = append ( container . EnvFrom , map [ string ] map [ string ] string {
section : {
"name" : store . Metadata ( ) . Name ,
} ,
} )
2022-05-05 08:05:15 +02:00
// read the envfile and remove them from the container environment or secret
envs := readEnvFile ( envfile )
for varname := range envs {
if ! isSecret {
// remove varname from container
for i , s := range container . Env {
if s . Name == varname {
container . Env = append ( container . Env [ : i ] , container . Env [ i + 1 : ] ... )
}
}
}
}
2022-02-14 14:37:09 +01:00
ret <- store
}
}
2022-04-05 08:05:33 +02:00
2022-05-05 11:33:02 +02:00
// AddValues adds values to the values.yaml map.
2022-04-05 08:05:33 +02:00
func AddValues ( servicename string , values map [ string ] interface { } ) {
locker . Lock ( )
defer locker . Unlock ( )
if _ , ok := values [ servicename ] ; ! ok {
Values [ servicename ] = make ( map [ string ] interface { } )
}
for k , v := range values {
Values [ servicename ] [ k ] = v
}
}
2022-05-05 11:33:02 +02:00
// AddVolumeValues add a volume to the values.yaml map for the given deployment name.
2022-04-05 08:05:33 +02:00
func AddVolumeValues ( deployment string , volname string , values map [ string ] interface { } ) {
locker . Lock ( )
defer locker . Unlock ( )
if _ , ok := VolumeValues [ deployment ] ; ! ok {
VolumeValues [ deployment ] = make ( map [ string ] map [ string ] interface { } )
}
VolumeValues [ deployment ] [ volname ] = values
}
2022-05-05 08:05:15 +02:00
func readEnvFile ( envfilename string ) map [ string ] string {
env := make ( map [ string ] string )
content , err := ioutil . ReadFile ( envfilename )
if err != nil {
logger . ActivateColors = true
logger . Red ( err . Error ( ) )
logger . ActivateColors = false
os . Exit ( 2 )
}
// each value is on a separate line with KEY=value
lines := strings . Split ( string ( content ) , "\n" )
for _ , line := range lines {
if strings . Contains ( line , "=" ) {
kv := strings . SplitN ( line , "=" , 2 )
env [ kv [ 0 ] ] = kv [ 1 ]
}
}
return env
}