You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2018/09/21 13:56:57 UTC
[camel-k] 02/04: Added incremental publisher
This is an automated email from the ASF dual-hosted git repository.
nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit 2c51dfd0d359885a8b298b35d77e50fbf0fb200f
Author: nferraro <ni...@gmail.com>
AuthorDate: Fri Sep 21 13:26:20 2018 +0200
Added incremental publisher
---
pkg/build/publish/s2i_incremental_publisher.go | 105 +++++++++++++++++++++++++
pkg/build/publish/s2i_publisher.go | 43 +++++++---
2 files changed, 137 insertions(+), 11 deletions(-)
diff --git a/pkg/build/publish/s2i_incremental_publisher.go b/pkg/build/publish/s2i_incremental_publisher.go
new file mode 100644
index 0000000..42d7c81
--- /dev/null
+++ b/pkg/build/publish/s2i_incremental_publisher.go
@@ -0,0 +1,105 @@
+/*
+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 publish
+
+import (
+ "context"
+ "github.com/apache/camel-k/pkg/build"
+)
+
+type s2iIncrementalPublisher struct {
+ s2iPublisher *s2iPublisher
+ lister PublishedImagesLister
+}
+
+// PublishedImage represent a base image that can be used as starting point
+type PublishedImage struct {
+ Image string
+ Classpath []string
+}
+
+// PublishedImagesLister allows to list all images already published
+type PublishedImagesLister interface {
+ ListPublishedImages() ([]PublishedImage, error)
+}
+
+// NewS2IIncrementalPublisher creates a new publisher that is able to do a Openshift S2I binary builds on top of other builds
+func NewS2IIncrementalPublisher(ctx context.Context, namespace string, lister PublishedImagesLister) build.Publisher {
+ layeredPublisher := s2iIncrementalPublisher{
+ lister: lister,
+ }
+ layeredPublisher.s2iPublisher = newS2IPublisher(ctx, namespace, layeredPublisher.selectArtifactsToUpload)
+ return &layeredPublisher
+}
+
+func (p *s2iIncrementalPublisher) Publish(req build.Request, assembled build.AssembledOutput) <-chan build.PublishedOutput {
+ return p.s2iPublisher.Publish(req, assembled)
+}
+
+func (p *s2iIncrementalPublisher) selectArtifactsToUpload(entries []build.ClasspathEntry) (string, []build.ClasspathEntry, error) {
+ images, err := p.lister.ListPublishedImages()
+ if err != nil {
+ return "", nil, err
+ }
+
+ bestImage, commonLibs := p.findBestImage(images, entries)
+ if (bestImage != nil) {
+ selectedClasspath := make([]build.ClasspathEntry, 0)
+ for _, entry := range entries {
+ if _, isCommon := commonLibs[entry.ID]; !isCommon {
+ selectedClasspath = append(selectedClasspath, entry)
+ }
+ }
+
+ return bestImage.Image, selectedClasspath, nil
+ }
+
+ // return default selection
+ return baseImage, entries, nil
+}
+
+func (p *s2iIncrementalPublisher) findBestImage(images []PublishedImage, entries []build.ClasspathEntry) (*PublishedImage, map[string]bool) {
+ requiredLibs := make(map[string]bool, len(entries))
+ for _, entry := range entries {
+ requiredLibs[entry.ID] = true
+ }
+
+ var bestImage *PublishedImage
+ bestImageCommonLibs := make(map[string]bool, 0)
+ for _, image := range images {
+ common := make(map[string]bool)
+ for _, id := range image.Classpath {
+ if _, ok := requiredLibs[id]; ok {
+ common[id] = true
+ }
+ }
+ numCommonLibs := len(common)
+ surplus := len(image.Classpath) - numCommonLibs
+ if surplus >= numCommonLibs/3 {
+ // Heuristic approach: if there are too many unrelated libraries, just use the base image
+ continue
+ }
+
+ if (numCommonLibs > len(bestImageCommonLibs)) {
+ bestImage = &image
+ bestImageCommonLibs = common
+ }
+ }
+
+ return bestImage, bestImageCommonLibs
+}
diff --git a/pkg/build/publish/s2i_publisher.go b/pkg/build/publish/s2i_publisher.go
index 5548194..ee86a1e 100644
--- a/pkg/build/publish/s2i_publisher.go
+++ b/pkg/build/publish/s2i_publisher.go
@@ -40,11 +40,13 @@ import (
const (
artifactDirPrefix = "s2i-"
+ baseImage = "fabric8/s2i-java:2.3"
)
type s2iPublisher struct {
buffer chan publishOperation
namespace string
+ uploadedArtifactsSelector
}
type publishOperation struct {
@@ -53,11 +55,20 @@ type publishOperation struct {
output chan build.PublishedOutput
}
+type uploadedArtifactsSelector func([]build.ClasspathEntry) (string, []build.ClasspathEntry, error)
+
// NewS2IPublisher creates a new publisher doing a Openshift S2I binary build
func NewS2IPublisher(ctx context.Context, namespace string) build.Publisher {
+ identitySelector := func(entries []build.ClasspathEntry) (string, []build.ClasspathEntry, error) { return baseImage, entries, nil }
+ return newS2IPublisher(ctx, namespace, identitySelector)
+}
+
+// NewS2IPublisher creates a new publisher doing a Openshift S2I binary build
+func newS2IPublisher(ctx context.Context, namespace string, uploadedArtifactsSelector uploadedArtifactsSelector) *s2iPublisher {
publisher := s2iPublisher{
- buffer: make(chan publishOperation, 100),
- namespace: namespace,
+ buffer: make(chan publishOperation, 100),
+ namespace: namespace,
+ uploadedArtifactsSelector: uploadedArtifactsSelector,
}
go publisher.publishCycle(ctx)
return &publisher
@@ -98,12 +109,17 @@ func (b *s2iPublisher) publishCycle(ctx context.Context) {
}
func (b *s2iPublisher) execute(request build.Request, assembled build.AssembledOutput) build.PublishedOutput {
- tarFile, err := b.createTar(assembled)
+ baseImageName, selectedArtifacts, err := b.uploadedArtifactsSelector(assembled.Classpath)
if err != nil {
return build.PublishedOutput{Error: err}
}
- image, err := b.publish(tarFile, request)
+ tarFile, err := b.createTar(assembled, selectedArtifacts)
+ if err != nil {
+ return build.PublishedOutput{Error: err}
+ }
+
+ image, err := b.publish(tarFile, baseImageName, request)
if err != nil {
return build.PublishedOutput{Error: err}
}
@@ -111,7 +127,7 @@ func (b *s2iPublisher) execute(request build.Request, assembled build.AssembledO
return build.PublishedOutput{Image: image}
}
-func (b *s2iPublisher) publish(tarFile string, source build.Request) (string, error) {
+func (b *s2iPublisher) publish(tarFile string, imageName string, source build.Request) (string, error) {
bc := buildv1.BuildConfig{
TypeMeta: metav1.TypeMeta{
@@ -131,7 +147,7 @@ func (b *s2iPublisher) publish(tarFile string, source build.Request) (string, er
SourceStrategy: &buildv1.SourceBuildStrategy{
From: v1.ObjectReference{
Kind: "DockerImage",
- Name: "fabric8/s2i-java:2.3",
+ Name: imageName,
},
},
},
@@ -235,7 +251,7 @@ func (b *s2iPublisher) publish(tarFile string, source build.Request) (string, er
return is.Status.DockerImageRepository + ":" + source.Identifier.Qualifier, nil
}
-func (b *s2iPublisher) createTar(assembled build.AssembledOutput) (string, error) {
+func (b *s2iPublisher) createTar(assembled build.AssembledOutput, selectedArtifacts []build.ClasspathEntry) (string, error) {
artifactDir, err := ioutil.TempDir("", artifactDirPrefix)
if err != nil {
return "", errors.Wrap(err, "could not create temporary dir for s2i artifacts")
@@ -248,19 +264,24 @@ func (b *s2iPublisher) createTar(assembled build.AssembledOutput) (string, error
}
defer tarAppender.Close()
- cp := ""
- for _, entry := range assembled.Classpath {
+ tarDir := "dependencies/"
+ for _, entry := range selectedArtifacts {
gav, err := maven.ParseGAV(entry.ID)
if err != nil {
return "", nil
}
- tarPath := path.Join("dependencies/", gav.GroupID)
- fileName, err := tarAppender.AddFile(entry.Location, tarPath)
+ tarPath := path.Join(tarDir, gav.GroupID)
+ _, err = tarAppender.AddFile(entry.Location, tarPath)
if err != nil {
return "", err
}
+ }
+ cp := ""
+ for _, entry := range assembled.Classpath {
+ _, fileName := path.Split(entry.Location)
+ fileName = path.Join(tarDir, fileName)
cp += fileName + "\n"
}