diff --git a/cli/app/app.go b/cli/app/app.go index f965aabb..aca55167 100644 --- a/cli/app/app.go +++ b/cli/app/app.go @@ -20,13 +20,12 @@ import ( "fmt" "math/rand" "os" - //"strconv" + "strconv" "strings" "github.com/Sirupsen/logrus" "github.com/urfave/cli" - "github.com/docker/libcompose/project" "github.com/docker/docker/api/client/bundlefile" "encoding/json" @@ -38,14 +37,12 @@ import ( //client "k8s.io/kubernetes/pkg/client/unversioned" //cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/runtime" - //"k8s.io/kubernetes/pkg/util/intstr" + "k8s.io/kubernetes/pkg/util/intstr" "github.com/fatih/structs" "github.com/ghodss/yaml" ) -type ProjectAction func(project *project.Project, c *cli.Context) - const letterBytes = "abcdefghijklmnopqrstuvwxyz0123456789" var unsupportedKey = map[string]string{ @@ -97,11 +94,10 @@ func BeforeApp(c *cli.Context) error { if c.GlobalBool("verbose") { logrus.SetLevel(logrus.DebugLevel) } - // logrus.Warning("Note: This is an experimental alternate implementation of the Docker Compose CLI (https://github.com/docker/compose)") return nil } -// ProjectKuberPS lists all rc, svc. +// Ps lists all rc, svc. func Ps(c *cli.Context) { //factory := cmdutil.NewFactory(nil) //clientConfig, err := factory.ClientConfig() @@ -176,7 +172,7 @@ func Ps(c *cli.Context) { } -// ProjectKuberDelete deletes all rc, svc. +// Delete deletes all rc, svc. func Delete(c *cli.Context) { //factory := cmdutil.NewFactory(nil) //clientConfig, err := factory.ClientConfig() @@ -204,7 +200,7 @@ func Delete(c *cli.Context) { //} } -// ProjectKuberScale scales rc. +// Scale scales rc. func Scale(c *cli.Context) { //factory := cmdutil.NewFactory(nil) //clientConfig, err := factory.ClientConfig() @@ -395,11 +391,11 @@ func initRS(name string, service ServiceConfig) *extensions.ReplicaSet { } // Configure the environment variables. -func configEnvs(name string, service ServiceConfig) ([]api.EnvVar) { +func configEnvs(name string, service ServiceConfig) []api.EnvVar { envs := []api.EnvVar{} for _, v := range service.Environment { envs = append(envs, api.EnvVar{ - Name: v.Name, + Name: v.Name, Value: v.Value, }) } @@ -411,111 +407,86 @@ func configEnvs(name string, service ServiceConfig) ([]api.EnvVar) { func configVolumes(service ServiceConfig) ([]api.VolumeMount, []api.Volume) { volumesMount := []api.VolumeMount{} volumes := []api.Volume{} - //for _, volume := range service.Volumes { - // var character string = ":" - // if strings.Contains(volume, character) { - // hostDir := volume[0:strings.Index(volume, character)] - // hostDir = strings.TrimSpace(hostDir) - // containerDir := volume[strings.Index(volume, character)+1:] - // containerDir = strings.TrimSpace(containerDir) - // - // // check if ro/rw mode is defined - // var readonly bool = true - // if strings.Index(volume, character) != strings.LastIndex(volume, character) { - // mode := volume[strings.LastIndex(volume, character)+1:] - // if strings.Compare(mode, "rw") == 0 { - // readonly = false - // } - // containerDir = containerDir[0:strings.Index(containerDir, character)] - // } - // - // // volumeName = random string of 20 chars - // volumeName := RandStringBytes(20) - // - // volumesMount = append(volumesMount, api.VolumeMount{Name: volumeName, ReadOnly: readonly, MountPath: containerDir}) - // p := &api.HostPathVolumeSource{ - // Path: hostDir, - // } - // //p.Path = hostDir - // volumeSource := api.VolumeSource{HostPath: p} - // volumes = append(volumes, api.Volume{Name: volumeName, VolumeSource: volumeSource}) - // } - //} + for _, volume := range service.Volumes { + character := ":" + if strings.Contains(volume, character) { + hostDir := volume[0:strings.Index(volume, character)] + hostDir = strings.TrimSpace(hostDir) + containerDir := volume[strings.Index(volume, character)+1:] + containerDir = strings.TrimSpace(containerDir) + + // check if ro/rw mode is defined + readonly := true + if strings.Index(volume, character) != strings.LastIndex(volume, character) { + mode := volume[strings.LastIndex(volume, character)+1:] + if strings.Compare(mode, "rw") == 0 { + readonly = false + } + containerDir = containerDir[0:strings.Index(containerDir, character)] + } + + // volumeName = random string of 20 chars + volumeName := RandStringBytes(20) + + volumesMount = append(volumesMount, api.VolumeMount{Name: volumeName, ReadOnly: readonly, MountPath: containerDir}) + p := &api.HostPathVolumeSource{ + Path: hostDir, + } + //p.Path = hostDir + volumeSource := api.VolumeSource{HostPath: p} + volumes = append(volumes, api.Volume{Name: volumeName, VolumeSource: volumeSource}) + } + } return volumesMount, volumes } // Configure the container ports. -func configPorts(name string, service ServiceConfig) ([]api.ContainerPort, string) { +func configPorts(name string, service ServiceConfig) []api.ContainerPort { ports := []api.ContainerPort{} - //for _, port := range service.Port { - // var character string = ":" - // if strings.Contains(port, character) { - // //portNumber := port[0:strings.Index(port, character)] - // targetPortNumber := port[strings.Index(port, character)+1:] - // targetPortNumber = strings.TrimSpace(targetPortNumber) - // targetPortNumberInt, err := strconv.Atoi(targetPortNumber) - // if err != nil { - // return nil, "Invalid container port " + port + " for service " + name - // } - // ports = append(ports, api.ContainerPort{ContainerPort: int32(targetPortNumberInt)}) - // } else { - // portNumber, err := strconv.Atoi(port) - // if err != nil { - // return nil, "Invalid container port " + port + " for service " + name - // } - // ports = append(ports, api.ContainerPort{ContainerPort: int32(portNumber)}) - // } - //} - //return ports, "" for _, port := range service.Port { + var p api.Protocol + switch port.Protocol { + default: + p = api.ProtocolTCP + case ProtocolTCP: + p = api.ProtocolTCP + case ProtocolUDP: + p = api.ProtocolUDP + } ports = append(ports, api.ContainerPort{ - HostPort: port.HostPort, + HostPort: port.HostPort, ContainerPort: port.ContainerPort, - //Protocol: port.Protocol, + Protocol: p, }) } - return ports, "" + return ports } // Configure the container service ports. -func configServicePorts(name string, service ServiceConfig) ([]api.ServicePort, string) { +func configServicePorts(name string, service ServiceConfig) []api.ServicePort { servicePorts := []api.ServicePort{} - //for _, port := range service.Ports { - // var character string = ":" - // if strings.Contains(port, character) { - // portNumber := port[0:strings.Index(port, character)] - // portNumber = strings.TrimSpace(portNumber) - // targetPortNumber := port[strings.Index(port, character)+1:] - // targetPortNumber = strings.TrimSpace(targetPortNumber) - // portNumberInt, err := strconv.Atoi(portNumber) - // if err != nil { - // return nil, "Invalid container port " + port + " for service " + name - // } - // targetPortNumberInt, err1 := strconv.Atoi(targetPortNumber) - // if err1 != nil { - // return nil, "Invalid container port " + port + " for service " + name - // } - // var targetPort intstr.IntOrString - // targetPort.StrVal = targetPortNumber - // targetPort.IntVal = int32(targetPortNumberInt) - // servicePorts = append(servicePorts, api.ServicePort{Port: int32(portNumberInt), Name: portNumber, Protocol: "TCP", TargetPort: targetPort}) - // } else { - // portNumber, err := strconv.Atoi(port) - // if err != nil { - // return nil, "Invalid container port " + port + " for service " + name - // } - // var targetPort intstr.IntOrString - // targetPort.StrVal = strconv.Itoa(portNumber) - // targetPort.IntVal = int32(portNumber) - // servicePorts = append(servicePorts, api.ServicePort{Port: int32(portNumber), Name: strconv.Itoa(portNumber), Protocol: "TCP", TargetPort: targetPort}) - // } - //} - - //for _, port := range service.Port { - // - //} - return servicePorts, "" + for _, port := range service.Port { + var p api.Protocol + switch port.Protocol { + default: + p = api.ProtocolTCP + case ProtocolTCP: + p = api.ProtocolTCP + case ProtocolUDP: + p = api.ProtocolUDP + } + var targetPort intstr.IntOrString + targetPort.IntVal = port.HostPort + targetPort.StrVal = strconv.Itoa(int(port.HostPort)) + servicePorts = append(servicePorts, api.ServicePort{ + Name: strconv.Itoa(int(port.ContainerPort)), + Protocol: p, + Port: port.ContainerPort, + TargetPort: targetPort, + }) + } + return servicePorts } // Transform data to json/yaml @@ -536,7 +507,7 @@ func transformer(v interface{}, entity string, generateYaml bool) ([]byte, strin func loadEnvVars(service bundlefile.Service) ([]EnvVar, string) { envs := []EnvVar{} for _, env := range service.Env { - var character string = "=" + character := "=" if strings.Contains(env, character) { value := env[strings.Index(env, character)+1:] name := env[0:strings.Index(env, character)] @@ -549,7 +520,7 @@ func loadEnvVars(service bundlefile.Service) ([]EnvVar, string) { } else { character = ":" if strings.Contains(env, character) { - var charQuote string = "'" + charQuote := "'" value := env[strings.Index(env, character)+1:] name := env[0:strings.Index(env, character)] name = strings.TrimSpace(name) @@ -569,9 +540,40 @@ func loadEnvVars(service bundlefile.Service) ([]EnvVar, string) { return envs, "" } +// load Ports from bundles file +func loadPorts(service bundlefile.Service) ([]Ports, string) { + ports := []Ports{} + for _, port := range service.Ports { + var p Protocol + switch port.Protocol { + default: + p = ProtocolTCP + case "TCP": + p = ProtocolTCP + case "UDP": + p = ProtocolUDP + } + ports = append(ports, Ports{ + HostPort: int32(port.Port), + ContainerPort: int32(port.Port), + Protocol: p, + }) + } + return ports, "" +} + +// load Image from bundles file +func loadImage(service bundlefile.Service) (string, string) { + character := "@" + if strings.Contains(service.Image, character) { + return service.Image[0:strings.Index(service.Image, character)], "" + } + return "", "Invalid image format" +} + // Load DAB file into KomposeObject -func loadBundlesFile(file string) (KomposeObject) { - kObject := KomposeObject{ +func loadBundlesFile(file string) KomposeObject { + komposeObject := KomposeObject{ ServiceConfigs: make(map[string]ServiceConfig), } buf, err := ioutil.ReadFile(file) @@ -586,35 +588,44 @@ func loadBundlesFile(file string) (KomposeObject) { for name, service := range bundle.Services { serviceConfig := ServiceConfig{} - serviceConfig.Image = service.Image serviceConfig.Command = service.Command serviceConfig.Args = service.Args + serviceConfig.Labels = service.Labels + + image, err := loadImage(service) + if err != "" { + logrus.Fatalf("Failed to load image from bundles file: " + err) + } + serviceConfig.Image = image envs, err := loadEnvVars(service) if err != "" { logrus.Fatalf("Failed to load envvar from bundles file: " + err) } - serviceConfig.Environment = envs - serviceConfig.Labels = service.Labels + + ports, err := loadPorts(service) + if err != "" { + logrus.Fatalf("Failed to load ports from bundles file: " + err) + } + serviceConfig.Port = ports + if service.WorkingDir != nil { serviceConfig.WorkingDir = *service.WorkingDir } - kObject.ServiceConfigs[name] = serviceConfig + + komposeObject.ServiceConfigs[name] = serviceConfig } - - fmt.Println(kObject) - - return kObject + return komposeObject } // Convert komposeObject to K8S controllers func komposeConvert(komposeObject KomposeObject, toStdout, createD, createRS, createDS, createChart, generateYaml bool, replicas int, inputFile string, outFile string, f *os.File) { - var mServices map[string][]byte = make(map[string][]byte) - var mReplicationControllers map[string][]byte = make(map[string][]byte) - var mDeployments map[string][]byte = make(map[string][]byte) - var mDaemonSets map[string][]byte = make(map[string][]byte) - var mReplicaSets map[string][]byte = make(map[string][]byte) + mServices := make(map[string][]byte) + mReplicationControllers := make(map[string][]byte) + mDeployments := make(map[string][]byte) + mDaemonSets := make(map[string][]byte) + mReplicaSets := make(map[string][]byte) var svcnames []string for name, service := range komposeObject.ServiceConfigs { @@ -640,17 +651,10 @@ func komposeConvert(komposeObject KomposeObject, toStdout, createD, createRS, cr volumesMount, volumes := configVolumes(service) // Configure the container ports. - ports, err := configPorts(name, service) - if err != "" { - logrus.Fatalf(err) - } + ports := configPorts(name, service) // Configure the service ports. - servicePorts, err := configServicePorts(name, service) - if err != "" { - logrus.Fatalf(err) - } - + servicePorts := configServicePorts(name, service) sc.Spec.Ports = servicePorts // Configure label @@ -658,7 +662,6 @@ func komposeConvert(komposeObject KomposeObject, toStdout, createD, createRS, cr for key, value := range service.Labels { labels[key] = value } - sc.ObjectMeta.Labels = labels // fillTemplate fills the pod template with the value calculated from config @@ -780,7 +783,7 @@ func komposeConvert(komposeObject KomposeObject, toStdout, createD, createRS, cr } } -// ProjectKuberConvert tranforms docker compose or dab file to k8s objects +// Convert tranforms docker compose or dab file to k8s objects func Convert(c *cli.Context) { inputFile := c.String("file") outFile := c.String("out") @@ -835,7 +838,7 @@ func Convert(c *cli.Context) { // Parse DAB file into komposeObject if fromBundles { - komposeObject = loadBundlesFile(inputFile); + komposeObject = loadBundlesFile(inputFile) } // Convert komposeObject to K8S controllers @@ -879,7 +882,7 @@ func print(name, trailing string, data []byte, toStdout, generateYaml bool, f *o } } -// ProjectKuberUp brings up rc, svc. +// Up brings up rc, svc. func Up(c *cli.Context) { //factory := cmdutil.NewFactory(nil) //clientConfig, err := factory.ClientConfig() diff --git a/cli/app/types.go b/cli/app/types.go index fed274a2..0cb023ba 100644 --- a/cli/app/types.go +++ b/cli/app/types.go @@ -16,57 +16,54 @@ limitations under the License. package app -// -//// ProjectFactory is an interface that helps creating libcompose project. -//type ProjectFactory interface { -// // Create creates a libcompose project from the command line options (codegangsta cli context). -// Create(c *cli.Context) (*project.Project, error) -//} - +// KomposeObject holds the generic struct of Kompose transformation type KomposeObject struct { - ServiceConfigs map[string]ServiceConfig + ServiceConfigs map[string]ServiceConfig } +// ServiceConfig holds the basic struct of a container type ServiceConfig struct { - ContainerName string - Image string - Environment []EnvVar - Port []Ports - Command []string - WorkingDir string - Args []string - //Volume []Volumes - Network []string - Labels map[string]string - CPUSet string - CPUShares int64 - CPUQuota int64 - CapAdd []string - CapDrop []string - Entrypoint []string - Expose []string - Privileged bool - Restart string - User string + ContainerName string + Image string + Environment []EnvVar + Port []Ports + Command []string + WorkingDir string + Args []string + Volumes []string + Network []string + Labels map[string]string + CPUSet string + CPUShares int64 + CPUQuota int64 + CapAdd []string + CapDrop []string + Entrypoint []string + Expose []string + Privileged bool + Restart string + User string } +// EnvVar holds the environment variable struct of a container type EnvVar struct { - Name string - Value string + Name string + Value string } +// Ports holds the ports struct of a container type Ports struct { - HostPort int32 - ContainerPort int32 - Protocol Protocol + HostPort int32 + ContainerPort int32 + Protocol Protocol } // Protocol defines network protocols supported for things like container ports. type Protocol string const ( -// ProtocolTCP is the TCP protocol. + // ProtocolTCP is the TCP protocol. ProtocolTCP Protocol = "TCP" -// ProtocolUDP is the UDP protocol. + // ProtocolUDP is the UDP protocol. ProtocolUDP Protocol = "UDP" -) \ No newline at end of file +) diff --git a/cli/command/command.go b/cli/command/command.go index 0be693cd..a348f063 100644 --- a/cli/command/command.go +++ b/cli/command/command.go @@ -24,9 +24,9 @@ import ( // ConvertCommand defines the kompose convert subcommand. func ConvertCommand() cli.Command { return cli.Command{ - Name: "convert", - Usage: "Convert docker-compose.yml to Kubernetes objects", - Action: func (c *cli.Context) { + Name: "convert", + Usage: "Convert docker-compose.yml to Kubernetes objects", + Action: func(c *cli.Context) { app.Convert(c) }, Flags: []cli.Flag{ @@ -82,9 +82,9 @@ func ConvertCommand() cli.Command { // UpCommand defines the kompose up subcommand. func UpCommand() cli.Command { return cli.Command{ - Name: "up", - Usage: "Submit rc, svc objects to kubernetes API endpoint", - Action: func (c *cli.Context) { + Name: "up", + Usage: "Submit rc, svc objects to kubernetes API endpoint", + Action: func(c *cli.Context) { app.Up(c) }, } @@ -93,9 +93,9 @@ func UpCommand() cli.Command { // PsCommand defines the kompose ps subcommand. func PsCommand() cli.Command { return cli.Command{ - Name: "ps", - Usage: "Get active data in the kubernetes cluster", - Action: func (c *cli.Context) { + Name: "ps", + Usage: "Get active data in the kubernetes cluster", + Action: func(c *cli.Context) { app.Ps(c) }, Flags: []cli.Flag{ @@ -114,9 +114,9 @@ func PsCommand() cli.Command { // DeleteCommand defines the kompose delete subcommand. func DeleteCommand() cli.Command { return cli.Command{ - Name: "delete", - Usage: "Remove instantiated services/rc from kubernetes", - Action: func (c *cli.Context) { + Name: "delete", + Usage: "Remove instantiated services/rc from kubernetes", + Action: func(c *cli.Context) { app.Delete(c) }, Flags: []cli.Flag{ @@ -139,9 +139,9 @@ func DeleteCommand() cli.Command { // ScaleCommand defines the kompose up subcommand. func ScaleCommand() cli.Command { return cli.Command{ - Name: "scale", - Usage: "Globally scale instantiated replication controllers", - Action: func (c *cli.Context) { + Name: "scale", + Usage: "Globally scale instantiated replication controllers", + Action: func(c *cli.Context) { app.Scale(c) }, Flags: []cli.Flag{ @@ -171,18 +171,3 @@ func CommonFlags() []cli.Flag { }, } } -// -//// Populate updates the specified project context based on command line arguments and subcommands. -//func Populate(context *project.Context, c *cli.Context) { -// context.ComposeFiles = append(context.ComposeFiles, c.GlobalString("file")) -// -// //if c.Command.Name == "logs" { -// // context.Log = true -// //} else if c.Command.Name == "up" { -// // context.Log = !c.Bool("d") -// // context.NoRecreate = c.Bool("no-recreate") -// // context.ForceRecreate = c.Bool("force-recreate") -// //} else if c.Command.Name == "scale" { -// // context.Timeout = uint(c.Int("timeout")) -// //} -//} diff --git a/cli/main/main.go b/cli/main/main.go index f09a1056..092861bd 100644 --- a/cli/main/main.go +++ b/cli/main/main.go @@ -19,10 +19,10 @@ package main import ( "os" - "github.com/urfave/cli" - "github.com/skippbox/kompose/version" - "github.com/skippbox/kompose/cli/command" cliApp "github.com/skippbox/kompose/cli/app" + "github.com/skippbox/kompose/cli/command" + "github.com/skippbox/kompose/version" + "github.com/urfave/cli" ) func main() {