Support docker bundles format

This commit is contained in:
ngtuna 2016-07-20 02:01:40 +07:00
parent 7a41edb65e
commit a9184491b7
4 changed files with 185 additions and 200 deletions

View File

@ -20,13 +20,12 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"os" "os"
//"strconv" "strconv"
"strings" "strings"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/docker/libcompose/project"
"github.com/docker/docker/api/client/bundlefile" "github.com/docker/docker/api/client/bundlefile"
"encoding/json" "encoding/json"
@ -38,14 +37,12 @@ import (
//client "k8s.io/kubernetes/pkg/client/unversioned" //client "k8s.io/kubernetes/pkg/client/unversioned"
//cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" //cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
//"k8s.io/kubernetes/pkg/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
"github.com/fatih/structs" "github.com/fatih/structs"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
) )
type ProjectAction func(project *project.Project, c *cli.Context)
const letterBytes = "abcdefghijklmnopqrstuvwxyz0123456789" const letterBytes = "abcdefghijklmnopqrstuvwxyz0123456789"
var unsupportedKey = map[string]string{ var unsupportedKey = map[string]string{
@ -97,11 +94,10 @@ func BeforeApp(c *cli.Context) error {
if c.GlobalBool("verbose") { if c.GlobalBool("verbose") {
logrus.SetLevel(logrus.DebugLevel) 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 return nil
} }
// ProjectKuberPS lists all rc, svc. // Ps lists all rc, svc.
func Ps(c *cli.Context) { func Ps(c *cli.Context) {
//factory := cmdutil.NewFactory(nil) //factory := cmdutil.NewFactory(nil)
//clientConfig, err := factory.ClientConfig() //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) { func Delete(c *cli.Context) {
//factory := cmdutil.NewFactory(nil) //factory := cmdutil.NewFactory(nil)
//clientConfig, err := factory.ClientConfig() //clientConfig, err := factory.ClientConfig()
@ -204,7 +200,7 @@ func Delete(c *cli.Context) {
//} //}
} }
// ProjectKuberScale scales rc. // Scale scales rc.
func Scale(c *cli.Context) { func Scale(c *cli.Context) {
//factory := cmdutil.NewFactory(nil) //factory := cmdutil.NewFactory(nil)
//clientConfig, err := factory.ClientConfig() //clientConfig, err := factory.ClientConfig()
@ -395,11 +391,11 @@ func initRS(name string, service ServiceConfig) *extensions.ReplicaSet {
} }
// Configure the environment variables. // Configure the environment variables.
func configEnvs(name string, service ServiceConfig) ([]api.EnvVar) { func configEnvs(name string, service ServiceConfig) []api.EnvVar {
envs := []api.EnvVar{} envs := []api.EnvVar{}
for _, v := range service.Environment { for _, v := range service.Environment {
envs = append(envs, api.EnvVar{ envs = append(envs, api.EnvVar{
Name: v.Name, Name: v.Name,
Value: v.Value, Value: v.Value,
}) })
} }
@ -411,111 +407,86 @@ func configEnvs(name string, service ServiceConfig) ([]api.EnvVar) {
func configVolumes(service ServiceConfig) ([]api.VolumeMount, []api.Volume) { func configVolumes(service ServiceConfig) ([]api.VolumeMount, []api.Volume) {
volumesMount := []api.VolumeMount{} volumesMount := []api.VolumeMount{}
volumes := []api.Volume{} volumes := []api.Volume{}
//for _, volume := range service.Volumes { for _, volume := range service.Volumes {
// var character string = ":" character := ":"
// if strings.Contains(volume, character) { if strings.Contains(volume, character) {
// hostDir := volume[0:strings.Index(volume, character)] hostDir := volume[0:strings.Index(volume, character)]
// hostDir = strings.TrimSpace(hostDir) hostDir = strings.TrimSpace(hostDir)
// containerDir := volume[strings.Index(volume, character)+1:] containerDir := volume[strings.Index(volume, character)+1:]
// containerDir = strings.TrimSpace(containerDir) containerDir = strings.TrimSpace(containerDir)
//
// // check if ro/rw mode is defined // check if ro/rw mode is defined
// var readonly bool = true readonly := true
// if strings.Index(volume, character) != strings.LastIndex(volume, character) { if strings.Index(volume, character) != strings.LastIndex(volume, character) {
// mode := volume[strings.LastIndex(volume, character)+1:] mode := volume[strings.LastIndex(volume, character)+1:]
// if strings.Compare(mode, "rw") == 0 { if strings.Compare(mode, "rw") == 0 {
// readonly = false readonly = false
// } }
// containerDir = containerDir[0:strings.Index(containerDir, character)] containerDir = containerDir[0:strings.Index(containerDir, character)]
// } }
//
// // volumeName = random string of 20 chars // volumeName = random string of 20 chars
// volumeName := RandStringBytes(20) volumeName := RandStringBytes(20)
//
// volumesMount = append(volumesMount, api.VolumeMount{Name: volumeName, ReadOnly: readonly, MountPath: containerDir}) volumesMount = append(volumesMount, api.VolumeMount{Name: volumeName, ReadOnly: readonly, MountPath: containerDir})
// p := &api.HostPathVolumeSource{ p := &api.HostPathVolumeSource{
// Path: hostDir, Path: hostDir,
// } }
// //p.Path = hostDir //p.Path = hostDir
// volumeSource := api.VolumeSource{HostPath: p} volumeSource := api.VolumeSource{HostPath: p}
// volumes = append(volumes, api.Volume{Name: volumeName, VolumeSource: volumeSource}) volumes = append(volumes, api.Volume{Name: volumeName, VolumeSource: volumeSource})
// } }
//} }
return volumesMount, volumes return volumesMount, volumes
} }
// Configure the container ports. // Configure the container ports.
func configPorts(name string, service ServiceConfig) ([]api.ContainerPort, string) { func configPorts(name string, service ServiceConfig) []api.ContainerPort {
ports := []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 { 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{ ports = append(ports, api.ContainerPort{
HostPort: port.HostPort, HostPort: port.HostPort,
ContainerPort: port.ContainerPort, ContainerPort: port.ContainerPort,
//Protocol: port.Protocol, Protocol: p,
}) })
} }
return ports, "" return ports
} }
// Configure the container service 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{} servicePorts := []api.ServicePort{}
//for _, port := range service.Ports { for _, port := range service.Port {
// var character string = ":" var p api.Protocol
// if strings.Contains(port, character) { switch port.Protocol {
// portNumber := port[0:strings.Index(port, character)] default:
// portNumber = strings.TrimSpace(portNumber) p = api.ProtocolTCP
// targetPortNumber := port[strings.Index(port, character)+1:] case ProtocolTCP:
// targetPortNumber = strings.TrimSpace(targetPortNumber) p = api.ProtocolTCP
// portNumberInt, err := strconv.Atoi(portNumber) case ProtocolUDP:
// if err != nil { p = api.ProtocolUDP
// return nil, "Invalid container port " + port + " for service " + name }
// } var targetPort intstr.IntOrString
// targetPortNumberInt, err1 := strconv.Atoi(targetPortNumber) targetPort.IntVal = port.HostPort
// if err1 != nil { targetPort.StrVal = strconv.Itoa(int(port.HostPort))
// return nil, "Invalid container port " + port + " for service " + name servicePorts = append(servicePorts, api.ServicePort{
// } Name: strconv.Itoa(int(port.ContainerPort)),
// var targetPort intstr.IntOrString Protocol: p,
// targetPort.StrVal = targetPortNumber Port: port.ContainerPort,
// targetPort.IntVal = int32(targetPortNumberInt) TargetPort: targetPort,
// servicePorts = append(servicePorts, api.ServicePort{Port: int32(portNumberInt), Name: portNumber, Protocol: "TCP", TargetPort: targetPort}) })
// } else { }
// portNumber, err := strconv.Atoi(port) return servicePorts
// 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, ""
} }
// Transform data to json/yaml // 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) { func loadEnvVars(service bundlefile.Service) ([]EnvVar, string) {
envs := []EnvVar{} envs := []EnvVar{}
for _, env := range service.Env { for _, env := range service.Env {
var character string = "=" character := "="
if strings.Contains(env, character) { if strings.Contains(env, character) {
value := env[strings.Index(env, character)+1:] value := env[strings.Index(env, character)+1:]
name := env[0:strings.Index(env, character)] name := env[0:strings.Index(env, character)]
@ -549,7 +520,7 @@ func loadEnvVars(service bundlefile.Service) ([]EnvVar, string) {
} else { } else {
character = ":" character = ":"
if strings.Contains(env, character) { if strings.Contains(env, character) {
var charQuote string = "'" charQuote := "'"
value := env[strings.Index(env, character)+1:] value := env[strings.Index(env, character)+1:]
name := env[0:strings.Index(env, character)] name := env[0:strings.Index(env, character)]
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
@ -569,9 +540,40 @@ func loadEnvVars(service bundlefile.Service) ([]EnvVar, string) {
return envs, "" 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 // Load DAB file into KomposeObject
func loadBundlesFile(file string) (KomposeObject) { func loadBundlesFile(file string) KomposeObject {
kObject := KomposeObject{ komposeObject := KomposeObject{
ServiceConfigs: make(map[string]ServiceConfig), ServiceConfigs: make(map[string]ServiceConfig),
} }
buf, err := ioutil.ReadFile(file) buf, err := ioutil.ReadFile(file)
@ -586,35 +588,44 @@ func loadBundlesFile(file string) (KomposeObject) {
for name, service := range bundle.Services { for name, service := range bundle.Services {
serviceConfig := ServiceConfig{} serviceConfig := ServiceConfig{}
serviceConfig.Image = service.Image
serviceConfig.Command = service.Command serviceConfig.Command = service.Command
serviceConfig.Args = service.Args 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) envs, err := loadEnvVars(service)
if err != "" { if err != "" {
logrus.Fatalf("Failed to load envvar from bundles file: " + err) logrus.Fatalf("Failed to load envvar from bundles file: " + err)
} }
serviceConfig.Environment = envs 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 { if service.WorkingDir != nil {
serviceConfig.WorkingDir = *service.WorkingDir serviceConfig.WorkingDir = *service.WorkingDir
} }
kObject.ServiceConfigs[name] = serviceConfig
komposeObject.ServiceConfigs[name] = serviceConfig
} }
return komposeObject
fmt.Println(kObject)
return kObject
} }
// Convert komposeObject to K8S controllers // 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) { 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) mServices := make(map[string][]byte)
var mReplicationControllers map[string][]byte = make(map[string][]byte) mReplicationControllers := make(map[string][]byte)
var mDeployments map[string][]byte = make(map[string][]byte) mDeployments := make(map[string][]byte)
var mDaemonSets map[string][]byte = make(map[string][]byte) mDaemonSets := make(map[string][]byte)
var mReplicaSets map[string][]byte = make(map[string][]byte) mReplicaSets := make(map[string][]byte)
var svcnames []string var svcnames []string
for name, service := range komposeObject.ServiceConfigs { for name, service := range komposeObject.ServiceConfigs {
@ -640,17 +651,10 @@ func komposeConvert(komposeObject KomposeObject, toStdout, createD, createRS, cr
volumesMount, volumes := configVolumes(service) volumesMount, volumes := configVolumes(service)
// Configure the container ports. // Configure the container ports.
ports, err := configPorts(name, service) ports := configPorts(name, service)
if err != "" {
logrus.Fatalf(err)
}
// Configure the service ports. // Configure the service ports.
servicePorts, err := configServicePorts(name, service) servicePorts := configServicePorts(name, service)
if err != "" {
logrus.Fatalf(err)
}
sc.Spec.Ports = servicePorts sc.Spec.Ports = servicePorts
// Configure label // Configure label
@ -658,7 +662,6 @@ func komposeConvert(komposeObject KomposeObject, toStdout, createD, createRS, cr
for key, value := range service.Labels { for key, value := range service.Labels {
labels[key] = value labels[key] = value
} }
sc.ObjectMeta.Labels = labels sc.ObjectMeta.Labels = labels
// fillTemplate fills the pod template with the value calculated from config // 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) { func Convert(c *cli.Context) {
inputFile := c.String("file") inputFile := c.String("file")
outFile := c.String("out") outFile := c.String("out")
@ -835,7 +838,7 @@ func Convert(c *cli.Context) {
// Parse DAB file into komposeObject // Parse DAB file into komposeObject
if fromBundles { if fromBundles {
komposeObject = loadBundlesFile(inputFile); komposeObject = loadBundlesFile(inputFile)
} }
// Convert komposeObject to K8S controllers // 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) { func Up(c *cli.Context) {
//factory := cmdutil.NewFactory(nil) //factory := cmdutil.NewFactory(nil)
//clientConfig, err := factory.ClientConfig() //clientConfig, err := factory.ClientConfig()

View File

@ -16,57 +16,54 @@ limitations under the License.
package app package app
// // KomposeObject holds the generic struct of Kompose transformation
//// 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)
//}
type KomposeObject struct { type KomposeObject struct {
ServiceConfigs map[string]ServiceConfig ServiceConfigs map[string]ServiceConfig
} }
// ServiceConfig holds the basic struct of a container
type ServiceConfig struct { type ServiceConfig struct {
ContainerName string ContainerName string
Image string Image string
Environment []EnvVar Environment []EnvVar
Port []Ports Port []Ports
Command []string Command []string
WorkingDir string WorkingDir string
Args []string Args []string
//Volume []Volumes Volumes []string
Network []string Network []string
Labels map[string]string Labels map[string]string
CPUSet string CPUSet string
CPUShares int64 CPUShares int64
CPUQuota int64 CPUQuota int64
CapAdd []string CapAdd []string
CapDrop []string CapDrop []string
Entrypoint []string Entrypoint []string
Expose []string Expose []string
Privileged bool Privileged bool
Restart string Restart string
User string User string
} }
// EnvVar holds the environment variable struct of a container
type EnvVar struct { type EnvVar struct {
Name string Name string
Value string Value string
} }
// Ports holds the ports struct of a container
type Ports struct { type Ports struct {
HostPort int32 HostPort int32
ContainerPort int32 ContainerPort int32
Protocol Protocol Protocol Protocol
} }
// Protocol defines network protocols supported for things like container ports. // Protocol defines network protocols supported for things like container ports.
type Protocol string type Protocol string
const ( const (
// ProtocolTCP is the TCP protocol. // ProtocolTCP is the TCP protocol.
ProtocolTCP Protocol = "TCP" ProtocolTCP Protocol = "TCP"
// ProtocolUDP is the UDP protocol. // ProtocolUDP is the UDP protocol.
ProtocolUDP Protocol = "UDP" ProtocolUDP Protocol = "UDP"
) )

View File

@ -24,9 +24,9 @@ import (
// ConvertCommand defines the kompose convert subcommand. // ConvertCommand defines the kompose convert subcommand.
func ConvertCommand() cli.Command { func ConvertCommand() cli.Command {
return cli.Command{ return cli.Command{
Name: "convert", Name: "convert",
Usage: "Convert docker-compose.yml to Kubernetes objects", Usage: "Convert docker-compose.yml to Kubernetes objects",
Action: func (c *cli.Context) { Action: func(c *cli.Context) {
app.Convert(c) app.Convert(c)
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -82,9 +82,9 @@ func ConvertCommand() cli.Command {
// UpCommand defines the kompose up subcommand. // UpCommand defines the kompose up subcommand.
func UpCommand() cli.Command { func UpCommand() cli.Command {
return cli.Command{ return cli.Command{
Name: "up", Name: "up",
Usage: "Submit rc, svc objects to kubernetes API endpoint", Usage: "Submit rc, svc objects to kubernetes API endpoint",
Action: func (c *cli.Context) { Action: func(c *cli.Context) {
app.Up(c) app.Up(c)
}, },
} }
@ -93,9 +93,9 @@ func UpCommand() cli.Command {
// PsCommand defines the kompose ps subcommand. // PsCommand defines the kompose ps subcommand.
func PsCommand() cli.Command { func PsCommand() cli.Command {
return cli.Command{ return cli.Command{
Name: "ps", Name: "ps",
Usage: "Get active data in the kubernetes cluster", Usage: "Get active data in the kubernetes cluster",
Action: func (c *cli.Context) { Action: func(c *cli.Context) {
app.Ps(c) app.Ps(c)
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -114,9 +114,9 @@ func PsCommand() cli.Command {
// DeleteCommand defines the kompose delete subcommand. // DeleteCommand defines the kompose delete subcommand.
func DeleteCommand() cli.Command { func DeleteCommand() cli.Command {
return cli.Command{ return cli.Command{
Name: "delete", Name: "delete",
Usage: "Remove instantiated services/rc from kubernetes", Usage: "Remove instantiated services/rc from kubernetes",
Action: func (c *cli.Context) { Action: func(c *cli.Context) {
app.Delete(c) app.Delete(c)
}, },
Flags: []cli.Flag{ Flags: []cli.Flag{
@ -139,9 +139,9 @@ func DeleteCommand() cli.Command {
// ScaleCommand defines the kompose up subcommand. // ScaleCommand defines the kompose up subcommand.
func ScaleCommand() cli.Command { func ScaleCommand() cli.Command {
return cli.Command{ return cli.Command{
Name: "scale", Name: "scale",
Usage: "Globally scale instantiated replication controllers", Usage: "Globally scale instantiated replication controllers",
Action: func (c *cli.Context) { Action: func(c *cli.Context) {
app.Scale(c) app.Scale(c)
}, },
Flags: []cli.Flag{ 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"))
// //}
//}

View File

@ -19,10 +19,10 @@ package main
import ( import (
"os" "os"
"github.com/urfave/cli"
"github.com/skippbox/kompose/version"
"github.com/skippbox/kompose/cli/command"
cliApp "github.com/skippbox/kompose/cli/app" cliApp "github.com/skippbox/kompose/cli/app"
"github.com/skippbox/kompose/cli/command"
"github.com/skippbox/kompose/version"
"github.com/urfave/cli"
) )
func main() { func main() {