| /* |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package s2i |
| |
| import ( |
| "io/ioutil" |
| "os" |
| "path" |
| |
| "github.com/pkg/errors" |
| |
| corev1 "k8s.io/api/core/v1" |
| apierrors "k8s.io/apimachinery/pkg/api/errors" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| "k8s.io/apimachinery/pkg/util/json" |
| |
| k8sclient "sigs.k8s.io/controller-runtime/pkg/client" |
| |
| buildv1 "github.com/openshift/api/build/v1" |
| imagev1 "github.com/openshift/api/image/v1" |
| |
| "github.com/apache/camel-k/pkg/builder" |
| "github.com/apache/camel-k/pkg/util/kubernetes" |
| "github.com/apache/camel-k/pkg/util/kubernetes/customclient" |
| "github.com/apache/camel-k/pkg/util/zip" |
| ) |
| |
| func publisher(ctx *builder.Context) error { |
| bc := buildv1.BuildConfig{ |
| TypeMeta: metav1.TypeMeta{ |
| APIVersion: buildv1.GroupVersion.String(), |
| Kind: "BuildConfig", |
| }, |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "camel-k-" + ctx.Build.Meta.Name, |
| Namespace: ctx.Namespace, |
| Labels: map[string]string{ |
| "app": "camel-k", |
| }, |
| }, |
| Spec: buildv1.BuildConfigSpec{ |
| CommonSpec: buildv1.CommonSpec{ |
| Source: buildv1.BuildSource{ |
| Type: buildv1.BuildSourceBinary, |
| }, |
| Strategy: buildv1.BuildStrategy{ |
| DockerStrategy: &buildv1.DockerBuildStrategy{}, |
| }, |
| Output: buildv1.BuildOutput{ |
| To: &corev1.ObjectReference{ |
| Kind: "ImageStreamTag", |
| Name: "camel-k-" + ctx.Build.Meta.Name + ":" + ctx.Build.Meta.ResourceVersion, |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| bc.Labels = kubernetes.MergeCamelCreatorLabels(ctx.Build.Meta.Labels, bc.Labels) |
| |
| err := ctx.Client.Delete(ctx.C, &bc) |
| if err != nil && !apierrors.IsNotFound(err) { |
| return errors.Wrap(err, "cannot delete build config") |
| } |
| |
| err = ctx.Client.Create(ctx.C, &bc) |
| if err != nil { |
| return errors.Wrap(err, "cannot create build config") |
| } |
| |
| is := imagev1.ImageStream{ |
| TypeMeta: metav1.TypeMeta{ |
| APIVersion: imagev1.GroupVersion.String(), |
| Kind: "ImageStream", |
| }, |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "camel-k-" + ctx.Build.Meta.Name, |
| Namespace: ctx.Namespace, |
| Labels: map[string]string{ |
| "app": "camel-k", |
| }, |
| }, |
| Spec: imagev1.ImageStreamSpec{ |
| LookupPolicy: imagev1.ImageLookupPolicy{ |
| Local: true, |
| }, |
| }, |
| } |
| |
| is.Labels = kubernetes.MergeCamelCreatorLabels(ctx.Build.Meta.Labels, is.Labels) |
| |
| err = ctx.Client.Delete(ctx.C, &is) |
| if err != nil && !apierrors.IsNotFound(err) { |
| return errors.Wrap(err, "cannot delete image stream") |
| } |
| |
| err = ctx.Client.Create(ctx.C, &is) |
| if err != nil { |
| return errors.Wrap(err, "cannot create image stream") |
| } |
| |
| archive := path.Join(ctx.Path, "archive.zip") |
| err = zip.Directory(path.Join(ctx.Path, "context"), archive) |
| if err != nil { |
| return errors.Wrap(err, "cannot zip context directory") |
| } |
| |
| resource, err := ioutil.ReadFile(archive) |
| if err != nil { |
| return errors.Wrap(err, "cannot fully read zip file "+archive) |
| } |
| |
| defer os.RemoveAll(ctx.Path) |
| |
| restClient, err := customclient.GetClientFor(ctx.Client, "build.openshift.io", "v1") |
| if err != nil { |
| return err |
| } |
| |
| result := restClient.Post(). |
| Namespace(ctx.Namespace). |
| Body(resource). |
| Resource("buildconfigs"). |
| Name("camel-k-" + ctx.Build.Meta.Name). |
| SubResource("instantiatebinary"). |
| Do(ctx.C) |
| |
| if result.Error() != nil { |
| return errors.Wrap(result.Error(), "cannot instantiate binary") |
| } |
| |
| data, err := result.Raw() |
| if err != nil { |
| return errors.Wrap(err, "no raw data retrieved") |
| } |
| |
| ocbuild := buildv1.Build{} |
| err = json.Unmarshal(data, &ocbuild) |
| if err != nil { |
| return errors.Wrap(err, "cannot unmarshal instantiated binary response") |
| } |
| |
| err = kubernetes.WaitCondition(ctx.C, ctx.Client, &ocbuild, func(obj interface{}) (bool, error) { |
| if val, ok := obj.(*buildv1.Build); ok { |
| if val.Status.Phase == buildv1.BuildPhaseComplete { |
| if val.Status.Output.To != nil { |
| ctx.Digest = val.Status.Output.To.ImageDigest |
| } |
| return true, nil |
| } else if val.Status.Phase == buildv1.BuildPhaseCancelled || |
| val.Status.Phase == buildv1.BuildPhaseFailed || |
| val.Status.Phase == buildv1.BuildPhaseError { |
| return false, errors.New("build failed") |
| } |
| } |
| return false, nil |
| }, ctx.Build.Timeout.Duration) |
| |
| if err != nil { |
| return err |
| } |
| |
| key, err := k8sclient.ObjectKeyFromObject(&is) |
| if err != nil { |
| return err |
| } |
| err = ctx.Client.Get(ctx.C, key, &is) |
| if err != nil { |
| return err |
| } |
| |
| if is.Status.DockerImageRepository == "" { |
| return errors.New("dockerImageRepository not available in ImageStream") |
| } |
| |
| ctx.Image = is.Status.DockerImageRepository + ":" + ctx.Build.Meta.ResourceVersion |
| |
| return nil |
| } |