Skip to content

Commit

Permalink
AMEND ME - add subscription installplan conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
njhale committed Jun 24, 2019
1 parent 145b8fd commit 078d75c
Show file tree
Hide file tree
Showing 28 changed files with 4,641 additions and 394 deletions.
3 changes: 2 additions & 1 deletion cmd/catalog/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ func main() {

logger := log.New()
if *debug {
logger.SetLevel(log.DebugLevel)
// logger.SetLevel(log.DebugLevel)
logger.SetLevel(log.TraceLevel)
}
logger.Infof("log level %s", logger.Level)

Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ require (
github.com/google/btree v1.0.0 // indirect
github.com/google/go-cmp v0.2.0 // indirect
github.com/google/gofuzz v1.0.0 // indirect
github.com/googleapis/gnostic v0.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.8.5 // indirect
github.com/json-iterator/go v1.1.6 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/maxbrunsfeld/counterfeiter/v6 v6.0.2
github.com/mitchellh/hashstructure v1.0.0
github.com/onsi/ginkgo v1.8.0 // indirect
github.com/openshift/api v3.9.1-0.20190424152011-77b8897ec79a+incompatible
github.com/openshift/client-go v0.0.0-20190401163519-84c2b942258a
Expand Down Expand Up @@ -58,7 +60,7 @@ require (
k8s.io/klog v0.2.0 // indirect
k8s.io/kube-aggregator v0.0.0-20190404125450-f5e124c822d6
k8s.io/kube-openapi v0.0.0-20190401085232-94e1e7b7574c
k8s.io/kubernetes v1.14.2
k8s.io/kubernetes v1.14.3
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 // indirect
sigs.k8s.io/yaml v1.1.0 // indirect
)
Expand Down
10 changes: 7 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,15 @@ github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0=
github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190203031600-7a902570cb17 h1:prg2TTpTOcJF1jRWL2zSU1FQNgB0STAFNux8GK82y8k=
github.com/gregjones/httpcache v0.0.0-20190203031600-7a902570cb17/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:BWIsLfhgKhV5g/oF34aRjniBHLTZe5DNekSjbAjIS6c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
Expand Down Expand Up @@ -182,6 +184,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/maxbrunsfeld/counterfeiter v0.0.0-20181017030959-1aadac120687/go.mod h1:aoVsckWnsNzazwF2kmD+bzgdr4GBlbK91zsdivQJ2eU=
github.com/maxbrunsfeld/counterfeiter/v6 v6.0.2 h1:pbpJx2aGTIexkk+R+XLnCA9r2TBLg8KKyDo4GvaJan0=
github.com/maxbrunsfeld/counterfeiter/v6 v6.0.2/go.mod h1:jDaYg8/bmdfygnyq5gnvMRDocYTEcXLPU0bXPtTco58=
github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y=
github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
Expand Down Expand Up @@ -388,8 +392,8 @@ k8s.io/kube-openapi v0.0.0-20180711000925-0cf8f7e6ed1d h1:mn2F9UzCk6KGa7M/d2ibLy
k8s.io/kube-openapi v0.0.0-20180711000925-0cf8f7e6ed1d/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/kubernetes v1.11.7-beta.0.0.20181219023948-b875d52ea96d/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/kubernetes v1.11.8-beta.0.0.20190124204751-3a10094374f2/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/kubernetes v1.14.2 h1:Gdq2hPpttbaJBoClIanCE6WSu4IZReA54yhkZtvPUOo=
k8s.io/kubernetes v1.14.2/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/kubernetes v1.14.3 h1:/FQkOJpjc1jGA37s7Rt3U10VwIKW685ejrgOp4UDRFE=
k8s.io/kubernetes v1.14.3/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 h1:8r+l4bNWjRlsFYlQJnKJ2p7s1YQPj4XyXiJVqDHRx7c=
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
sigs.k8s.io/controller-runtime v0.1.10/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8=
Expand Down
10 changes: 10 additions & 0 deletions pkg/api/apis/operators/subscription_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,18 @@ const (

// UnhealthyCatalogSourceFound is a reason string for Subscriptions that transitioned because an unhealthy CatalogSource was found.
UnhealthyCatalogSourceFound = "UnhealthyCatalogSourceFound"

// InstallPlanMissing is a reason string for Subscriptions whose stated InstallPlan is not found.
InstallPlanMissing = "InstallPlanMissing"

// InstallPlanAwaitingApproval is a reason string for Subscriptions whose stated InstallPlan is awaiting approval.
InstallPlanAwaitingApproval = "InstallPlanAwaitingApproval"

// InstallPlanFailed is a reason string for Subscriptions whose stated InstallPlan has failed to be applied.
InstallPlanFailed = "InstallPlanFailed"
)

// SubscriptionCondition represents the latest available observations of a Subscription's state.
type SubscriptionCondition struct {
// Type is the type of Subscription condition.
Type SubscriptionConditionType
Expand Down
32 changes: 24 additions & 8 deletions pkg/api/apis/operators/v1alpha1/installplan_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,23 @@ type InstallPlanCondition struct {
// allow overwriting `now` function for deterministic tests
var now = metav1.Now

// SetCondition adds or updates a condition, using `Type` as merge key
func (s *InstallPlanStatus) SetCondition(cond InstallPlanCondition) InstallPlanCondition {
updated := now()
cond.LastUpdateTime = updated
cond.LastTransitionTime = updated
// GetCondition returns the InstallPlanCondition of the given type if it exists in the InstallPlanStatus' Conditions.
// Returns a condition of the given type with a ConditionStatus of "Unknown" if not found.
func (s InstallPlanStatus) GetCondition(conditionType InstallPlanConditionType) InstallPlanCondition {
for _, cond := range s.Conditions {
if cond.Type == conditionType {
return cond
}
}

return InstallPlanCondition{
Type: conditionType,
Status: corev1.ConditionUnknown,
}
}

// SetCondition adds or updates a condition, using `Type` as merge key.
func (s *InstallPlanStatus) SetCondition(cond InstallPlanCondition) InstallPlanCondition {
for i, existing := range s.Conditions {
if existing.Type != cond.Type {
continue
Expand All @@ -120,19 +131,24 @@ func (s *InstallPlanStatus) SetCondition(cond InstallPlanCondition) InstallPlanC
return cond
}

func ConditionFailed(cond InstallPlanConditionType, reason InstallPlanConditionReason, err error) InstallPlanCondition {

func ConditionFailed(cond InstallPlanConditionType, reason InstallPlanConditionReason, message string, now *metav1.Time) InstallPlanCondition {
return InstallPlanCondition{
Type: cond,
Status: corev1.ConditionFalse,
Reason: reason,
Message: err.Error(),
Message: message,
LastUpdateTime: *now,
LastTransitionTime: *now,
}
}

func ConditionMet(cond InstallPlanConditionType) InstallPlanCondition {
func ConditionMet(cond InstallPlanConditionType, now *metav1.Time) InstallPlanCondition {
return InstallPlanCondition{
Type: cond,
Status: corev1.ConditionTrue,
LastUpdateTime: *now,
LastTransitionTime: *now,
}
}

Expand Down
58 changes: 48 additions & 10 deletions pkg/api/apis/operators/v1alpha1/subscription_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,47 @@ type SubscriptionConditionType string
const (
// SubscriptionCatalogSourcesUnhealthy indicates that some or all of the CatalogSources to be used in resolution are unhealthy.
SubscriptionCatalogSourcesUnhealthy SubscriptionConditionType = "CatalogSourcesUnhealthy"

// SubscriptionInstallPlanMissing indicates that a Subscription's InstallPlan is missing.
SubscriptionInstallPlanMissing SubscriptionConditionType = "InstallPlanMissing"

// SubscriptionInstallPlanPending indicates that a Subscription's InstallPlan is pending installation.
SubscriptionInstallPlanPending SubscriptionConditionType = "InstallPlanPending"

// SubscriptionInstallPlanFailed indicates that the installation of a Subscription's InstallPlan has failed.
SubscriptionInstallPlanFailed SubscriptionConditionType = "InstallPlanFailed"
)

const (
// NoCatalogSourcesFound is a reason string for Subscriptions with unhealthy CatalogSources due to none being available.
NoCatalogSourcesFound = "NoCatalogSourcesFound"

// AllCatalogSourcesHealthy is a reason string for Subscriptions whose CatalogSources are all healthy.
// AllCatalogSourcesHealthy is a reason string for Subscriptions that transitioned due to all CatalogSources being healthy.
AllCatalogSourcesHealthy = "AllCatalogSourcesHealthy"

// CatalogSourcesAdded is a reason string for Subscriptions that transitioned due to CatalogSources being added.
CatalogSourcesAdded = "CatalogSourcesAdded"

// CatalogSourcesUpdated is a reason string for Subscriptions that transitioned due to CatalogSource being updated..
// CatalogSourcesUpdated is a reason string for Subscriptions that transitioned due to CatalogSource being updated.
CatalogSourcesUpdated = "CatalogSourcesUpdated"

// CatalogSourcesDeleted is a reason string for Subscriptions that transitioned due to CatalogSources being removed.
CatalogSourcesDeleted = "CatalogSourcesDeleted"

// UnhealthyCatalogSourceFound is a reason string for Subscriptions that transitioned because an unhealthy CatalogSource was found.
UnhealthyCatalogSourceFound = "UnhealthyCatalogSourceFound"

// ReferencedInstallPlanNotFound is a reason string for Subscriptions that transitioned due to a referenced InstallPlan not being found.
ReferencedInstallPlanNotFound = "ReferencedInstallPlanNotFound"

// InstallPlanNotYetReconciled is a reason string for Subscriptions that transitioned due to a referenced InstallPlan not being reconciled yet.
InstallPlanNotYetReconciled = "InstallPlanNotYetReconciled"

// InstallPlanFailed is a reason string for Subscriptions that transitioned due to a referenced InstallPlan failing without setting an explicit failure condition.
InstallPlanFailed = "InstallPlanFailed"
)

// SubscriptionCondition represents the latest available observations of a Subscription's state.
type SubscriptionCondition struct {
// Type is the type of Subscription condition.
Type SubscriptionConditionType `json:"type" description:"type of Subscription condition"`
Expand All @@ -87,7 +106,7 @@ type SubscriptionCondition struct {

// LastTransitionTime is the last time the condition transit from one status to another
// +optional
LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another"`
LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty" description:"last time the condition transit from one status to another" hash:"ignore"`
}

// Equals returns true if a SubscriptionCondition equals the one given, false otherwise.
Expand Down Expand Up @@ -129,16 +148,16 @@ type SubscriptionStatus struct {

// Conditions is a list of the latest available observations about a Subscription's current state.
// +optional
Conditions []SubscriptionCondition `json:"conditions,omitempty"`
Conditions []SubscriptionCondition `json:"conditions,omitempty" hash:"set"`

// LastUpdated represents the last time that the Subscription status was updated.
LastUpdated metav1.Time `json:"lastUpdated"`
}

// GetCondition returns the SubscriptionCondition of the given type if it exists in the SubscriptionStatus' Conditions.
// Returns a condition of the given type with a ConditionStatus of "Unknown" if not found.
func (status SubscriptionStatus) GetCondition(conditionType SubscriptionConditionType) SubscriptionCondition {
for _, cond := range status.Conditions {
func (s SubscriptionStatus) GetCondition(conditionType SubscriptionConditionType) SubscriptionCondition {
for _, cond := range s.Conditions {
if cond.Type == conditionType {
return cond
}
Expand All @@ -151,15 +170,34 @@ func (status SubscriptionStatus) GetCondition(conditionType SubscriptionConditio
}

// SetCondition sets the given SubscriptionCondition in the SubscriptionStatus' Conditions.
func (status *SubscriptionStatus) SetCondition(condition SubscriptionCondition) {
for i, cond := range status.Conditions {
func (s *SubscriptionStatus) SetCondition(condition SubscriptionCondition) {
for i, cond := range s.Conditions {
if cond.Type == condition.Type {
status.Conditions[i] = condition
s.Conditions[i] = condition
return
}
}

status.Conditions = append(status.Conditions, condition)
s.Conditions = append(s.Conditions, condition)
}

// RemoveConditions removes any conditions of the given types from the SubscriptionStatus' Conditions.
func (s *SubscriptionStatus) RemoveConditions(remove ...SubscriptionConditionType) {
exclusions := map[SubscriptionConditionType]struct{}{}
for _, r := range remove {
exclusions[r] = struct{}{}
}

var filtered []SubscriptionCondition
for _, cond := range s.Conditions {
if _, ok := exclusions[cond.Type]; ok {
// Skip excluded condition types
continue
}
filtered = append(filtered, cond)
}

s.Conditions = filtered
}

type InstallPlanReference struct {
Expand Down
9 changes: 5 additions & 4 deletions pkg/controller/operators/catalog/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
subscription.WithOperatorLister(op.lister),
subscription.WithSubscriptionInformer(subInformer.Informer()),
subscription.WithCatalogInformer(catsrcInformer.Informer()),
subscription.WithInstallPlanInformer(ipInformer.Informer()),
subscription.WithSubscriptionQueue(subQueue),
subscription.WithAppendedReconcilers(subscription.ReconcilerFromLegacySyncHandler(op.syncSubscriptions, nil)),
subscription.WithRegistryReconcilerFactory(op.reconciler),
Expand Down Expand Up @@ -919,7 +920,7 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) {
return
}

outInstallPlan, syncError := transitionInstallPlanState(logger.Logger, o, *plan)
outInstallPlan, syncError := transitionInstallPlanState(logger.Logger, o, *plan, o.now())

if syncError != nil {
logger = logger.WithField("syncError", syncError)
Expand Down Expand Up @@ -964,7 +965,7 @@ type installPlanTransitioner interface {

var _ installPlanTransitioner = &Operator{}

func transitionInstallPlanState(log *logrus.Logger, transitioner installPlanTransitioner, in v1alpha1.InstallPlan) (*v1alpha1.InstallPlan, error) {
func transitionInstallPlanState(log *logrus.Logger, transitioner installPlanTransitioner, in v1alpha1.InstallPlan, now metav1.Time) (*v1alpha1.InstallPlan, error) {
out := in.DeepCopy()

switch in.Status.Phase {
Expand All @@ -981,11 +982,11 @@ func transitionInstallPlanState(log *logrus.Logger, transitioner installPlanTran
log.Debug("attempting to install")
if err := transitioner.ExecutePlan(out); err != nil {
out.Status.SetCondition(v1alpha1.ConditionFailed(v1alpha1.InstallPlanInstalled,
v1alpha1.InstallPlanReasonComponentFailed, err))
v1alpha1.InstallPlanReasonComponentFailed, err.Error(), &now))
out.Status.Phase = v1alpha1.InstallPlanPhaseFailed
return out, err
}
out.Status.SetCondition(v1alpha1.ConditionMet(v1alpha1.InstallPlanInstalled))
out.Status.SetCondition(v1alpha1.ConditionMet(v1alpha1.InstallPlanInstalled, &now))
out.Status.Phase = v1alpha1.InstallPlanPhaseComplete
return out, nil
default:
Expand Down
4 changes: 3 additions & 1 deletion pkg/controller/operators/catalog/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ func (m *mockTransitioner) ExecutePlan(plan *v1alpha1.InstallPlan) error {
func TestTransitionInstallPlan(t *testing.T) {
errMsg := "transition test error"
err := errors.New(errMsg)
clockFake := utilclock.NewFakeClock(time.Date(2018, time.January, 26, 20, 40, 0, 0, time.UTC))
now := metav1.NewTime(clockFake.Now())

installed := &v1alpha1.InstallPlanCondition{
Type: v1alpha1.InstallPlanInstalled,
Expand Down Expand Up @@ -103,7 +105,7 @@ func TestTransitionInstallPlan(t *testing.T) {
transitioner := &mockTransitioner{tt.transError}

// Attempt to transition phases.
out, _ := transitionInstallPlanState(logrus.New(), transitioner, *plan)
out, _ := transitionInstallPlanState(logrus.New(), transitioner, *plan, now)

// Assert that the final phase is as expected.
require.Equal(t, tt.expected, out.Status.Phase)
Expand Down
12 changes: 11 additions & 1 deletion pkg/controller/operators/catalog/subscription/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type syncerConfig struct {
lister operatorlister.OperatorLister
subscriptionInformer cache.SharedIndexInformer
catalogInformer cache.SharedIndexInformer
installPlanInformer cache.SharedIndexInformer
subscriptionQueue workqueue.RateLimitingInterface
reconcilers kubestate.ReconcilerChain
registryReconcilerFactory reconciler.RegistryReconcilerFactory
Expand Down Expand Up @@ -72,13 +73,20 @@ func WithSubscriptionInformer(subscriptionInformer cache.SharedIndexInformer) Sy
}
}

// WithCatalogInformer sets the informer a syncer will wire dependent subscription notifications to.
// WithCatalogInformer sets a CatalogSource informer to act as an event source for dependent Subscriptions.
func WithCatalogInformer(catalogInformer cache.SharedIndexInformer) SyncerOption {
return func(config *syncerConfig) {
config.catalogInformer = catalogInformer
}
}

// WithInstallPlanInformer sets an InstallPlan informer to act as an event source for dependent Subscriptions.
func WithInstallPlanInformer(installPlanInformer cache.SharedIndexInformer) SyncerOption {
return func(config *syncerConfig) {
config.installPlanInformer = installPlanInformer
}
}

// WithOperatorLister sets a syncer's operator lister.
func WithOperatorLister(lister operatorlister.OperatorLister) SyncerOption {
return func(config *syncerConfig) {
Expand Down Expand Up @@ -138,6 +146,8 @@ func (s *syncerConfig) validate() (err error) {
err = newInvalidConfigError("nil subscription informer")
case s.catalogInformer == nil:
err = newInvalidConfigError("nil catalog informer")
case s.installPlanInformer == nil:
err = newInvalidConfigError("nil installplan informer")
case s.subscriptionQueue == nil:
err = newInvalidConfigError("nil subscription queue")
case len(s.reconcilers) == 0:
Expand Down
Loading

0 comments on commit 078d75c

Please sign in to comment.