chore: Move Inventory object to pkg/apis/actuation

- Replace custom TypeMeta & ObjectMeta with standard metav1 structs
  to allow Inventory to satisfy the metav1.Object, runtime.Object,
  and client.Object interfaces. This should make the Inventory API
  easier to use and easily convertable to an Unstructured object.

BREAKING CHANGE: Move inventory.Inventory to actuation.Inventory (under pkg/apis/)
This commit is contained in:
Karl Isenberg 2022-02-14 22:35:53 -08:00
parent 2b7c073a37
commit bb84f24cb0
12 changed files with 357 additions and 214 deletions

2
LICENSE_TEMPLATE_GO Normal file
View File

@ -0,0 +1,2 @@
// Copyright YEAR The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

View File

@ -35,7 +35,13 @@ install-addlicense:
install-lint:
(which $(GOPATH)/bin/golangci-lint || go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.40.1)
generate: install-stringer
install-deepcopy-gen:
(which $(GOPATH)/bin/deepcopy-gen || go install k8s.io/code-generator/cmd/deepcopy-gen@v0.23.3)
generate-deepcopy: install-deepcopy-gen
hack/run-in-gopath.sh deepcopy-gen --input-dirs ./pkg/apis/... -O zz_generated.deepcopy --go-header-file ./LICENSE_TEMPLATE_GO
generate: install-stringer generate-deepcopy
go generate ./...
license: install-addlicense

43
hack/run-in-gopath.sh Executable file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Copyright 2021 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
set -o errexit -o nounset -o pipefail -o posix
PKG_PATH="sigs.k8s.io/cli-utils"
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
# Make a new temporary GOPATH directory
export GOPATH=$(mktemp -d -t cli-utils-gopath.XXXXXXXXXX)
# Clean up on exit (modcache has read-only files, so clean that first)
trap "go clean -modcache && rm '${GOPATH}/src/${PKG_PATH}' && rm -rf '${GOPATH}'" EXIT
# Make sure we can read, write, and delete
chmod a+rw "${GOPATH}"
# Use a temporary cache
export GOCACHE="${GOPATH}/cache"
# Create a symlink for the local repo in the GOPATH
mkdir -p "${GOPATH}/src/${PKG_PATH}"
rm -r "${GOPATH}/src/${PKG_PATH}"
ln -s "${REPO_ROOT}" "${GOPATH}/src/${PKG_PATH}"
# Make sure our own Go binaries are in PATH.
export PATH="${GOPATH}/bin:${PATH}"
# Set GOROOT so binaries that parse code can work properly.
export GOROOT=$(go env GOROOT)
# Unset GOBIN in case it already exists in the current session.
unset GOBIN
# enter the GOPATH before executing the command
cd "${GOPATH}/src/${PKG_PATH}"
# Run the user-provided command.
"${@}"
# exit the GOPATH before deleting it
cd "${REPO_ROOT}"

View File

@ -1,6 +1,6 @@
// Code generated by "stringer -type=ActuationStatus -linecomment"; DO NOT EDIT.
package inventory
package actuation
import "strconv"

View File

@ -1,6 +1,6 @@
// Code generated by "stringer -type=ActuationStrategy -linecomment"; DO NOT EDIT.
package inventory
package actuation
import "strconv"

View File

@ -0,0 +1,8 @@
// Copyright 2021 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package actuation contains API Schema definitions for the
// cli-utils.kubernetes.io API group.
// +k8s:deepcopy-gen=package
// +groupName=cli-utils.kubernetes.io
package actuation // import "sigs.k8s.io/cli-utils/pkg/apis/actuation"

View File

@ -1,6 +1,6 @@
// Code generated by "stringer -type=ReconcileStatus -linecomment"; DO NOT EDIT.
package inventory
package actuation
import "strconv"

View File

@ -1,18 +1,19 @@
// Copyright 2021 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package inventory
package actuation
import "k8s.io/apimachinery/pkg/types"
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)
// Inventory represents the inventory object in memory.
// Inventory is currently only used for in-memory storage and not serialized to
// disk or to the API server.
// TODO: Replace InventoryInfo with Inventory.TypeMeta & Inventory.ObjectMeta
// TODO: Replace object.ObjMetadataSet in Storage interface with Inventory.Spec
type Inventory struct {
TypeMeta `json:",inline"`
ObjectMeta `json:"metadata,omitempty"`
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec InventorySpec `json:"spec,omitempty"`
Status InventoryStatus `json:"status,omitempty"`
@ -106,29 +107,3 @@ const (
ReconcileFailed // Failed
ReconcileTimeout // Timeout
)
// TypeMeta describes a REST resource.
type TypeMeta struct {
// Kind is a string value representing the REST resource this object represents.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
Kind string `json:"kind,omitempty"`
// APIVersion defines the versioned schema of this representation of an object.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
APIVersion string `json:"apiVersion,omitempty"`
}
// ObjectMeta describes an individual object instance of a REST resource.
// TODO: Do we need other fields, like UID, Generation, ResourceVersion, and CreationTimestamp?
type ObjectMeta struct {
// Name identifies an object instance of a REST resource.
// More info: http://kubernetes.io/docs/user-guide/identifiers#names
Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
// Namespace identifies a group of objects across REST resources.
// If namespace is specified, the resource must be namespace-scoped.
// If namespace is omitted, the resource must be cluster-scoped.
// More info: http://kubernetes.io/docs/user-guide/namespaces
// +optional
Namespace string `json:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"`
}

View File

@ -0,0 +1,104 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
// Copyright 2022 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Code generated by deepcopy-gen. DO NOT EDIT.
package actuation
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Inventory) DeepCopyInto(out *Inventory) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Inventory.
func (in *Inventory) DeepCopy() *Inventory {
if in == nil {
return nil
}
out := new(Inventory)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InventorySpec) DeepCopyInto(out *InventorySpec) {
*out = *in
if in.Objects != nil {
in, out := &in.Objects, &out.Objects
*out = make([]ObjectReference, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InventorySpec.
func (in *InventorySpec) DeepCopy() *InventorySpec {
if in == nil {
return nil
}
out := new(InventorySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *InventoryStatus) DeepCopyInto(out *InventoryStatus) {
*out = *in
if in.Objects != nil {
in, out := &in.Objects, &out.Objects
*out = make([]ObjectStatus, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InventoryStatus.
func (in *InventoryStatus) DeepCopy() *InventoryStatus {
if in == nil {
return nil
}
out := new(InventoryStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectReference) DeepCopyInto(out *ObjectReference) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectReference.
func (in *ObjectReference) DeepCopy() *ObjectReference {
if in == nil {
return nil
}
out := new(ObjectReference)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectStatus) DeepCopyInto(out *ObjectStatus) {
*out = *in
out.ObjectReference = in.ObjectReference
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectStatus.
func (in *ObjectStatus) DeepCopy() *ObjectStatus {
if in == nil {
return nil
}
out := new(ObjectStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -8,6 +8,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/cli-utils/pkg/apis/actuation"
"sigs.k8s.io/cli-utils/pkg/apply/cache"
"sigs.k8s.io/cli-utils/pkg/apply/event"
"sigs.k8s.io/cli-utils/pkg/inventory"
@ -215,36 +216,36 @@ loop:
"Actual events (%d) do not match expected events (%d)",
len(receivedEvents), len(expectedEvents))
expectedInventory := inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory := actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment1.GetUID(),
Generation: testDeployment1.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment2.GetUID(),
Generation: testDeployment2.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment3ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationFailed,
Reconcile: inventory.ReconcileSkipped,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationFailed,
Reconcile: actuation.ReconcileSkipped,
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment4ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSkipped,
Reconcile: inventory.ReconcileSkipped,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSkipped,
Reconcile: actuation.ReconcileSkipped,
},
},
},
@ -387,36 +388,36 @@ loop:
"Actual events (%d) do not match expected events (%d)",
len(receivedEvents), len(expectedEvents))
expectedInventory := inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory := actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment1.GetUID(),
Generation: testDeployment1.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileTimeout,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileTimeout,
UID: testDeployment2.GetUID(),
Generation: testDeployment2.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment3ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationFailed,
Reconcile: inventory.ReconcileSkipped,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationFailed,
Reconcile: actuation.ReconcileSkipped,
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment4ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSkipped,
Reconcile: inventory.ReconcileSkipped,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSkipped,
Reconcile: actuation.ReconcileSkipped,
},
},
},
@ -492,14 +493,14 @@ loop:
"Actual events (%d) do not match expected events (%d)",
len(receivedEvents), len(expectedEvents))
expectedInventory := inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory := actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeploymentID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment.GetUID(),
Generation: testDeployment.GetGeneration(),
},
@ -579,14 +580,14 @@ loop:
"Actual events (%d) do not match expected events (%d)",
len(receivedEvents), len(expectedEvents))
expectedInventory := inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory := actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeploymentID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcilePending,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcilePending,
UID: testDeployment.GetUID(),
Generation: testDeployment.GetGeneration(),
},
@ -687,14 +688,14 @@ loop:
}
assert.Equal(t, expectedResults, receivedResults)
expectedInventory := inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory := actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeploymentID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment.GetUID(),
Generation: testDeployment.GetGeneration(),
},
@ -722,7 +723,7 @@ func TestWaitTask_Failed(t *testing.T) {
eventsFunc func(*cache.ResourceCacheMap, *WaitTask, *TaskContext)
waitTimeout time.Duration
expectedEvents []event.Event
expectedInventory *inventory.Inventory
expectedInventory *actuation.Inventory
}{
"continue on failed if others InProgress": {
configureTaskContextFunc: func(taskContext *TaskContext) {
@ -790,22 +791,22 @@ func TestWaitTask_Failed(t *testing.T) {
},
},
},
expectedInventory: &inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory: &actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileFailed,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileFailed,
UID: testDeployment1.GetUID(),
Generation: testDeployment1.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment2.GetUID(),
Generation: testDeployment2.GetGeneration(),
},
@ -873,22 +874,22 @@ func TestWaitTask_Failed(t *testing.T) {
},
},
},
expectedInventory: &inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory: &actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileFailed,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileFailed,
UID: testDeployment1.GetUID(),
Generation: testDeployment1.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment2.GetUID(),
Generation: testDeployment2.GetGeneration(),
},
@ -971,22 +972,22 @@ func TestWaitTask_Failed(t *testing.T) {
},
},
},
expectedInventory: &inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory: &actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment1.GetUID(),
Generation: testDeployment1.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment2.GetUID(),
Generation: testDeployment2.GetGeneration(),
},
@ -1078,22 +1079,22 @@ func TestWaitTask_Failed(t *testing.T) {
},
},
},
expectedInventory: &inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory: &actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileTimeout,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileTimeout,
UID: testDeployment1.GetUID(),
Generation: testDeployment1.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment2.GetUID(),
Generation: testDeployment2.GetGeneration(),
},
@ -1175,7 +1176,7 @@ func TestWaitTask_UIDChanged(t *testing.T) {
eventsFunc func(*cache.ResourceCacheMap, *WaitTask, *TaskContext)
waitTimeout time.Duration
expectedEvents []event.Event
expectedInventory *inventory.Inventory
expectedInventory *actuation.Inventory
}{
"UID changed after apply means reconcile failure": {
condition: AllCurrent,
@ -1239,24 +1240,24 @@ func TestWaitTask_UIDChanged(t *testing.T) {
},
},
},
expectedInventory: &inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory: &actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
// UID change causes failure after apply
Reconcile: inventory.ReconcileFailed,
Reconcile: actuation.ReconcileFailed,
// Recorded UID should be from the applied object, not the new replacement
UID: testDeployment1.GetUID(),
Generation: testDeployment1.GetGeneration(),
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyApply,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment2.GetUID(),
Generation: testDeployment2.GetGeneration(),
},
@ -1326,24 +1327,24 @@ func TestWaitTask_UIDChanged(t *testing.T) {
},
},
},
expectedInventory: &inventory.Inventory{
Status: inventory.InventoryStatus{
Objects: []inventory.ObjectStatus{
expectedInventory: &actuation.Inventory{
Status: actuation.InventoryStatus{
Objects: []actuation.ObjectStatus{
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment1ID),
Strategy: inventory.ActuationStrategyDelete,
Actuation: inventory.ActuationSucceeded,
Strategy: actuation.ActuationStrategyDelete,
Actuation: actuation.ActuationSucceeded,
// UID change causes success after delete
Reconcile: inventory.ReconcileSucceeded,
Reconcile: actuation.ReconcileSucceeded,
// Recorded UID should be from the deleted object, not the new replacement
UID: testDeployment1.GetUID(),
// Deleted generation is unknown
},
{
ObjectReference: inventory.ObjectReferenceFromObjMetadata(testDeployment2ID),
Strategy: inventory.ActuationStrategyDelete,
Actuation: inventory.ActuationSucceeded,
Reconcile: inventory.ReconcileSucceeded,
Strategy: actuation.ActuationStrategyDelete,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcileSucceeded,
UID: testDeployment2.GetUID(),
// Deleted generation is unknown
},

View File

@ -8,29 +8,30 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"sigs.k8s.io/cli-utils/pkg/apis/actuation"
"sigs.k8s.io/cli-utils/pkg/object"
)
// Manager wraps an Inventory with convenience methods that use ObjMetadata.
type Manager struct {
inventory *Inventory
inventory *actuation.Inventory
}
// NewManager returns a new manager instance.
func NewManager() *Manager {
return &Manager{
inventory: &Inventory{},
inventory: &actuation.Inventory{},
}
}
// Inventory returns the in-memory version of the managed inventory.
func (tc *Manager) Inventory() *Inventory {
func (tc *Manager) Inventory() *actuation.Inventory {
return tc.inventory
}
// ObjectStatus retrieves the status of an object with the specified ID.
// The returned status is a pointer and can be updated in-place for efficiency.
func (tc *Manager) ObjectStatus(id object.ObjMetadata) (*ObjectStatus, bool) {
func (tc *Manager) ObjectStatus(id object.ObjMetadata) (*actuation.ObjectStatus, bool) {
for i, objStatus := range tc.inventory.Status.Objects {
if ObjMetadataEqualObjectReference(id, objStatus.ObjectReference) {
return &(tc.inventory.Status.Objects[i]), true
@ -41,7 +42,7 @@ func (tc *Manager) ObjectStatus(id object.ObjMetadata) (*ObjectStatus, bool) {
// ObjectsWithActuationStatus retrieves the set of objects with the
// specified actuation strategy and status.
func (tc *Manager) ObjectsWithActuationStatus(strategy ActuationStrategy, status ActuationStatus) object.ObjMetadataSet {
func (tc *Manager) ObjectsWithActuationStatus(strategy actuation.ActuationStrategy, status actuation.ActuationStatus) object.ObjMetadataSet {
var ids object.ObjMetadataSet
for _, objStatus := range tc.inventory.Status.Objects {
if objStatus.Strategy == strategy && objStatus.Actuation == status {
@ -53,7 +54,7 @@ func (tc *Manager) ObjectsWithActuationStatus(strategy ActuationStrategy, status
// ObjectsWithActuationStatus retrieves the set of objects with the
// specified reconcile status, regardless of actuation strategy.
func (tc *Manager) ObjectsWithReconcileStatus(status ReconcileStatus) object.ObjMetadataSet {
func (tc *Manager) ObjectsWithReconcileStatus(status actuation.ReconcileStatus) object.ObjMetadataSet {
var ids object.ObjMetadataSet
for _, objStatus := range tc.inventory.Status.Objects {
if objStatus.Reconcile == status {
@ -64,7 +65,7 @@ func (tc *Manager) ObjectsWithReconcileStatus(status ReconcileStatus) object.Obj
}
// SetObjectStatus updates or adds an ObjectStatus record to the inventory.
func (tc *Manager) SetObjectStatus(id object.ObjMetadata, objStatus ObjectStatus) {
func (tc *Manager) SetObjectStatus(id object.ObjMetadata, objStatus actuation.ObjectStatus) {
for i, objStatus := range tc.inventory.Status.Objects {
if ObjMetadataEqualObjectReference(id, objStatus.ObjectReference) {
tc.inventory.Status.Objects[i] = objStatus
@ -80,19 +81,19 @@ func (tc *Manager) IsSuccessfulApply(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Strategy == ActuationStrategyApply &&
objStatus.Actuation == ActuationSucceeded
return objStatus.Strategy == actuation.ActuationStrategyApply &&
objStatus.Actuation == actuation.ActuationSucceeded
}
// AddSuccessfulApply updates the context with information about the
// resource identified by the provided id. Currently, we keep information
// about the generation of the resource after the apply operation completed.
func (tc *Manager) AddSuccessfulApply(id object.ObjMetadata, uid types.UID, gen int64) {
tc.SetObjectStatus(id, ObjectStatus{
tc.SetObjectStatus(id, actuation.ObjectStatus{
ObjectReference: ObjectReferenceFromObjMetadata(id),
Strategy: ActuationStrategyApply,
Actuation: ActuationSucceeded,
Reconcile: ReconcilePending,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcilePending,
UID: uid,
Generation: gen,
})
@ -101,16 +102,16 @@ func (tc *Manager) AddSuccessfulApply(id object.ObjMetadata, uid types.UID, gen
// SuccessfulApplies returns all the objects (as ObjMetadata) that
// were added as applied resources to the Manager.
func (tc *Manager) SuccessfulApplies() object.ObjMetadataSet {
return tc.ObjectsWithActuationStatus(ActuationStrategyApply,
ActuationSucceeded)
return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyApply,
actuation.ActuationSucceeded)
}
// AppliedResourceUID looks up the UID of a successfully applied resource
func (tc *Manager) AppliedResourceUID(id object.ObjMetadata) (types.UID, bool) {
objStatus, found := tc.ObjectStatus(id)
return objStatus.UID, found &&
objStatus.Strategy == ActuationStrategyApply &&
objStatus.Actuation == ActuationSucceeded
objStatus.Strategy == actuation.ActuationStrategyApply &&
objStatus.Actuation == actuation.ActuationSucceeded
}
// AppliedResourceUIDs returns a set with the UIDs of all the
@ -118,8 +119,8 @@ func (tc *Manager) AppliedResourceUID(id object.ObjMetadata) (types.UID, bool) {
func (tc *Manager) AppliedResourceUIDs() sets.String {
uids := sets.NewString()
for _, objStatus := range tc.inventory.Status.Objects {
if objStatus.Strategy == ActuationStrategyApply &&
objStatus.Actuation == ActuationSucceeded {
if objStatus.Strategy == actuation.ActuationStrategyApply &&
objStatus.Actuation == actuation.ActuationSucceeded {
if objStatus.UID != "" {
uids.Insert(string(objStatus.UID))
}
@ -144,8 +145,8 @@ func (tc *Manager) IsSuccessfulDelete(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Strategy == ActuationStrategyDelete &&
objStatus.Actuation == ActuationSucceeded
return objStatus.Strategy == actuation.ActuationStrategyDelete &&
objStatus.Actuation == actuation.ActuationSucceeded
}
// AddSuccessfulDelete updates the context with information about the
@ -154,11 +155,11 @@ func (tc *Manager) IsSuccessfulDelete(id object.ObjMetadata) bool {
// object was scheduled to be deleted asynchronously, which might cause further
// updates by finalizers. The UID will change if the object is re-created.
func (tc *Manager) AddSuccessfulDelete(id object.ObjMetadata, uid types.UID) {
tc.SetObjectStatus(id, ObjectStatus{
tc.SetObjectStatus(id, actuation.ObjectStatus{
ObjectReference: ObjectReferenceFromObjMetadata(id),
Strategy: ActuationStrategyDelete,
Actuation: ActuationSucceeded,
Reconcile: ReconcilePending,
Strategy: actuation.ActuationStrategyDelete,
Actuation: actuation.ActuationSucceeded,
Reconcile: actuation.ReconcilePending,
UID: uid,
})
}
@ -166,8 +167,8 @@ func (tc *Manager) AddSuccessfulDelete(id object.ObjMetadata, uid types.UID) {
// SuccessfulDeletes returns all the objects (as ObjMetadata) that
// were successfully deleted.
func (tc *Manager) SuccessfulDeletes() object.ObjMetadataSet {
return tc.ObjectsWithActuationStatus(ActuationStrategyDelete,
ActuationSucceeded)
return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyDelete,
actuation.ActuationSucceeded)
}
// IsFailedApply returns true if the object failed to apply
@ -176,23 +177,23 @@ func (tc *Manager) IsFailedApply(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Strategy == ActuationStrategyApply &&
objStatus.Actuation == ActuationFailed
return objStatus.Strategy == actuation.ActuationStrategyApply &&
objStatus.Actuation == actuation.ActuationFailed
}
// AddFailedApply registers that the object failed to apply
func (tc *Manager) AddFailedApply(id object.ObjMetadata) {
tc.SetObjectStatus(id, ObjectStatus{
tc.SetObjectStatus(id, actuation.ObjectStatus{
ObjectReference: ObjectReferenceFromObjMetadata(id),
Strategy: ActuationStrategyApply,
Actuation: ActuationFailed,
Reconcile: ReconcilePending,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationFailed,
Reconcile: actuation.ReconcilePending,
})
}
// FailedApplies returns all the objects that failed to apply
func (tc *Manager) FailedApplies() object.ObjMetadataSet {
return tc.ObjectsWithActuationStatus(ActuationStrategyApply, ActuationFailed)
return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyApply, actuation.ActuationFailed)
}
// IsFailedDelete returns true if the object failed to delete
@ -201,23 +202,24 @@ func (tc *Manager) IsFailedDelete(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Strategy == ActuationStrategyDelete &&
objStatus.Actuation == ActuationFailed
return objStatus.Strategy == actuation.ActuationStrategyDelete &&
objStatus.Actuation == actuation.ActuationFailed
}
// AddFailedDelete registers that the object failed to delete
func (tc *Manager) AddFailedDelete(id object.ObjMetadata) {
tc.SetObjectStatus(id, ObjectStatus{
tc.SetObjectStatus(id, actuation.ObjectStatus{
ObjectReference: ObjectReferenceFromObjMetadata(id),
Strategy: ActuationStrategyDelete,
Actuation: ActuationFailed,
Reconcile: ReconcilePending,
Strategy: actuation.ActuationStrategyDelete,
Actuation: actuation.ActuationFailed,
Reconcile: actuation.ReconcilePending,
})
}
// FailedDeletes returns all the objects that failed to delete
func (tc *Manager) FailedDeletes() object.ObjMetadataSet {
return tc.ObjectsWithActuationStatus(ActuationStrategyDelete, ActuationFailed)
return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyDelete,
actuation.ActuationFailed)
}
// IsSkippedApply returns true if the object apply was skipped
@ -226,23 +228,23 @@ func (tc *Manager) IsSkippedApply(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Strategy == ActuationStrategyApply &&
objStatus.Actuation == ActuationSkipped
return objStatus.Strategy == actuation.ActuationStrategyApply &&
objStatus.Actuation == actuation.ActuationSkipped
}
// AddSkippedApply registers that the object apply was skipped
func (tc *Manager) AddSkippedApply(id object.ObjMetadata) {
tc.SetObjectStatus(id, ObjectStatus{
tc.SetObjectStatus(id, actuation.ObjectStatus{
ObjectReference: ObjectReferenceFromObjMetadata(id),
Strategy: ActuationStrategyApply,
Actuation: ActuationSkipped,
Reconcile: ReconcilePending,
Strategy: actuation.ActuationStrategyApply,
Actuation: actuation.ActuationSkipped,
Reconcile: actuation.ReconcilePending,
})
}
// SkippedApplies returns all the objects where apply was skipped
func (tc *Manager) SkippedApplies() object.ObjMetadataSet {
return tc.ObjectsWithActuationStatus(ActuationStrategyApply, ActuationSkipped)
return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyApply, actuation.ActuationSkipped)
}
// IsSkippedDelete returns true if the object delete was skipped
@ -251,23 +253,24 @@ func (tc *Manager) IsSkippedDelete(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Strategy == ActuationStrategyDelete &&
objStatus.Actuation == ActuationSkipped
return objStatus.Strategy == actuation.ActuationStrategyDelete &&
objStatus.Actuation == actuation.ActuationSkipped
}
// AddSkippedDelete registers that the object delete was skipped
func (tc *Manager) AddSkippedDelete(id object.ObjMetadata) {
tc.SetObjectStatus(id, ObjectStatus{
tc.SetObjectStatus(id, actuation.ObjectStatus{
ObjectReference: ObjectReferenceFromObjMetadata(id),
Strategy: ActuationStrategyDelete,
Actuation: ActuationSkipped,
Reconcile: ReconcilePending,
Strategy: actuation.ActuationStrategyDelete,
Actuation: actuation.ActuationSkipped,
Reconcile: actuation.ReconcilePending,
})
}
// SkippedDeletes returns all the objects where deletion was skipped
func (tc *Manager) SkippedDeletes() object.ObjMetadataSet {
return tc.ObjectsWithActuationStatus(ActuationStrategyDelete, ActuationSkipped)
return tc.ObjectsWithActuationStatus(actuation.ActuationStrategyDelete,
actuation.ActuationSkipped)
}
// IsSuccessfulReconcile returns true if the object is reconciled
@ -276,7 +279,7 @@ func (tc *Manager) IsSuccessfulReconcile(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Reconcile == ReconcileSucceeded
return objStatus.Reconcile == actuation.ReconcileSucceeded
}
// SetSuccessfulReconcile registers that the object is reconciled
@ -285,13 +288,13 @@ func (tc *Manager) SetSuccessfulReconcile(id object.ObjMetadata) error {
if !found {
return fmt.Errorf("object not in inventory: %q", id)
}
objStatus.Reconcile = ReconcileSucceeded
objStatus.Reconcile = actuation.ReconcileSucceeded
return nil
}
// SuccessfulReconciles returns all the reconciled objects
func (tc *Manager) SuccessfulReconciles() object.ObjMetadataSet {
return tc.ObjectsWithReconcileStatus(ReconcileSucceeded)
return tc.ObjectsWithReconcileStatus(actuation.ReconcileSucceeded)
}
// IsFailedReconcile returns true if the object failed to reconcile
@ -300,7 +303,7 @@ func (tc *Manager) IsFailedReconcile(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Reconcile == ReconcileFailed
return objStatus.Reconcile == actuation.ReconcileFailed
}
// SetFailedReconcile registers that the object failed to reconcile
@ -309,13 +312,13 @@ func (tc *Manager) SetFailedReconcile(id object.ObjMetadata) error {
if !found {
return fmt.Errorf("object not in inventory: %q", id)
}
objStatus.Reconcile = ReconcileFailed
objStatus.Reconcile = actuation.ReconcileFailed
return nil
}
// FailedReconciles returns all the objects that failed to reconcile
func (tc *Manager) FailedReconciles() object.ObjMetadataSet {
return tc.ObjectsWithReconcileStatus(ReconcileFailed)
return tc.ObjectsWithReconcileStatus(actuation.ReconcileFailed)
}
// IsSkippedReconcile returns true if the object reconcile was skipped
@ -324,7 +327,7 @@ func (tc *Manager) IsSkippedReconcile(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Reconcile == ReconcileSkipped
return objStatus.Reconcile == actuation.ReconcileSkipped
}
// SetSkippedReconcile registers that the object reconcile was skipped
@ -333,13 +336,13 @@ func (tc *Manager) SetSkippedReconcile(id object.ObjMetadata) error {
if !found {
return fmt.Errorf("object not in inventory: %q", id)
}
objStatus.Reconcile = ReconcileSkipped
objStatus.Reconcile = actuation.ReconcileSkipped
return nil
}
// SkippedReconciles returns all the objects where reconcile was skipped
func (tc *Manager) SkippedReconciles() object.ObjMetadataSet {
return tc.ObjectsWithReconcileStatus(ReconcileSkipped)
return tc.ObjectsWithReconcileStatus(actuation.ReconcileSkipped)
}
// IsTimeoutReconcile returns true if the object reconcile was skipped
@ -348,7 +351,7 @@ func (tc *Manager) IsTimeoutReconcile(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Reconcile == ReconcileTimeout
return objStatus.Reconcile == actuation.ReconcileTimeout
}
// SetTimeoutReconcile registers that the object reconcile was skipped
@ -357,13 +360,13 @@ func (tc *Manager) SetTimeoutReconcile(id object.ObjMetadata) error {
if !found {
return fmt.Errorf("object not in inventory: %q", id)
}
objStatus.Reconcile = ReconcileTimeout
objStatus.Reconcile = actuation.ReconcileTimeout
return nil
}
// TimeoutReconciles returns all the objects where reconcile was skipped
func (tc *Manager) TimeoutReconciles() object.ObjMetadataSet {
return tc.ObjectsWithReconcileStatus(ReconcileTimeout)
return tc.ObjectsWithReconcileStatus(actuation.ReconcileTimeout)
}
// IsPendingReconcile returns true if the object reconcile is pending
@ -372,7 +375,7 @@ func (tc *Manager) IsPendingReconcile(id object.ObjMetadata) bool {
if !found {
return false
}
return objStatus.Reconcile == ReconcilePending
return objStatus.Reconcile == actuation.ReconcilePending
}
// SetPendingReconcile registers that the object reconcile is pending
@ -381,11 +384,11 @@ func (tc *Manager) SetPendingReconcile(id object.ObjMetadata) error {
if !found {
return fmt.Errorf("object not in inventory: %q", id)
}
objStatus.Reconcile = ReconcilePending
objStatus.Reconcile = actuation.ReconcilePending
return nil
}
// PendingReconciles returns all the objects where reconcile is pending
func (tc *Manager) PendingReconciles() object.ObjMetadataSet {
return tc.ObjectsWithReconcileStatus(ReconcilePending)
return tc.ObjectsWithReconcileStatus(actuation.ReconcilePending)
}

View File

@ -5,11 +5,12 @@ package inventory
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/cli-utils/pkg/apis/actuation"
"sigs.k8s.io/cli-utils/pkg/object"
)
// ObjMetadataEqualObjectReference compares an ObjMetadata with a ObjectReference
func ObjMetadataEqualObjectReference(id object.ObjMetadata, ref ObjectReference) bool {
func ObjMetadataEqualObjectReference(id object.ObjMetadata, ref actuation.ObjectReference) bool {
return id.GroupKind.Group == ref.Group &&
id.GroupKind.Kind == ref.Kind &&
id.Namespace == ref.Namespace &&
@ -17,8 +18,8 @@ func ObjMetadataEqualObjectReference(id object.ObjMetadata, ref ObjectReference)
}
// ObjectReferenceFromObjMetadata converts an ObjMetadata to a ObjectReference
func ObjectReferenceFromObjMetadata(id object.ObjMetadata) ObjectReference {
return ObjectReference{
func ObjectReferenceFromObjMetadata(id object.ObjMetadata) actuation.ObjectReference {
return actuation.ObjectReference{
Group: id.GroupKind.Group,
Kind: id.GroupKind.Kind,
Name: id.Name,
@ -27,7 +28,7 @@ func ObjectReferenceFromObjMetadata(id object.ObjMetadata) ObjectReference {
}
// ObjMetadataFromObjectReference converts an ObjectReference to a ObjMetadata
func ObjMetadataFromObjectReference(ref ObjectReference) object.ObjMetadata {
func ObjMetadataFromObjectReference(ref actuation.ObjectReference) object.ObjMetadata {
return object.ObjMetadata{
GroupKind: schema.GroupKind{
Group: ref.Group,