Skip to content

Commit

Permalink
Merge pull request #126 from fluxcd/update-path
Browse files Browse the repository at this point in the history
Allow specifying the path for manifests updates
  • Loading branch information
stefanprodan authored Mar 16, 2021
2 parents 43d9d39 + 7c5d7b8 commit a1f05d9
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 7 deletions.
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)
})

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

0 comments on commit a1f05d9

Please sign in to comment.