Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying the path for manifests updates #126

Merged
merged 2 commits into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions api/v1alpha1/imageupdateautomation_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@ type ImageUpdateAutomationSpec struct {
// ready to make changes.
// +required
Checkout GitCheckoutSpec `json:"checkout"`

// Interval gives an lower bound for how often the automation
// run should be attempted.
// +required
Interval metav1.Duration `json:"interval"`

// Update gives the specification for how to update the files in
// the repository. This can be left empty, to use the default
// value.
// +kubebuilder:default={"strategy":"Setters"}
Update *UpdateStrategy `json:"update,omitempty"`

// Commit specifies how to commit to the git repository.
// +required
Commit CommitSpec `json:"commit"`
Expand Down Expand Up @@ -87,6 +90,12 @@ type UpdateStrategy struct {
// +required
// +kubebuilder:default=Setters
Strategy UpdateStrategyName `json:"strategy"`

// Path to the directory containing the manifests to be updated.
// Defaults to 'None', which translates to the root path
// of the GitRepositoryRef.
// +optional
Path string `json:"path,omitempty"`
}

// CommitSpec specifies how to commit changes to the git repository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ spec:
files in the repository. This can be left empty, to use the default
value.
properties:
path:
description: Path to the directory containing the manifests to
be updated. Defaults to 'None', which translates to the root
path of the GitRepositoryRef.
type: string
strategy:
default: Setters
description: Strategy names the strategy to be used.
Expand Down
12 changes: 11 additions & 1 deletion controllers/imageupdateautomation_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
gogit "github.com/go-git/go-git/v5"
libgit2 "github.com/libgit2/git2go/v31"

securejoin "github.com/cyphar/filepath-securejoin"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-logr/logr"
Expand Down Expand Up @@ -196,7 +197,16 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(ctx context.Context, req ctr
return failWithError(err)
}

if result, err := updateAccordingToSetters(ctx, tmp, policies.Items); err != nil {
manifestsPath := tmp
if auto.Spec.Update.Path != "" {
if p, err := securejoin.SecureJoin(tmp, auto.Spec.Update.Path); err != nil {
return failWithError(err)
} else {
manifestsPath = p
}
}

if result, err := updateAccordingToSetters(ctx, manifestsPath, policies.Items); err != nil {
return failWithError(err)
} else {
templateValues.Updated = result
Expand Down
1 change: 1 addition & 0 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ var _ = BeforeSuite(func(done Done) {
Expect(imageAutoReconciler.SetupWithManager(k8sManager)).To(Succeed())

go func() {
defer GinkgoRecover()
err = k8sManager.Start(ctrl.SetupSignalHandler())
Expect(err).ToNot(HaveOccurred())
}()
Expand Down
10 changes: 10 additions & 0 deletions controllers/testdata/pathconfig/no/deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: update-no
spec:
template:
spec:
containers:
- name: hello
image: helloworld:1.0.0 # SETTER_SITE
10 changes: 10 additions & 0 deletions controllers/testdata/pathconfig/yes/deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: update-yes
spec:
template:
spec:
containers:
- name: hello
image: helloworld:1.0.0 # SETTER_SITE
126 changes: 125 additions & 1 deletion controllers/update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"math/rand"
"net/url"
"os"
"path"
"path/filepath"
"strings"
"time"
Expand Down Expand Up @@ -263,6 +264,130 @@ Images:
})
})

Context("update path", func() {

var localRepo *git.Repository
const commitTemplate = `Commit summary

{{ range $resource, $_ := .Updated.Objects -}}
- {{ $resource.Name }}
{{ end -}}
`

BeforeEach(func() {
Expect(initGitRepo(gitServer, "testdata/pathconfig", branch, repositoryPath)).To(Succeed())
repoURL := gitServer.HTTPAddressWithCredentials() + repositoryPath
var err error
localRepo, err = git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
URL: repoURL,
RemoteName: "origin",
ReferenceName: plumbing.NewBranchReferenceName(branch),
})
Expect(err).ToNot(HaveOccurred())

gitRepoKey := types.NamespacedName{
Name: "image-auto-" + randStringRunes(5),
Namespace: namespace.Name,
}
gitRepo := &sourcev1.GitRepository{
ObjectMeta: metav1.ObjectMeta{
Name: gitRepoKey.Name,
Namespace: namespace.Name,
},
Spec: sourcev1.GitRepositorySpec{
URL: repoURL,
Interval: metav1.Duration{Duration: time.Minute},
},
}
Expect(k8sClient.Create(context.Background(), gitRepo)).To(Succeed())
policyKey := types.NamespacedName{
Name: "policy-" + randStringRunes(5),
Namespace: namespace.Name,
}
// NB not testing the image reflector controller; this
// will make a "fully formed" ImagePolicy object.
policy := &imagev1_reflect.ImagePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: policyKey.Name,
Namespace: policyKey.Namespace,
},
Spec: imagev1_reflect.ImagePolicySpec{
ImageRepositoryRef: meta.LocalObjectReference{
Name: "not-expected-to-exist",
},
Policy: imagev1_reflect.ImagePolicyChoice{
SemVer: &imagev1_reflect.SemVerPolicy{
Range: "1.x",
},
},
},
Status: imagev1_reflect.ImagePolicyStatus{
LatestImage: "helloworld:v1.0.0",
},
}
Expect(k8sClient.Create(context.Background(), policy)).To(Succeed())
Expect(k8sClient.Status().Update(context.Background(), policy)).To(Succeed())

// Insert a setter reference into the deployment file,
// before creating the automation object itself.
commitInRepo(repoURL, branch, "Install setter marker", func(tmp string) {
replaceMarker(path.Join(tmp, "yes"), policyKey)
})
commitInRepo(repoURL, branch, "Install setter marker", func(tmp string) {
replaceMarker(path.Join(tmp, "no"), policyKey)
})

// pull the head commit we just pushed, so it's not
// considered a new commit when checking for a commit
// made by automation.
waitForNewHead(localRepo, branch)

// now create the automation object, and let it (one
// hopes!) make a commit itself.
updateKey := types.NamespacedName{
Namespace: namespace.Name,
Name: "update-test",
}
updateBySetters := &imagev1.ImageUpdateAutomation{
ObjectMeta: metav1.ObjectMeta{
Name: updateKey.Name,
Namespace: updateKey.Namespace,
},
Spec: imagev1.ImageUpdateAutomationSpec{
Interval: metav1.Duration{Duration: 2 * time.Hour}, // this is to ensure any subsequent run should be outside the scope of the testing
Checkout: imagev1.GitCheckoutSpec{
GitRepositoryRef: meta.LocalObjectReference{
Name: gitRepoKey.Name,
},
Branch: branch,
},
Update: &imagev1.UpdateStrategy{
Strategy: imagev1.UpdateStrategySetters,
Path: "./yes",
},
Commit: imagev1.CommitSpec{
MessageTemplate: commitTemplate,
},
},
}
Expect(k8sClient.Create(context.Background(), updateBySetters)).To(Succeed())
// wait for a new commit to be made by the controller
waitForNewHead(localRepo, branch)
squaremo marked this conversation as resolved.
Show resolved Hide resolved
})

AfterEach(func() {
Expect(k8sClient.Delete(context.Background(), namespace)).To(Succeed())
})

It("updates only the deployment in the specified path", func() {
head, _ := localRepo.Head()
commit, err := localRepo.CommitObject(head.Hash())
Expect(err).ToNot(HaveOccurred())
Expect(commit.Message).To(Not(ContainSubstring("update-no")))
Expect(commit.Message).To(ContainSubstring("update-yes"))
})
})

endToEnd := func(impl, proto string) func() {
return func() {
var (
Expand Down Expand Up @@ -619,7 +744,6 @@ Images:
Expect(fetchedAuto.Spec.Update).To(Equal(&imagev1.UpdateStrategy{Strategy: imagev1.UpdateStrategySetters}))
})
})

})

func expectCommittedAndPushed(conditions []metav1.Condition) {
Expand Down
92 changes: 87 additions & 5 deletions docs/api/image-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ into which will be interpolated the details of the change made.</p>
<td>
<code>gitRepositoryRef</code><br>
<em>
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#localobjectreference-v1-core">
Kubernetes core/v1.LocalObjectReference
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a>
</em>
</td>
Expand All @@ -106,7 +106,9 @@ string
</em>
</td>
<td>
<p>Branch gives the branch to clone from the git repository.</p>
<p>Branch gives the branch to clone from the git repository. If
<code>.spec.push</code> is not supplied, commits will also be pushed to
this branch.</p>
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -206,7 +208,23 @@ CommitSpec
</em>
</td>
<td>
<p>Commit specifies how to commit to the git repo</p>
<p>Commit specifies how to commit to the git repository.</p>
</td>
</tr>
<tr>
<td>
<code>push</code><br>
<em>
<a href="#image.toolkit.fluxcd.io/v1alpha1.PushSpec">
PushSpec
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Push specifies how and where to push commits made by the
automation. If missing, commits are pushed (back) to
<code>.spec.checkout.branch</code>.</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -311,7 +329,23 @@ CommitSpec
</em>
</td>
<td>
<p>Commit specifies how to commit to the git repo</p>
<p>Commit specifies how to commit to the git repository.</p>
</td>
</tr>
<tr>
<td>
<code>push</code><br>
<em>
<a href="#image.toolkit.fluxcd.io/v1alpha1.PushSpec">
PushSpec
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>Push specifies how and where to push commits made by the
automation. If missing, commits are pushed (back) to
<code>.spec.checkout.branch</code>.</p>
</td>
</tr>
<tr>
Expand Down Expand Up @@ -434,6 +468,40 @@ github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus
</table>
</div>
</div>
<h3 id="image.toolkit.fluxcd.io/v1alpha1.PushSpec">PushSpec
</h3>
<p>
(<em>Appears on:</em>
<a href="#image.toolkit.fluxcd.io/v1alpha1.ImageUpdateAutomationSpec">ImageUpdateAutomationSpec</a>)
</p>
<p>PushSpec specifies how and where to push commits.</p>
<div class="md-typeset__scrollwrap">
<div class="md-typeset__table">
<table>
<thead>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>branch</code><br>
<em>
string
</em>
</td>
<td>
<p>Branch specifies that commits should be pushed to the branch
named. The branch is created using <code>.spec.checkout.branch</code> as the
starting point, if it doesn&rsquo;t already exist.</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<h3 id="image.toolkit.fluxcd.io/v1alpha1.UpdateStrategy">UpdateStrategy
</h3>
<p>
Expand Down Expand Up @@ -466,6 +534,20 @@ UpdateStrategyName
<p>Strategy names the strategy to be used.</p>
</td>
</tr>
<tr>
<td>
<code>path</code><br>
<em>
string
</em>
</td>
<td>
<em>(Optional)</em>
<p>Path to the directory containing the manifests to be updated.
Defaults to &lsquo;None&rsquo;, which translates to the root path
of the GitRepositoryRef.</p>
</td>
</tr>
</tbody>
</table>
</div>
Expand Down
5 changes: 5 additions & 0 deletions docs/spec/v1alpha1/imageupdateautomations.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ type UpdateStrategy struct {
// Strategy names the strategy to be used.
// +required
Strategy UpdateStrategyName `json:"strategy"`
// Path to the directory containing the manifests to be updated.
// Defaults to 'None', which translates to the root path
// of the GitRepositoryRef.
// +optional
Path string `json:"path,omitempty"`
}
```

Expand Down
Loading