Skip to content

Commit

Permalink
kie-kogito-serverless-operator-405: Add external built image integri…
Browse files Browse the repository at this point in the history
…ty validation
  • Loading branch information
treblereel committed Sep 27, 2024
1 parent cd39bac commit e38ec80
Show file tree
Hide file tree
Showing 17 changed files with 236 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ data:
/deployments/lib/\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/*.jar
/deployments/\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/app/
/deployments/app/\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/quarkus/
/deployments/quarkus/\n\nEXPOSE 8080\nUSER 185\nENV AB_JOLOKIA_OFF=\"\"\nENV JAVA_OPTS=\"-Dquarkus.http.host=0.0.0.0
/deployments/quarkus/\nCOPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/classes/workflow.sw.json
/deployments/app/workflow.sw.json\n\nEXPOSE 8080\nUSER 185\nENV AB_JOLOKIA_OFF=\"\"\nENV JAVA_OPTS=\"-Dquarkus.http.host=0.0.0.0
-Djava.util.logging.manager=org.jboss.logmanager.LogManager\"\nENV JAVA_APP_JAR=\"/deployments/quarkus-run.jar\"\n"
kind: ConfigMap
metadata:
Expand Down
5 changes: 3 additions & 2 deletions config/manager/SonataFlow-Builder.containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ ARG MAVEN_ARGS_APPEND
COPY --chown=1001 . ./resources

RUN /home/kogito/launch/build-app.sh ./resources

#=============================
# Runtime Run
#=============================
FROM registry.access.redhat.com/ubi9/openjdk-17-runtime:latest

ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'

# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/lib/ /deployments/lib/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/*.jar /deployments/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/app/ /deployments/app/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/quarkus/ /deployments/quarkus/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/classes/workflow.sw.json /deployments/app/workflow.sw.json

EXPOSE 8080
USER 185
Expand Down
Binary file added container-builder/bin/builder
Binary file not shown.
Binary file removed container-builder/bin/controller-gen
Binary file not shown.
3 changes: 2 additions & 1 deletion container-builder/builder/kubernetes/testdata/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ COPY --from=builder --chown=185 /home/kogito/kogito-sw-base/target/quarkus-app/l
COPY --from=builder --chown=185 /home/kogito/kogito-sw-base/target/quarkus-app/*.jar /deployments/
COPY --from=builder --chown=185 /home/kogito/kogito-sw-base/target/quarkus-app/app/ /deployments/app/
COPY --from=builder --chown=185 /home/kogito/kogito-sw-base/target/quarkus-app/quarkus/ /deployments/quarkus/
COPY --from=builder --chown=185 /home/kogito/kogito-sw-base/target/classes/workflow.sw.json /deployments/app/workflow.sw.json

EXPOSE 8080
USER 185
ENV AB_JOLOKIA_OFF=""
ENV JAVA_OPTS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/*.jar /deployments/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/app/ /deployments/app/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/quarkus-app/quarkus/ /deployments/quarkus/
COPY --from=builder --chown=185 /home/kogito/serverless-workflow-project/target/classes/workflow.sw.json /deployments/app/workflow.sw.json

EXPOSE 8080
USER 185
Expand Down
123 changes: 123 additions & 0 deletions controllers/validation/ImageValidator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2024 Apache Software Foundation (ASF)
//
// Licensed 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 validation

import (
"archive/tar"
"context"
"fmt"
"io"

operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08"
"github.com/google/go-cmp/cmp"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
"k8s.io/apimachinery/pkg/util/yaml"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

type ImageValidator struct{}

var workflowName = "deployments/app/workflow.sw.json"

func (v ImageValidator) Validate(ctx context.Context, client client.Client, sonataflow *operatorapi.SonataFlow, req ctrl.Request) error {
if sonataflow.HasContainerSpecImage() {
err := client.Get(ctx, req.NamespacedName, sonataflow)
equals, err := validateImage(sonataflow, sonataflow.Spec.PodTemplate.Container.Image)
if err != nil {
return err
}
if !equals {
return fmt.Errorf("Workflow, defined in the image %s doesn't match deployment workflow", sonataflow.Spec.PodTemplate.Container.Image)
}
}
return nil
}

func validateImage(sonataflow *operatorapi.SonataFlow, image string) (bool, error) {
imageRef, err := name.ParseReference(image)
if err != nil {
return false, err
}

ref, err := remote.Image(imageRef)
if err != nil {
return false, err
}

reader, err := readLayers(ref, workflowName)
if err != nil {
return false, err
}

workflowDockerImage, err := jsonFromDockerImage(reader)
if err != nil {
return false, err
}

return cmp.Equal(workflowDockerImage, sonataflow.Spec.Flow), nil
}

func readLayers(image v1.Image, workflow string) (*tar.Reader, error) {
layers, err := image.Layers()
if err != nil {
return nil, err
}

for i := len(layers) - 1; i >= 0; i-- {
if reader, err := readLayer(layers[i], workflow); err == nil && reader != nil {
return reader, nil
} else if err != nil {
return nil, err
}
}
return nil, fmt.Errorf("file not found %s in docker image", workflow)
}

func readLayer(layer v1.Layer, workflow string) (*tar.Reader, error) {
uncompressedLayer, err := layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("failed to get uncompressed layer: %v", err)
}
defer uncompressedLayer.Close()

tarReader := tar.NewReader(uncompressedLayer)
for {
header, err := tarReader.Next()
if err != nil {
if err.Error() == "EOF" {
break
}
return nil, fmt.Errorf("error reading tar: %v", err)
}

if header.Typeflag == '0' && header.Name == workflow {
return tarReader, nil
}
}

return nil, nil
}

func jsonFromDockerImage(reader io.Reader) (operatorapi.Flow, error) {
data, err := io.ReadAll(reader)
workflow := &operatorapi.Flow{}
if err = yaml.Unmarshal(data, workflow); err != nil {
return *workflow, err
}
return *workflow, nil
}
40 changes: 40 additions & 0 deletions controllers/validation/Validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2024 Apache Software Foundation (ASF)
//
// Licensed 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 validation

import (
"context"

operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var validators = []Validator{ImageValidator{}}

type Validator interface {
Validate(ctx context.Context, client client.Client, sonataflow *operatorapi.SonataFlow, req ctrl.Request) error
}

// validate the SonataFlow object, right now it's only check if workflow is in deployment has image declared as that image
// is the same as the image in the SonataFlow object
func Validate(ctx context.Context, client client.Client, sonataflow *operatorapi.SonataFlow, req ctrl.Request) error {
for _, validator := range validators {
if err := validator.Validate(ctx, client, sonataflow, req); err != nil {
return err
}
}
return nil
}
12 changes: 10 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ require (

require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/google/go-cmp v0.6.0
github.com/google/go-containerregistry v0.20.2
github.com/imdario/mergo v0.3.16
k8s.io/klog/v2 v2.120.1
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
Expand All @@ -51,6 +53,10 @@ require (
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/docker/cli v27.1.1+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
Expand All @@ -69,8 +75,6 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-containerregistry v0.13.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect
github.com/google/uuid v1.6.0 // indirect
Expand All @@ -81,6 +85,7 @@ require (
github.com/jpillora/backoff v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/klauspost/compress v1.16.6 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
Expand All @@ -91,6 +96,7 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pb33f/libopenapi v0.8.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
Expand All @@ -104,7 +110,9 @@ require (
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 // indirect
github.com/senseyeio/duration v0.0.0-20180430131211-7c2a214ada46 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
Expand Down
Loading

0 comments on commit e38ec80

Please sign in to comment.