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 d8fd323
Show file tree
Hide file tree
Showing 19 changed files with 238 additions and 22 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
2 changes: 1 addition & 1 deletion container-builder/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
)

require (
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/log v0.1.0 // indirect
Expand Down
3 changes: 1 addition & 2 deletions container-builder/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
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 d8fd323

Please sign in to comment.