merge master branch

This commit is contained in:
ngtuna 2016-07-19 00:17:33 +07:00
commit daa85e2027
6 changed files with 131 additions and 88 deletions

View File

@ -181,6 +181,13 @@ WARNING: Unsupported key ContainerName - ignoring
WARNING: Unsupported key Dockerfile - ignoring WARNING: Unsupported key Dockerfile - ignoring
``` ```
## Bash completion
Running this below command in order to benefit from bash completion
```
$ PROG=kompose source script/bash_autocomplete
```
## Building ## Building
### Building with `go` ### Building with `go`

View File

@ -37,6 +37,7 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
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/util/intstr" "k8s.io/kubernetes/pkg/util/intstr"
"github.com/fatih/structs" "github.com/fatih/structs"
@ -260,7 +261,7 @@ func createOutFile(out string) *os.File {
} }
// Init RC object // Init RC object
func initRC(name string, service *project.ServiceConfig) *api.ReplicationController { func initRC(name string, service *project.ServiceConfig, replicas int) *api.ReplicationController {
rc := &api.ReplicationController{ rc := &api.ReplicationController{
TypeMeta: unversioned.TypeMeta{ TypeMeta: unversioned.TypeMeta{
Kind: "ReplicationController", Kind: "ReplicationController",
@ -271,7 +272,7 @@ func initRC(name string, service *project.ServiceConfig) *api.ReplicationControl
//Labels: map[string]string{"service": name}, //Labels: map[string]string{"service": name},
}, },
Spec: api.ReplicationControllerSpec{ Spec: api.ReplicationControllerSpec{
Replicas: 1, Replicas: int32(replicas),
Selector: map[string]string{"service": name}, Selector: map[string]string{"service": name},
Template: &api.PodTemplateSpec{ Template: &api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
@ -565,8 +566,14 @@ func ProjectKuberConvert(p *project.Project, c *cli.Context) {
createRS := c.BoolT("replicaset") createRS := c.BoolT("replicaset")
createChart := c.BoolT("chart") createChart := c.BoolT("chart")
fromBundles := c.BoolT("from-bundles") fromBundles := c.BoolT("from-bundles")
replicas := c.Int("replicationcontroller")
singleOutput := len(outFile) != 0 || toStdout singleOutput := len(outFile) != 0 || toStdout
// Create Deployment by default if no controller has be set
if !createD && !createDS && !createRS && replicas == 0 {
createD = true
}
// Validate the flags // Validate the flags
if len(outFile) != 0 && toStdout { if len(outFile) != 0 && toStdout {
logrus.Fatalf("Error: --out and --stdout can't be set at the same time") logrus.Fatalf("Error: --out and --stdout can't be set at the same time")
@ -585,6 +592,9 @@ func ProjectKuberConvert(p *project.Project, c *cli.Context) {
if createRS { if createRS {
count++ count++
} }
if replicas != 0 {
count++
}
if count > 1 { if count > 1 {
logrus.Fatalf("Error: only one type of Kubernetes controller can be generated when --out or --stdout is specified") logrus.Fatalf("Error: only one type of Kubernetes controller can be generated when --out or --stdout is specified")
} }
@ -636,7 +646,7 @@ func ProjectKuberConvert(p *project.Project, c *cli.Context) {
checkUnsupportedKey(*service) checkUnsupportedKey(*service)
rc := initRC(name, service) rc := initRC(name, service, replicas)
sc := initSC(name, service) sc := initSC(name, service)
dc := initDC(name, service) dc := initDC(name, service)
ds := initDS(name, service) ds := initDS(name, service)
@ -648,62 +658,20 @@ func ProjectKuberConvert(p *project.Project, c *cli.Context) {
logrus.Fatalf(err) logrus.Fatalf(err)
} }
rc.Spec.Template.Spec.Containers[0].Env = envs
dc.Spec.Template.Spec.Containers[0].Env = envs
ds.Spec.Template.Spec.Containers[0].Env = envs
rs.Spec.Template.Spec.Containers[0].Env = envs
// Configure the container command. // Configure the container command.
var cmds []string var cmds []string
for _, cmd := range service.Command.Slice() { for _, cmd := range service.Command.Slice() {
cmds = append(cmds, cmd) cmds = append(cmds, cmd)
} }
rc.Spec.Template.Spec.Containers[0].Command = cmds
dc.Spec.Template.Spec.Containers[0].Command = cmds
ds.Spec.Template.Spec.Containers[0].Command = cmds
rs.Spec.Template.Spec.Containers[0].Command = cmds
// Configure the container working dir.
rc.Spec.Template.Spec.Containers[0].WorkingDir = service.WorkingDir
dc.Spec.Template.Spec.Containers[0].WorkingDir = service.WorkingDir
ds.Spec.Template.Spec.Containers[0].WorkingDir = service.WorkingDir
rs.Spec.Template.Spec.Containers[0].WorkingDir = service.WorkingDir
// Configure the container volumes. // Configure the container volumes.
volumesMount, volumes := configVolumes(service) volumesMount, volumes := configVolumes(service)
rc.Spec.Template.Spec.Containers[0].VolumeMounts = volumesMount
dc.Spec.Template.Spec.Containers[0].VolumeMounts = volumesMount
ds.Spec.Template.Spec.Containers[0].VolumeMounts = volumesMount
rs.Spec.Template.Spec.Containers[0].VolumeMounts = volumesMount
rc.Spec.Template.Spec.Volumes = volumes
dc.Spec.Template.Spec.Volumes = volumes
ds.Spec.Template.Spec.Volumes = volumes
rs.Spec.Template.Spec.Volumes = volumes
// Configure the container privileged mode
if service.Privileged == true {
securitycontexts := &api.SecurityContext{
Privileged: &service.Privileged,
}
rc.Spec.Template.Spec.Containers[0].SecurityContext = securitycontexts
dc.Spec.Template.Spec.Containers[0].SecurityContext = securitycontexts
ds.Spec.Template.Spec.Containers[0].SecurityContext = securitycontexts
rs.Spec.Template.Spec.Containers[0].SecurityContext = securitycontexts
}
// Configure the container ports. // Configure the container ports.
ports, err := configPorts(name, service) ports, err := configPorts(name, service)
if err != "" { if err != "" {
logrus.Fatalf(err) logrus.Fatalf(err)
} }
rc.Spec.Template.Spec.Containers[0].Ports = ports
dc.Spec.Template.Spec.Containers[0].Ports = ports
ds.Spec.Template.Spec.Containers[0].Ports = ports
rs.Spec.Template.Spec.Containers[0].Ports = ports
// Configure the service ports. // Configure the service ports.
servicePorts, err := configServicePorts(name, service) servicePorts, err := configServicePorts(name, service)
if err != "" { if err != "" {
@ -717,38 +685,48 @@ func ProjectKuberConvert(p *project.Project, c *cli.Context) {
for key, value := range service.Labels.MapParts() { for key, value := range service.Labels.MapParts() {
labels[key] = value labels[key] = value
} }
rc.Spec.Template.ObjectMeta.Labels = labels
dc.Spec.Template.ObjectMeta.Labels = labels
ds.Spec.Template.ObjectMeta.Labels = labels
rs.Spec.Template.ObjectMeta.Labels = labels
rc.ObjectMeta.Labels = labels
dc.ObjectMeta.Labels = labels
ds.ObjectMeta.Labels = labels
rs.ObjectMeta.Labels = labels
sc.ObjectMeta.Labels = labels sc.ObjectMeta.Labels = labels
// Configure the container restart policy. // fillTemplate fills the pod template with the value calculated from config
switch service.Restart { fillTemplate := func(template *api.PodTemplateSpec) {
case "", "always": template.Spec.Containers[0].Env = envs
rc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyAlways template.Spec.Containers[0].Command = cmds
dc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyAlways template.Spec.Containers[0].WorkingDir = service.WorkingDir
ds.Spec.Template.Spec.RestartPolicy = api.RestartPolicyAlways template.Spec.Containers[0].VolumeMounts = volumesMount
rs.Spec.Template.Spec.RestartPolicy = api.RestartPolicyAlways template.Spec.Volumes = volumes
case "no": // Configure the container privileged mode
rc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyNever if service.Privileged == true {
dc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyNever template.Spec.Containers[0].SecurityContext = &api.SecurityContext{
ds.Spec.Template.Spec.RestartPolicy = api.RestartPolicyNever Privileged: &service.Privileged,
rs.Spec.Template.Spec.RestartPolicy = api.RestartPolicyNever }
case "on-failure": }
rc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure template.Spec.Containers[0].Ports = ports
dc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure template.ObjectMeta.Labels = labels
ds.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure // Configure the container restart policy.
rs.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure switch service.Restart {
default: case "", "always":
logrus.Fatalf("Unknown restart policy %s for service %s", service.Restart, name) template.Spec.RestartPolicy = api.RestartPolicyAlways
case "no":
template.Spec.RestartPolicy = api.RestartPolicyNever
case "on-failure":
template.Spec.RestartPolicy = api.RestartPolicyOnFailure
default:
logrus.Fatalf("Unknown restart policy %s for service %s", service.Restart, name)
}
} }
// fillObjectMeta fills the metadata with the value calculated from config
fillObjectMeta := func(meta *api.ObjectMeta) {
meta.Labels = labels
}
// Update each supported controllers
updateController(rc, fillTemplate, fillObjectMeta)
updateController(rs, fillTemplate, fillObjectMeta)
updateController(dc, fillTemplate, fillObjectMeta)
updateController(ds, fillTemplate, fillObjectMeta)
// convert datarc to json / yaml // convert datarc to json / yaml
datarc, err := transformer(rc, "replication controller", generateYaml) datarc, err := transformer(rc, "replication controller", generateYaml)
if err != "" { if err != "" {
@ -831,8 +809,7 @@ func ProjectKuberConvert(p *project.Project, c *cli.Context) {
} }
} }
// We can create RC when we either don't print to --out or --stdout, or we don't create any other controllers if replicas != 0 {
if !singleOutput || (!createD && !createDS && !createRS) {
for k, v := range mReplicationControllers { for k, v := range mReplicationControllers {
print(k, "rc", v, toStdout, generateYaml, f) print(k, "rc", v, toStdout, generateYaml, f)
} }
@ -843,7 +820,7 @@ func ProjectKuberConvert(p *project.Project, c *cli.Context) {
} }
if createChart { if createChart {
err := generateHelm(composeFile, svcnames, generateYaml) err := generateHelm(composeFile, svcnames, generateYaml, createD, createDS, createRS, replicas)
if err != nil { if err != nil {
logrus.Fatalf("Failed to create Chart data: %s\n", err) logrus.Fatalf("Failed to create Chart data: %s\n", err)
} }
@ -964,3 +941,24 @@ func ProjectKuberUp(p *project.Project, c *cli.Context) {
} }
} }
// updateController updates the given object with the given pod template update function and ObjectMeta update function
func updateController(obj runtime.Object, updateTemplate func(*api.PodTemplateSpec), updateMeta func(meta *api.ObjectMeta)) {
switch t := obj.(type) {
case *api.ReplicationController:
if t.Spec.Template == nil {
t.Spec.Template = &api.PodTemplateSpec{}
}
updateTemplate(t.Spec.Template)
updateMeta(&t.ObjectMeta)
case *extensions.Deployment:
updateTemplate(&t.Spec.Template)
updateMeta(&t.ObjectMeta)
case *extensions.ReplicaSet:
updateTemplate(&t.Spec.Template)
updateMeta(&t.ObjectMeta)
case *extensions.DaemonSet:
updateTemplate(&t.Spec.Template)
updateMeta(&t.ObjectMeta)
}
}

View File

@ -32,7 +32,7 @@ import (
/** /**
* Generate Helm Chart configuration * Generate Helm Chart configuration
*/ */
func generateHelm(filename string, svcnames []string, generateYaml bool) error { func generateHelm(filename string, svcnames []string, generateYaml, createD, createDS, createRS bool, replicas int) error {
type ChartDetails struct { type ChartDetails struct {
Name string Name string
} }
@ -89,26 +89,35 @@ home:
} }
/* Copy all related json/yaml files into the newly created manifests directory */ /* Copy all related json/yaml files into the newly created manifests directory */
// TODO: support copying controller files other than rc?
// TODO: support copying the file specified by --out? // TODO: support copying the file specified by --out?
for _, svcname := range svcnames { for _, svcname := range svcnames {
extension := ".json" extension := ".json"
if generateYaml { if generateYaml {
extension = ".yaml" extension = ".yaml"
} }
infile, err := ioutil.ReadFile(svcname + "-rc" + extension) if createD {
if err != nil { if err = cpToChart(manifestDir, svcname, "deployment", extension); err != nil {
logrus.Infof("Error reading %s: %s\n", svcname+"-rc"+extension, err) return err
return err }
} }
if createDS {
err = ioutil.WriteFile(manifestDir+string(os.PathSeparator)+svcname+"-rc"+extension, infile, 0644) if err = cpToChart(manifestDir, svcname, "daemonset", extension); err != nil {
if err != nil { return err
return err }
}
if (replicas != 0) {
if err = cpToChart(manifestDir, svcname, "replicationcontroller", extension); err != nil {
return err
}
}
if createRS {
if err = cpToChart(manifestDir, svcname, "replicaset", extension); err != nil {
return err
}
} }
/* The svc file is optional */ /* The svc file is optional */
infile, err = ioutil.ReadFile(svcname + "-svc" + extension) infile, err := ioutil.ReadFile(svcname + "-svc" + extension)
if err != nil { if err != nil {
continue continue
} }
@ -121,3 +130,13 @@ home:
fmt.Fprintf(os.Stdout, "chart created in %q\n", "."+string(os.PathSeparator)+dirName+string(os.PathSeparator)) fmt.Fprintf(os.Stdout, "chart created in %q\n", "."+string(os.PathSeparator)+dirName+string(os.PathSeparator))
return nil return nil
} }
func cpToChart(manifestDir, svcname, trailing, extension string) error {
infile, err := ioutil.ReadFile(svcname + "-" + trailing + extension)
if err != nil {
logrus.Infof("Error reading %s: %s\n", svcname+"-"+trailing+extension, err)
return err
}
return ioutil.WriteFile(manifestDir+string(os.PathSeparator)+svcname+"-"+trailing+extension, infile, 0644)
}

View File

@ -40,15 +40,19 @@ func ConvertCommand(factory app.ProjectFactory) cli.Command {
Usage: "Specify file name in order to save objects into", Usage: "Specify file name in order to save objects into",
EnvVar: "OUTPUT_FILE", EnvVar: "OUTPUT_FILE",
}, },
// TODO: validate the flags and make sure only one type is specified
cli.BoolFlag{ cli.BoolFlag{
Name: "deployment,d", Name: "deployment,d",
Usage: "Generate a deployment resource file", Usage: "Generate a deployment resource file (default on)",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "daemonset,ds", Name: "daemonset,ds",
Usage: "Generate a daemonset resource file", Usage: "Generate a daemonset resource file",
}, },
cli.IntFlag{
Name: "replicationcontroller,rc",
Value: 0,
Usage: "Specify replicas in order to generate a replication controller resource file",
},
cli.BoolFlag{ cli.BoolFlag{
Name: "replicaset,rs", Name: "replicaset,rs",
Usage: "Generate a replicaset resource file", Usage: "Generate a replicaset resource file",

View File

@ -35,6 +35,7 @@ func main() {
app.Version = version.VERSION + " (" + version.GITCOMMIT + ")" app.Version = version.VERSION + " (" + version.GITCOMMIT + ")"
app.Author = "Skippbox Compose Contributors" app.Author = "Skippbox Compose Contributors"
app.Email = "https://github.com/skippbox/kompose" app.Email = "https://github.com/skippbox/kompose"
app.EnableBashCompletion = true
app.Before = cliApp.BeforeApp app.Before = cliApp.BeforeApp
app.Flags = append(command.CommonFlags()) app.Flags = append(command.CommonFlags())
app.Commands = []cli.Command{ app.Commands = []cli.Command{

14
script/bash_autocomplete Normal file
View File

@ -0,0 +1,14 @@
#! /bin/bash
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
}
complete -F _cli_bash_autocomplete $PROG