add support for cross-namespace sourceRef in ImageUpdateAutomation
ImageUpdateAutomation objects can now refer to GitRepository objects in other namespaces. Implemented by switching sourceRef from a SourceReference to a dependency.CrossNamespaceDependencyReference. Signed-off-by: Sanskar Jaiswal <sanskar.jaiswal@weave.works>
This commit is contained in:
parent
524b603a72
commit
3de51e7a1e
|
|
@ -29,7 +29,7 @@ type ImageUpdateAutomationSpec struct {
|
|||
// SourceRef refers to the resource giving access details
|
||||
// to a git repository.
|
||||
// +required
|
||||
SourceRef SourceReference `json:"sourceRef"`
|
||||
SourceRef CrossNamespaceSourceReference `json:"sourceRef"`
|
||||
// GitSpec contains all the git-specific definitions. This is
|
||||
// technically optional, but in practice mandatory until there are
|
||||
// other kinds of source allowed.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2020 The Flux authors
|
||||
Copyright 2020, 2021 The Flux authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,20 +16,33 @@ limitations under the License.
|
|||
|
||||
package v1beta1
|
||||
|
||||
// SourceReference contains enough information to let you locate the
|
||||
// typed, referenced source object.
|
||||
type SourceReference struct {
|
||||
// API version of the referent
|
||||
import "fmt"
|
||||
|
||||
// CrossNamespaceSourceReference contains enough information to let you locate the
|
||||
// typed Kubernetes resource object at cluster level.
|
||||
type CrossNamespaceSourceReference struct {
|
||||
// API version of the referent.
|
||||
// +optional
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
|
||||
// Kind of the referent
|
||||
// Kind of the referent.
|
||||
// +kubebuilder:validation:Enum=GitRepository
|
||||
// +kubebuilder:default=GitRepository
|
||||
// +required
|
||||
Kind string `json:"kind"`
|
||||
|
||||
// Name of the referent
|
||||
// Name of the referent.
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference.
|
||||
// +optional
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
func (s *CrossNamespaceSourceReference) String() string {
|
||||
if s.Namespace != "" {
|
||||
return fmt.Sprintf("%s/%s/%s", s.Kind, s.Namespace, s.Name)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", s.Kind, s.Name)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,21 @@ func (in *CommitUser) DeepCopy() *CommitUser {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CrossNamespaceSourceReference) DeepCopyInto(out *CrossNamespaceSourceReference) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CrossNamespaceSourceReference.
|
||||
func (in *CrossNamespaceSourceReference) DeepCopy() *CrossNamespaceSourceReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CrossNamespaceSourceReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *GitCheckoutSpec) DeepCopyInto(out *GitCheckoutSpec) {
|
||||
*out = *in
|
||||
|
|
@ -252,21 +267,6 @@ func (in *SigningKey) DeepCopy() *SigningKey {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SourceReference) DeepCopyInto(out *SourceReference) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceReference.
|
||||
func (in *SourceReference) DeepCopy() *SourceReference {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SourceReference)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *UpdateStrategy) DeepCopyInto(out *UpdateStrategy) {
|
||||
*out = *in
|
||||
|
|
|
|||
|
|
@ -645,16 +645,20 @@ spec:
|
|||
to a git repository.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent
|
||||
description: API version of the referent.
|
||||
type: string
|
||||
kind:
|
||||
default: GitRepository
|
||||
description: Kind of the referent
|
||||
description: Kind of the referent.
|
||||
enum:
|
||||
- GitRepository
|
||||
type: string
|
||||
name:
|
||||
description: Name of the referent
|
||||
description: Name of the referent.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace of the referent, defaults to the namespace
|
||||
of the Kubernetes resource object that contains the reference.
|
||||
type: string
|
||||
required:
|
||||
- kind
|
||||
|
|
|
|||
|
|
@ -162,22 +162,27 @@ func (r *ImageUpdateAutomationReconciler) Reconcile(ctx context.Context, req ctr
|
|||
if kind := auto.Spec.SourceRef.Kind; kind != sourcev1.GitRepositoryKind {
|
||||
return failWithError(fmt.Errorf("source kind %q not supported", kind))
|
||||
}
|
||||
|
||||
gitSpec := auto.Spec.GitSpec
|
||||
if gitSpec == nil {
|
||||
return failWithError(fmt.Errorf("source kind %s neccessitates field .spec.git", sourcev1.GitRepositoryKind))
|
||||
}
|
||||
|
||||
var origin sourcev1.GitRepository
|
||||
gitRepoNamespace := req.Namespace
|
||||
if auto.Spec.SourceRef.Namespace != "" {
|
||||
gitRepoNamespace = auto.Spec.SourceRef.Namespace
|
||||
}
|
||||
originName := types.NamespacedName{
|
||||
Name: auto.Spec.SourceRef.Name,
|
||||
Namespace: auto.GetNamespace(),
|
||||
Namespace: gitRepoNamespace,
|
||||
}
|
||||
debuglog.Info("fetching git repository", "gitrepository", originName)
|
||||
|
||||
if err := r.Get(ctx, originName, &origin); err != nil {
|
||||
if client.IgnoreNotFound(err) == nil {
|
||||
imagev1.SetImageUpdateAutomationReadiness(&auto, metav1.ConditionFalse, imagev1.GitNotAvailableReason, "referenced git repository is missing")
|
||||
log.Error(err, "referenced git repository does not exist")
|
||||
log.Error(err, fmt.Sprintf("referenced git repository %s does not exist.", originName.String()))
|
||||
if err := r.patchStatus(ctx, req, auto.Status); err != nil {
|
||||
return ctrl.Result{Requeue: true}, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,9 +238,189 @@ Images:
|
|||
},
|
||||
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
|
||||
SourceRef: imagev1.SourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
SourceRef: imagev1.CrossNamespaceSourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
Namespace: gitRepoKey.Namespace,
|
||||
},
|
||||
GitSpec: &imagev1.GitSpec{
|
||||
Checkout: &imagev1.GitCheckoutSpec{
|
||||
Reference: sourcev1.GitRepositoryRef{
|
||||
Branch: branch,
|
||||
},
|
||||
},
|
||||
Commit: imagev1.CommitSpec{
|
||||
MessageTemplate: commitTemplate,
|
||||
Author: imagev1.CommitUser{
|
||||
Name: authorName,
|
||||
Email: authorEmail,
|
||||
},
|
||||
},
|
||||
},
|
||||
Update: &imagev1.UpdateStrategy{
|
||||
Strategy: imagev1.UpdateStrategySetters,
|
||||
},
|
||||
},
|
||||
}
|
||||
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("formats the commit message as in the template", func() {
|
||||
head, _ := localRepo.Head()
|
||||
commit, err := localRepo.CommitObject(head.Hash())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(commit.Message).To(Equal(commitMessage))
|
||||
})
|
||||
|
||||
It("has the commit author as given", func() {
|
||||
head, _ := localRepo.Head()
|
||||
commit, err := localRepo.CommitObject(head.Hash())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(commit.Author).NotTo(BeNil())
|
||||
Expect(commit.Author.Name).To(Equal(authorName))
|
||||
Expect(commit.Author.Email).To(Equal(authorEmail))
|
||||
})
|
||||
})
|
||||
|
||||
Context("ref cross-ns GitRepository", func() {
|
||||
var (
|
||||
localRepo *git.Repository
|
||||
commitMessage string
|
||||
)
|
||||
|
||||
const (
|
||||
authorName = "Flux B Ot"
|
||||
authorEmail = "fluxbot@example.com"
|
||||
commitTemplate = `Commit summary
|
||||
|
||||
Automation: {{ .AutomationObject }}
|
||||
|
||||
Files:
|
||||
{{ range $filename, $_ := .Updated.Files -}}
|
||||
- {{ $filename }}
|
||||
{{ end -}}
|
||||
|
||||
Objects:
|
||||
{{ range $resource, $_ := .Updated.Objects -}}
|
||||
{{ if eq $resource.Kind "Deployment" -}}
|
||||
- {{ $resource.Kind | lower }} {{ $resource.Name | lower }}
|
||||
{{ else -}}
|
||||
- {{ $resource.Kind }} {{ $resource.Name }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
|
||||
Images:
|
||||
{{ range .Updated.Images -}}
|
||||
- {{.}} ({{.Policy.Name}})
|
||||
{{ end -}}
|
||||
`
|
||||
commitMessageFmt = `Commit summary
|
||||
|
||||
Automation: %s/update-test
|
||||
|
||||
Files:
|
||||
- deploy.yaml
|
||||
Objects:
|
||||
- deployment test
|
||||
Images:
|
||||
- helloworld:v1.0.0 (%s)
|
||||
`
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
Expect(initGitRepo(gitServer, "testdata/appconfig", 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())
|
||||
|
||||
// A different namespace for the GitRepository.
|
||||
gitRepoNamespace := &corev1.Namespace{}
|
||||
gitRepoNamespace.Name = "cross-ns-git-repo" + randStringRunes(5)
|
||||
Expect(k8sClient.Create(context.Background(), gitRepoNamespace)).To(Succeed())
|
||||
|
||||
gitRepoKey := types.NamespacedName{
|
||||
Name: "image-auto-" + randStringRunes(5),
|
||||
Namespace: gitRepoNamespace.Name,
|
||||
}
|
||||
gitRepo := &sourcev1.GitRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: gitRepoKey.Name,
|
||||
Namespace: gitRepoKey.Namespace,
|
||||
},
|
||||
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.NamespacedObjectReference{
|
||||
Name: "not-expected-to-exist",
|
||||
},
|
||||
Policy: imagev1_reflect.ImagePolicyChoice{
|
||||
SemVer: &imagev1_reflect.SemVerPolicy{
|
||||
Range: "1.x",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
Expect(k8sClient.Create(context.Background(), policy)).To(Succeed())
|
||||
policy.Status.LatestImage = "helloworld:v1.0.0"
|
||||
Expect(k8sClient.Status().Update(context.Background(), policy)).To(Succeed())
|
||||
|
||||
// Format the expected message given the generated values
|
||||
commitMessage = fmt.Sprintf(commitMessageFmt, namespace.Name, policyKey.Name)
|
||||
|
||||
// Insert a setter reference into the deployment file,
|
||||
// before creating the automation object itself.
|
||||
commitInRepo(repoURL, branch, "Install setter marker", func(tmp string) {
|
||||
Expect(replaceMarker(tmp, policyKey)).To(Succeed())
|
||||
})
|
||||
|
||||
// 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
|
||||
SourceRef: imagev1.CrossNamespaceSourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
Namespace: gitRepoKey.Namespace,
|
||||
},
|
||||
GitSpec: &imagev1.GitSpec{
|
||||
Checkout: &imagev1.GitCheckoutSpec{
|
||||
|
|
@ -380,9 +560,10 @@ Images:
|
|||
Strategy: imagev1.UpdateStrategySetters,
|
||||
Path: "./yes",
|
||||
},
|
||||
SourceRef: imagev1.SourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
SourceRef: imagev1.CrossNamespaceSourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
Namespace: gitRepoKey.Namespace,
|
||||
},
|
||||
GitSpec: &imagev1.GitSpec{
|
||||
Checkout: &imagev1.GitCheckoutSpec{
|
||||
|
|
@ -524,9 +705,10 @@ Images:
|
|||
Namespace: updateKey.Namespace,
|
||||
},
|
||||
Spec: imagev1.ImageUpdateAutomationSpec{
|
||||
SourceRef: imagev1.SourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
SourceRef: imagev1.CrossNamespaceSourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
Namespace: gitRepoKey.Namespace,
|
||||
},
|
||||
Interval: metav1.Duration{Duration: 2 * time.Hour}, // this is to ensure any subsequent run should be outside the scope of the testing
|
||||
GitSpec: &imagev1.GitSpec{
|
||||
|
|
@ -720,9 +902,10 @@ Images:
|
|||
|
||||
update = &imagev1.ImageUpdateAutomation{
|
||||
Spec: imagev1.ImageUpdateAutomationSpec{
|
||||
SourceRef: imagev1.SourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
SourceRef: imagev1.CrossNamespaceSourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
Namespace: gitRepoKey.Namespace,
|
||||
},
|
||||
Update: &imagev1.UpdateStrategy{
|
||||
Strategy: imagev1.UpdateStrategySetters,
|
||||
|
|
@ -838,9 +1021,10 @@ Images:
|
|||
},
|
||||
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
|
||||
SourceRef: imagev1.SourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
SourceRef: imagev1.CrossNamespaceSourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: gitRepoKey.Name,
|
||||
Namespace: gitRepoKey.Namespace,
|
||||
},
|
||||
Update: &imagev1.UpdateStrategy{
|
||||
Strategy: imagev1.UpdateStrategySetters,
|
||||
|
|
@ -960,9 +1144,10 @@ Images:
|
|||
Namespace: key.Namespace,
|
||||
},
|
||||
Spec: imagev1.ImageUpdateAutomationSpec{
|
||||
SourceRef: imagev1.SourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: "garbage",
|
||||
SourceRef: imagev1.CrossNamespaceSourceReference{
|
||||
Kind: "GitRepository",
|
||||
Name: "garbage",
|
||||
Namespace: key.Namespace,
|
||||
},
|
||||
Interval: metav1.Duration{Duration: 2 * time.Hour}, // this is to ensure any subsequent run should be outside the scope of the testing
|
||||
GitSpec: &imagev1.GitSpec{
|
||||
|
|
|
|||
|
|
@ -119,6 +119,74 @@ string
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="image.toolkit.fluxcd.io/v1beta1.CrossNamespaceSourceReference">CrossNamespaceSourceReference
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#image.toolkit.fluxcd.io/v1beta1.ImageUpdateAutomationSpec">ImageUpdateAutomationSpec</a>)
|
||||
</p>
|
||||
<p>CrossNamespaceSourceReference contains enough information to let you locate the
|
||||
typed Kubernetes resource object at cluster level.</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>apiVersion</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>API version of the referent.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>kind</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Kind of the referent.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>name</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Name of the referent.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>namespace</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Namespace of the referent, defaults to the namespace of the Kubernetes resource object that contains the reference.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="image.toolkit.fluxcd.io/v1beta1.GitCheckoutSpec">GitCheckoutSpec
|
||||
</h3>
|
||||
<p>
|
||||
|
|
@ -262,8 +330,8 @@ ImageUpdateAutomationSpec
|
|||
<td>
|
||||
<code>sourceRef</code><br>
|
||||
<em>
|
||||
<a href="#image.toolkit.fluxcd.io/v1beta1.SourceReference">
|
||||
SourceReference
|
||||
<a href="#image.toolkit.fluxcd.io/v1beta1.CrossNamespaceSourceReference">
|
||||
CrossNamespaceSourceReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
|
@ -370,8 +438,8 @@ ImageUpdateAutomationStatus
|
|||
<td>
|
||||
<code>sourceRef</code><br>
|
||||
<em>
|
||||
<a href="#image.toolkit.fluxcd.io/v1beta1.SourceReference">
|
||||
SourceReference
|
||||
<a href="#image.toolkit.fluxcd.io/v1beta1.CrossNamespaceSourceReference">
|
||||
CrossNamespaceSourceReference
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
|
@ -616,62 +684,6 @@ ImageUpdateAutomation.</p>
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="image.toolkit.fluxcd.io/v1beta1.SourceReference">SourceReference
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#image.toolkit.fluxcd.io/v1beta1.ImageUpdateAutomationSpec">ImageUpdateAutomationSpec</a>)
|
||||
</p>
|
||||
<p>SourceReference contains enough information to let you locate the
|
||||
typed, referenced source object.</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>apiVersion</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>API version of the referent</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>kind</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Kind of the referent</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>name</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Name of the referent</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="image.toolkit.fluxcd.io/v1beta1.UpdateStrategy">UpdateStrategy
|
||||
</h3>
|
||||
<p>
|
||||
|
|
|
|||
Loading…
Reference in New Issue