Add {create,export} auto image-policy

Signed-off-by: Michael Bridgen <michael@weave.works>
pull/538/head
Michael Bridgen 4 years ago
parent b66bdec61a
commit 037a5b71fd

@ -0,0 +1,182 @@
/*
Copyright 2020 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.
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 main
import (
"context"
"fmt"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"github.com/fluxcd/flux2/internal/utils"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
"github.com/fluxcd/pkg/apis/meta"
)
var createAutoImagePolicyCmd = &cobra.Command{
Use: "image-policy <name>",
Short: "Create or update an ImagePolicy object",
Long: `The create auto image-policy command generates an ImagePolicy resource.
An ImagePolicy object calculates a "latest image" given an image
repository and a policy, e.g., semver.
The image that sorts highest according to the policy is recorded in
the status of the object.`,
RunE: createAutoImagePolicyRun}
type imagePolicyFlags struct {
imageRef string
semver string
}
var imagePolicyArgs = imagePolicyFlags{}
func init() {
flags := createAutoImagePolicyCmd.Flags()
flags.StringVar(&imagePolicyArgs.imageRef, "image-ref", "", "the name of an image repository object")
flags.StringVar(&imagePolicyArgs.semver, "semver", "", "a semver range to apply to tags; e.g., '1.x'")
createAutoCmd.AddCommand(createAutoImagePolicyCmd)
}
func createAutoImagePolicyRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("ImagePolicy name is required")
}
objectName := args[0]
if imagePolicyArgs.imageRef == "" {
return fmt.Errorf("the name of an ImageRepository in the namespace is required (--image-ref)")
}
labels, err := parseLabels()
if err != nil {
return err
}
var policy = imagev1.ImagePolicy{
ObjectMeta: metav1.ObjectMeta{
Name: objectName,
Namespace: namespace,
Labels: labels,
},
Spec: imagev1.ImagePolicySpec{
ImageRepositoryRef: corev1.LocalObjectReference{
Name: imagePolicyArgs.imageRef,
},
},
}
switch {
case imagePolicyArgs.semver != "":
policy.Spec.Policy.SemVer = &imagev1.SemVerPolicy{
Range: imagePolicyArgs.semver,
}
default:
return fmt.Errorf("a policy must be provided with --semver")
}
if export {
return exportImagePolicy(policy) // defined with export command
}
// I don't need these until attempting to upsert the object, but
// for consistency with other create commands, the following are
// given a chance to error out before reporting any progress.
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
logger.Generatef("generating ImagePolicy")
logger.Actionf("applying ImagePolicy")
namespacedName, err := upsertImagePolicy(ctx, kubeClient, &policy)
if err != nil {
return err
}
logger.Waitingf("waiting for ImagePolicy reconciliation")
if err := wait.PollImmediate(pollInterval, timeout,
isImagePolicyReady(ctx, kubeClient, namespacedName, &policy)); err != nil {
return err
}
logger.Successf("ImagePolicy reconciliation completed")
return nil
}
func upsertImagePolicy(ctx context.Context, kubeClient client.Client, policy *imagev1.ImagePolicy) (types.NamespacedName, error) {
nsname := types.NamespacedName{
Namespace: policy.GetNamespace(),
Name: policy.GetName(),
}
var existing imagev1.ImagePolicy
existing.SetName(nsname.Name)
existing.SetNamespace(nsname.Namespace)
op, err := controllerutil.CreateOrUpdate(ctx, kubeClient, &existing, func() error {
existing.Spec = policy.Spec
existing.SetLabels(policy.Labels)
return nil
})
if err != nil {
return nsname, err
}
switch op {
case controllerutil.OperationResultCreated:
logger.Successf("ImagePolicy created")
case controllerutil.OperationResultUpdated:
logger.Successf("ImagePolicy updated")
}
return nsname, nil
}
func isImagePolicyReady(ctx context.Context, kubeClient client.Client,
namespacedName types.NamespacedName, policy *imagev1.ImagePolicy) wait.ConditionFunc {
return func() (bool, error) {
err := kubeClient.Get(ctx, namespacedName, policy)
if err != nil {
return false, err
}
// Confirm the state we are observing is for the current generation
if policy.Generation != policy.Status.ObservedGeneration {
return false, nil
}
if c := apimeta.FindStatusCondition(policy.Status.Conditions, meta.ReadyCondition); c != nil {
switch c.Status {
case metav1.ConditionTrue:
return true, nil
case metav1.ConditionFalse:
return false, fmt.Errorf(c.Message)
}
}
return false, nil
}
}

@ -0,0 +1,120 @@
/*
Copyright 2020 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.
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 main
import (
"context"
"fmt"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/fluxcd/flux2/internal/utils"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
)
var exportImagePolicyCmd = &cobra.Command{
Use: "image-policy [name]",
Short: "Export ImagePolicy resources in YAML format",
Long: "The export image-policy command exports one or all ImagePolicy resources in YAML format.",
Example: ` # Export all ImagePolicy resources
flux export auto image-policy --all > image-policies.yaml
# Export a specific policy
flux export auto image-policy alpine1x > alpine1x.yaml
`,
RunE: exportImagePolicyRun,
}
func init() {
exportAutoCmd.AddCommand(exportImagePolicyCmd)
}
func exportImagePolicyRun(cmd *cobra.Command, args []string) error {
if !exportAll && len(args) < 1 {
return fmt.Errorf("name is required")
}
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
if exportAll {
var list imagev1.ImagePolicyList
err = kubeClient.List(ctx, &list, client.InNamespace(namespace))
if err != nil {
return err
}
if len(list.Items) == 0 {
logger.Failuref("no imagepolicy objects found in %s namespace", namespace)
return nil
}
for _, policy := range list.Items {
if err := exportImagePolicy(policy); err != nil {
return err
}
}
} else {
name := args[0]
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var policy imagev1.ImagePolicy
err = kubeClient.Get(ctx, namespacedName, &policy)
if err != nil {
return err
}
return exportImagePolicy(policy)
}
return nil
}
func exportImagePolicy(policy imagev1.ImagePolicy) error {
gvk := imagev1.GroupVersion.WithKind(imagev1.ImagePolicyKind)
export := imagev1.ImagePolicy{
TypeMeta: metav1.TypeMeta{
Kind: gvk.Kind,
APIVersion: gvk.GroupVersion().String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: policy.Name,
Namespace: policy.Namespace,
Labels: policy.Labels,
Annotations: policy.Annotations,
},
Spec: policy.Spec,
}
data, err := yaml.Marshal(export)
if err != nil {
return err
}
fmt.Println("---")
fmt.Println(resourceToString(data))
return nil
}

@ -30,5 +30,6 @@ being available.
### SEE ALSO ### SEE ALSO
* [flux create](flux_create.md) - Create or update sources and resources * [flux create](flux_create.md) - Create or update sources and resources
* [flux create auto image-policy](flux_create_auto_image-policy.md) - Create or update an ImagePolicy object
* [flux create auto image-repository](flux_create_auto_image-repository.md) - Create or update an ImageRepository object * [flux create auto image-repository](flux_create_auto_image-repository.md) - Create or update an ImageRepository object

@ -0,0 +1,42 @@
## flux create auto image-policy
Create or update an ImagePolicy object
### Synopsis
The create auto image-policy command generates an ImagePolicy resource.
An ImagePolicy object calculates a "latest image" given an image
repository and a policy, e.g., semver.
The image that sorts highest according to the policy is recorded in
the status of the object.
```
flux create auto image-policy <name> [flags]
```
### Options
```
-h, --help help for image-policy
--image-ref string the name of an image repository object
--semver string a semver range to apply to tags; e.g., '1.x'
```
### Options inherited from parent commands
```
--context string kubernetes context to use
--export export in YAML format to stdout
--interval duration source sync interval (default 1m0s)
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
--label strings set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)
-n, --namespace string the namespace scope for this operation (default "flux-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [flux create auto](flux_create_auto.md) - Create or update resources dealing with automation

@ -26,5 +26,6 @@ The export auto sub-commands export automation object in YAML format.
### SEE ALSO ### SEE ALSO
* [flux export](flux_export.md) - Export resources in YAML format * [flux export](flux_export.md) - Export resources in YAML format
* [flux export auto image-policy](flux_export_auto_image-policy.md) - Export ImagePolicy resources in YAML format
* [flux export auto image-repository](flux_export_auto_image-repository.md) - Export ImageRepository resources in YAML format * [flux export auto image-repository](flux_export_auto_image-repository.md) - Export ImageRepository resources in YAML format

@ -0,0 +1,44 @@
## flux export auto image-policy
Export ImagePolicy resources in YAML format
### Synopsis
The export image-policy command exports one or all ImagePolicy resources in YAML format.
```
flux export auto image-policy [name] [flags]
```
### Examples
```
# Export all ImagePolicy resources
flux export auto image-policy --all > image-policies.yaml
# Export a Provider
flux export auto image-policy alpine1x > alpine1x.yaml
```
### Options
```
-h, --help help for image-policy
```
### Options inherited from parent commands
```
--all select all resources
--context string kubernetes context to use
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
-n, --namespace string the namespace scope for this operation (default "flux-system")
--timeout duration timeout for this operation (default 5m0s)
--verbose print generated objects
```
### SEE ALSO
* [flux export auto](flux_export_auto.md) - Export automation objects
Loading…
Cancel
Save