diff --git a/bin/kodo b/bin/kodo index d8d0b6e..5757253 100755 Binary files a/bin/kodo and b/bin/kodo differ diff --git a/main.go b/main.go index f9ae0b0..e757e93 100644 --- a/main.go +++ b/main.go @@ -42,6 +42,8 @@ func init() { rcommand.PersistentFlags().Int32VarP(&deployVar.Port, "port", "p", 8000, "port at which app should run") rcommand.MarkFlagRequired("server") + rcommand.AddCommand(buildCommand) + rcommand.PersistentFlags().StringVarP(&deployVar.Source, "source", "o", "github.com", "github repo which has docker image") } func main() { @@ -63,6 +65,19 @@ var podCommand = &cobra.Command{ }, } +var buildCommand = &cobra.Command{ + Use: "build", + Run: func(cm *cobra.Command, args []string) { + fmt.Println("Building image from docker file at source") + err := cmd.BuildDockerFile(envVar, deployVar) + if err == nil { + fmt.Println("BuildConfig and ImageStream Created Successfully, Build can now be Started") + } else { + log.Fatal(err) + } + }, +} + var deployCommand = &cobra.Command{ Use: "deploy", Run: func(cm *cobra.Command, args []string) { @@ -97,4 +112,4 @@ var deployCommand = &cobra.Command{ } }, -} \ No newline at end of file +} diff --git a/pkg/kodo/cmd/build.go b/pkg/kodo/cmd/build.go new file mode 100644 index 0000000..e419d28 --- /dev/null +++ b/pkg/kodo/cmd/build.go @@ -0,0 +1,111 @@ +package cmd + +import ( + "context" + + "k8s.io/client-go/rest" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + buildv1api "github.com/openshift/api/build/v1" + imagev1api "github.com/openshift/api/image/v1" + + buildv1clientapi "github.com/openshift/client-go/build/clientset/versioned/typed/build/v1" + imagev1clientapi "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1" +) + +func createTypeMeta(kind string, APIVersion string) metav1.TypeMeta { + return metav1.TypeMeta{ + Kind: kind, + APIVersion: APIVersion, + } +} + +func createObjectType(name string, namespace string) metav1.ObjectMeta { + return metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + } + +} + +func createBuildSpec(uri string) buildv1api.BuildConfigSpec { + return buildv1api.BuildConfigSpec{ + CommonSpec: buildv1api.CommonSpec{ + Source: buildv1api.BuildSource{ + Type: buildv1api.BuildSourceType("Git"), + Git: &buildv1api.GitBuildSource{ + URI: uri, + }, + }, + Strategy: buildv1api.BuildStrategy{ + Type: buildv1api.BuildStrategyType("Docker"), + }, + Output: buildv1api.BuildOutput{ + To: &corev1.ObjectReference{ + Kind: "ImageStreamTag", + Name: "my-ruby-image:latest", + }, + }, + }, + } +} + +func createBuildConfig(envVar *EnvironmentVariables, deployVar *DeploymentVariables) buildv1api.BuildConfig { + return buildv1api.BuildConfig{ + TypeMeta: createTypeMeta("BuildConfig", "build.openshift.io/v1"), + ObjectMeta: createObjectType("my-app-docker-build", envVar.Namespace), + Spec: createBuildSpec(deployVar.Source), + } +} + +func createImageStream(envVar *EnvironmentVariables) imagev1api.ImageStream { + return imagev1api.ImageStream{ + TypeMeta: createTypeMeta("ImageStream", "image.openshift.io/v1"), + ObjectMeta: createObjectType("my-ruby-image", envVar.Namespace), + } +} + +func newImageStreamClient(envVar *EnvironmentVariables) *imagev1clientapi.ImageV1Client { + config := rest.Config{ + Host: envVar.Host, + BearerToken: envVar.Bearertoken, + TLSClientConfig: rest.TLSClientConfig{ + Insecure: true, + }, + } + myClientSet, _ := imagev1clientapi.NewForConfig(&config) + return myClientSet +} +func newBuildConfigClient(envVar *EnvironmentVariables) *buildv1clientapi.BuildV1Client { + config := rest.Config{ + Host: envVar.Host, + BearerToken: envVar.Bearertoken, + TLSClientConfig: rest.TLSClientConfig{ + Insecure: true, + }, + } + myClientSet, _ := buildv1clientapi.NewForConfig(&config) + return myClientSet +} + +// BuildDockerFile : creates new BuildConfig and ImageStream from Dockerfile in github repo +func BuildDockerFile(envVar *EnvironmentVariables, deployVar *DeploymentVariables) error { + buildclient := newBuildConfigClient(envVar) + buildconfig := createBuildConfig(envVar, deployVar) + + imagestreamclient := newImageStreamClient(envVar) + imagestream := createImageStream(envVar) + + _, imgerr := imagestreamclient.ImageStreams(envVar.Namespace).Create(context.TODO(), &imagestream, metav1.CreateOptions{}) + _, builderr := buildclient.BuildConfigs(envVar.Namespace).Create(context.TODO(), &buildconfig, metav1.CreateOptions{}) + + if imgerr != nil { + return imgerr + } + if builderr != nil { + return builderr + } + return nil +} diff --git a/pkg/kodo/cmd/build_test.go b/pkg/kodo/cmd/build_test.go new file mode 100644 index 0000000..17c0c47 --- /dev/null +++ b/pkg/kodo/cmd/build_test.go @@ -0,0 +1,118 @@ +package cmd + +import ( + "fmt" + "testing" + + cmp "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + buildv1api "github.com/openshift/api/build/v1" + imagev1api "github.com/openshift/api/image/v1" + corev1 "k8s.io/api/core/v1" +) + +var envVar = EnvironmentVariables{ + Namespace: "buildtest", + Host: "", + Bearertoken: "", +} + +var deployVar = DeploymentVariables{ + Source: "https://github.com/openshift/ruby-hello-world.git", +} + +func getBuildConfig() buildv1api.BuildConfig { + return buildv1api.BuildConfig{ + TypeMeta: createTypeMeta("BuildConfig", "build.openshift.io/v1"), + ObjectMeta: createObjectType("my-app-docker-build", "buildtest"), + Spec: createBuildSpec("https://github.com/openshift/ruby-hello-world.git"), + } +} + +func getBuildConfigSpec() buildv1api.BuildConfigSpec { + return buildv1api.BuildConfigSpec{ + CommonSpec: buildv1api.CommonSpec{ + Source: buildv1api.BuildSource{ + Type: buildv1api.BuildSourceType("Git"), + Git: &buildv1api.GitBuildSource{ + URI: "gitUrl", + }, + }, + Strategy: buildv1api.BuildStrategy{ + Type: buildv1api.BuildStrategyType("Docker"), + }, + Output: buildv1api.BuildOutput{ + To: &corev1.ObjectReference{ + Kind: "ImageStreamTag", + Name: "my-ruby-image:latest", + }, + }, + }, + } +} + +func getImageStream() imagev1api.ImageStream { + return imagev1api.ImageStream{ + TypeMeta: metav1.TypeMeta{ + Kind: "ImageStream", + APIVersion: "image.openshift.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-ruby-image", + Namespace: "buildtest", + }, + } +} + +func TestCreateTypeMeta(t *testing.T) { + want := metav1.TypeMeta{ + Kind: "testKind", + APIVersion: "testAPIVersion", + } + got := createTypeMeta("testKind", "testAPIVersion") + if diff := cmp.Diff(want, got); diff != "" { + fmt.Println(diff) + t.Fatalf("The TypeMeta didnt match") + } + +} + +func TestCreateObjectType(t *testing.T) { + want := metav1.ObjectMeta{ + Name: "test", + Namespace: "test-namespace", + } + got := createObjectType("test", "test-namespace") + if diff := cmp.Diff(want, got); diff != "" { + fmt.Println(diff) + t.Fatalf("The ObjectTypes didnt match") + } +} + +func TestCreateBuildSpec(t *testing.T) { + want := getBuildConfigSpec() + got := createBuildSpec("gitUrl") + if diff := cmp.Diff(want, got); diff != "" { + fmt.Println(diff) + t.Fatalf("The BuildConfigSpecs didnt match") + } +} + +func TestBuildConfig(t *testing.T) { + want := getBuildConfig() + got := createBuildConfig(&envVar, &deployVar) + if diff := cmp.Diff(want, got); diff != "" { + fmt.Println(diff) + t.Fatalf("The BuildConfigs didnt match") + } +} + +func TestImageStream(t *testing.T) { + want := getImageStream() + got := createImageStream(&envVar) + if diff := cmp.Diff(want, got); diff != "" { + fmt.Println(diff) + t.Fatalf("The ImageStreams didnt match") + } +} diff --git a/pkg/kodo/cmd/deploy.go b/pkg/kodo/cmd/deploy.go index 4a4c804..338bbc2 100644 --- a/pkg/kodo/cmd/deploy.go +++ b/pkg/kodo/cmd/deploy.go @@ -16,10 +16,12 @@ import ( cv1 "k8s.io/client-go/kubernetes/typed/core/v1" ) +//DeploymentVariables - variables associated with deployment type DeploymentVariables struct { //New struct for deployment creation variables Image string Replicas int32 Port int32 + Source string } type DeploymentIdentifiers struct { //New struct to hold unique identifiers for deployment/service/route