174 lines
5.1 KiB
Go
174 lines
5.1 KiB
Go
/*
|
|
Copyright 2022 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 object
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"time"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
|
)
|
|
|
|
var (
|
|
ErrObservedGenerationNotFound = errors.New("observed generation not found")
|
|
ErrLastHandledReconcileAtNotFound = errors.New("last handled reconcile at not found")
|
|
ErrRequeueIntervalNotFound = errors.New("requeue interval not found")
|
|
)
|
|
|
|
// toUnstructured converts a runtime object into Unstructured.
|
|
// Based on https://github.com/fluxcd/pkg/blob/b4a14854c75753ea9431693b39c4be672f246552/runtime/patch/utils.go#L55.
|
|
func toUnstructured(obj runtime.Object) (*unstructured.Unstructured, error) {
|
|
// If the incoming object is already unstructured, perform a deep copy first
|
|
// otherwise DefaultUnstructuredConverter ends up returning the inner map without
|
|
// making a copy.
|
|
if _, ok := obj.(runtime.Unstructured); ok {
|
|
obj = obj.DeepCopyObject()
|
|
}
|
|
rawMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &unstructured.Unstructured{Object: rawMap}, nil
|
|
}
|
|
|
|
// GetStatusLastHandledReconcileAt returns the status.lastHandledReconcileAt
|
|
// value of a given runtime object, if present.
|
|
func GetStatusLastHandledReconcileAt(obj runtime.Object) (string, error) {
|
|
u, err := toUnstructured(obj)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
ra, found, err := unstructured.NestedString(u.Object, "status", "lastHandledReconcileAt")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if !found {
|
|
return "", ErrLastHandledReconcileAtNotFound
|
|
}
|
|
return ra, nil
|
|
}
|
|
|
|
// SetStatusLastHandledReconcileAt sets the status.lastHandledReconcileAt value
|
|
// of a given runtime object.
|
|
func SetStatusLastHandledReconcileAt(obj runtime.Object, val string) error {
|
|
content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u := unstructured.Unstructured{}
|
|
u.SetUnstructuredContent(content)
|
|
if err := unstructured.SetNestedField(u.Object, val, "status", "lastHandledReconcileAt"); err != nil {
|
|
return err
|
|
}
|
|
return runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, obj)
|
|
}
|
|
|
|
// GetStatusObservedGeneration returns the status.observedGeneration of a given
|
|
// runtime object.
|
|
func GetStatusObservedGeneration(obj runtime.Object) (int64, error) {
|
|
u, err := toUnstructured(obj)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
og, found, err := unstructured.NestedInt64(u.Object, "status", "observedGeneration")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if !found {
|
|
return 0, ErrObservedGenerationNotFound
|
|
}
|
|
return og, nil
|
|
}
|
|
|
|
// GetRequeueInterval returns the spec.interval of a given runtime object, if
|
|
// present.
|
|
func GetRequeueInterval(obj runtime.Object) (time.Duration, error) {
|
|
period := time.Second
|
|
u, err := toUnstructured(obj)
|
|
if err != nil {
|
|
return period, err
|
|
}
|
|
interval, found, err := unstructured.NestedString(u.Object, "spec", "interval")
|
|
if err != nil {
|
|
return period, err
|
|
}
|
|
if !found {
|
|
return period, ErrRequeueIntervalNotFound
|
|
}
|
|
return time.ParseDuration(interval)
|
|
}
|
|
|
|
// GetSuspend returns the spec.suspend of a given runtime object.
|
|
func GetSuspend(obj runtime.Object) (bool, error) {
|
|
u, err := toUnstructured(obj)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
suspend, found, err := unstructured.NestedBool(u.Object, "spec", "suspend")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
// Since suspend is an optional field, it's false when not found.
|
|
if !found {
|
|
return false, nil
|
|
}
|
|
return suspend, nil
|
|
}
|
|
|
|
// SetSuspend sets the spec.suspend value of a given runtime object.
|
|
func SetSuspend(obj runtime.Object, val bool) error {
|
|
content, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
u := unstructured.Unstructured{}
|
|
u.SetUnstructuredContent(content)
|
|
if err := unstructured.SetNestedField(u.Object, val, "spec", "suspend"); err != nil {
|
|
return err
|
|
}
|
|
return runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, obj)
|
|
}
|
|
|
|
// GetArtifact returns the status.artifact of a given runtime object.
|
|
func GetArtifact(obj runtime.Object) (*sourcev1.Artifact, error) {
|
|
u, err := toUnstructured(obj)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
artifact, found, err := unstructured.NestedFieldNoCopy(u.Object, "status", "artifact")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Since artifact is an optional field, return nil when not found.
|
|
if !found {
|
|
return nil, nil
|
|
}
|
|
enc, err := json.Marshal(artifact)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
outArtifact := &sourcev1.Artifact{}
|
|
if err := json.Unmarshal(enc, outArtifact); err != nil {
|
|
return nil, err
|
|
}
|
|
return outArtifact, nil
|
|
}
|