From b99a28f78ef614044619dee7bbe6dc8176c998c2 Mon Sep 17 00:00:00 2001 From: Suraj Deshmukh Date: Wed, 22 Nov 2017 15:21:05 +0530 Subject: [PATCH] create buildconfig and imagestream from configs --- pkg/build/build.go | 173 ++++++++++++++++++++++++++++++++++++++++++-- pkg/cmd/commands.go | 6 +- 2 files changed, 168 insertions(+), 11 deletions(-) diff --git a/pkg/build/build.go b/pkg/build/build.go index 7540ab7d2..96719acb3 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -25,10 +25,19 @@ import ( "path" "path/filepath" "strings" + "time" log "github.com/Sirupsen/logrus" dockerlib "github.com/fsouza/go-dockerclient" + "github.com/ghodss/yaml" + os_build_v1 "github.com/openshift/origin/pkg/build/apis/build/v1" + os_image_v1 "github.com/openshift/origin/pkg/image/apis/image/v1" "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + _ "k8s.io/kubernetes/pkg/api/install" + kapi "k8s.io/kubernetes/pkg/api/v1" + + "github.com/kedgeproject/kedge/pkg/cmd" ) func BuildPushDockerImage(dockerfile, image, context string, push bool) error { @@ -174,24 +183,172 @@ func CreateTarball(source, target string) error { }) } +// getImageTag get tag name from image name +// if no tag is specified return 'latest' +func GetImageTag(image string) string { + // format: registry_host:registry_port/repo_name/image_name:image_tag + // example: + // 1) myregistryhost:5000/fedora/httpd:version1.0 + // 2) myregistryhost:5000/fedora/httpd + // 3) myregistryhost/fedora/httpd:version1.0 + // 4) myregistryhost/fedora/httpd + // 5) fedora/httpd + // 6) httpd + imageAndTag := image + + imageTagSplit := strings.Split(image, "/") + if len(imageTagSplit) >= 2 { + imageAndTag = imageTagSplit[len(imageTagSplit)-1] + } + + p := strings.Split(imageAndTag, ":") + if len(p) == 2 { + return p[1] + } + return "latest" +} + +func GetImageName(image string) string { + imageAndTag := image + + imageTagSplit := strings.Split(image, "/") + if len(imageTagSplit) >= 2 { + imageAndTag = imageTagSplit[len(imageTagSplit)-1] + } + p := strings.Split(imageAndTag, ":") + if len(p) <= 2 { + return p[0] + } + + return image +} + func BuildS2I(image, context, builderImage string) error { - var cmd []string - // Generate the buildconfig and imagestream - log.Info("Creating buildconfig and imagestream") - cmd = []string{"oc", "new-build", "--binary", "--name=" + image, "--docker-image=" + builderImage, "--allow-missing-images"} + labels := map[string]string{ + "build": GetImageName(image), + } + annotations := map[string]string{ + "openshift.io/generated-by": "KedgeBuildS2I", + } - if err := RunCommand(cmd); err != nil { + isbuilder := os_image_v1.ImageStream{ + TypeMeta: metav1.TypeMeta{ + Kind: "ImageStream", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: GetImageName(builderImage), + Labels: labels, + Annotations: annotations, + }, + Spec: os_image_v1.ImageStreamSpec{ + Tags: []os_image_v1.TagReference{ + { + From: &kapi.ObjectReference{ + Kind: "DockerImage", + Name: GetImageName(builderImage) + ":" + GetImageTag(builderImage), + }, + }, + }, + }, + } + + is := os_image_v1.ImageStream{ + TypeMeta: metav1.TypeMeta{ + Kind: "ImageStream", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: GetImageName(image), + Labels: labels, + Annotations: annotations, + }, + Spec: os_image_v1.ImageStreamSpec{ + Tags: []os_image_v1.TagReference{ + { + From: &kapi.ObjectReference{ + Kind: "DockerImage", + Name: GetImageName(image) + ":" + GetImageTag(image), + }, + }, + }, + }, + } + + bc := os_build_v1.BuildConfig{ + TypeMeta: metav1.TypeMeta{ + Kind: "BuildConfig", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: GetImageName(image), + Labels: labels, + Annotations: annotations, + }, + Spec: os_build_v1.BuildConfigSpec{ + CommonSpec: os_build_v1.CommonSpec{ + Strategy: os_build_v1.BuildStrategy{ + Type: "Binary", + SourceStrategy: &os_build_v1.SourceBuildStrategy{ + From: kapi.ObjectReference{ + Kind: "DockerImage", + Name: builderImage, + }, + }, + }, + Output: os_build_v1.BuildOutput{ + To: &kapi.ObjectReference{ + Kind: "ImageStreamTag", + Name: GetImageName(image) + ":" + GetImageTag(image), + }, + }, + }, + }, + } + + isbuilderyaml, err := yaml.Marshal(isbuilder) + if err != nil { + return err + } + + isyaml, err := yaml.Marshal(is) + if err != nil { return err } - // start the first build since it won't be triggered automatically + bcyaml, err := yaml.Marshal(bc) + if err != nil { + return err + } + + log.Debugf("ImageStream for builder image: \n%s\n", string(isbuilderyaml)) + log.Debugf("ImageStream for output image: \n%s\n", string(isyaml)) + log.Debugf("BuildConfig: \n%s\n", string(bcyaml)) + + args := []string{"create", "-f", "-"} + err = cmd.RunClusterCommand(args, isbuilderyaml, true) + if err != nil { + log.Debugf("error creating imagestream for builderimage: %v", err) + } + err = cmd.RunClusterCommand(args, isyaml, true) + if err != nil { + return err + } + err = cmd.RunClusterCommand(args, bcyaml, true) + if err != nil { + return err + } + + // wait until builderimage buildconfig is generated + time.Sleep(3 * time.Second) + log.Infof("Starting build for %q", image) - cmd = []string{"oc", "start-build", image, "--from-dir=" + context} + //cmd := []string{"oc", "start-build", image, "--from-dir=" + context, "-w"} + cmd := []string{"oc", "start-build", image, "--from-dir=" + context, "-F"} if err := RunCommand(cmd); err != nil { return err } - log.Infof("To trigger the build again, just run:\noc start-build %s --from-dir=%s", image, context) return nil diff --git a/pkg/cmd/commands.go b/pkg/cmd/commands.go index 618a268b0..b33968d81 100644 --- a/pkg/cmd/commands.go +++ b/pkg/cmd/commands.go @@ -90,7 +90,7 @@ func CreateArtifacts(paths []string, generate bool, args ...string) error { // e.g. If the command and arguments are "apply --namespace staging", then the // final command becomes "kubectl apply --namespace staging -f -" arguments := append(args, "-f", "-") - err = runClusterCommand(arguments, data, useOC) + err = RunClusterCommand(arguments, data, useOC) if err != nil { return errors.Wrap(err, "failed to execute command") } @@ -118,7 +118,7 @@ func CreateArtifacts(paths []string, generate bool, args ...string) error { // e.g. If the command and arguments are "apply --namespace staging", then the // final command becomes "kubectl apply --namespace staging -f absolute-filename" arguments := append(args, "-f", file) - err = runClusterCommand(arguments, nil, useOC) + err = RunClusterCommand(arguments, nil, useOC) if err != nil { return errors.Wrap(err, "failed to execute command") } @@ -130,7 +130,7 @@ func CreateArtifacts(paths []string, generate bool, args ...string) error { // runClusterCommand calls kubectl or oc binary. // Boolean flag useOC controls if oc or kubectl will be used -func runClusterCommand(args []string, data []byte, useOC bool) error { +func RunClusterCommand(args []string, data []byte, useOC bool) error { executable := "kubectl" if useOC { executable = "oc"