Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/resourcemerge/cv.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func EnsureCVOConfig(modified *bool, existing *cvv1.CVOConfig, required cvv1.CVO
*modified = true
existing.Channel = required.Channel
}
if existing.ClusterID.String() != required.ClusterID.String() {
if existing.ClusterID != required.ClusterID {
*modified = true
existing.ClusterID = required.ClusterID
}
Expand Down
30 changes: 30 additions & 0 deletions pkg/apis/clusterversion.openshift.io/v1/cluster_id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package v1

import (
"encoding/json"
"fmt"

"github.com/google/uuid"
)

// UnmarshalJSON unmarshals RFC4122 uuid from string.
func (cid *ClusterID) UnmarshalJSON(b []byte) error {
var strid string
if err := json.Unmarshal(b, &strid); err != nil {
return err
}

uid, err := uuid.Parse(strid)
if err != nil {
return err
}
if uid.Variant() != uuid.RFC4122 {
return fmt.Errorf("invalid ClusterID %q, must be an RFC4122-variant UUID: found %s", strid, uid.Variant())
}
if uid.Version() != 4 {
return fmt.Errorf("Invalid ClusterID %q, must be a version-4 UUID: found %s", strid, uid.Version())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, why do we care about the UUID version?

@abhinavdahiya abhinavdahiya Oct 4, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cincinnati cares about it. And CVO needs to only use that specific version of uuid to successfully talk to cincinnati

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are banking on the fact that V4 UUIDs are random so that we can key on this when doing rate-limited updates.

}

*cid = ClusterID(uid.String())
return nil
}
25 changes: 23 additions & 2 deletions pkg/apis/clusterversion.openshift.io/v1/types.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package v1

import (
"github.com/google/uuid"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -24,9 +23,31 @@ type CVOConfig struct {

Upstream URL `json:"upstream"`
Channel string `json:"channel"`
ClusterID uuid.UUID `json:"clusterId"`
ClusterID ClusterID `json:"clusterID"`

DesiredUpdate Update `json:"desiredUpdate"`

// Overrides is list of overides for components that are managed by
// cluster version operator
Overrides []ComponentOverride `json:"overrides,omitempty"`
}

// ClusterID is string RFC4122 uuid.
type ClusterID string

// ComponentOverride allows overriding cluster version operator's behavior
// for a component.
type ComponentOverride struct {
// Kind should match the TypeMeta.Kind for object.
Kind string `json:"kind"`

// The Namespace and Name for the component.
Namespace string `json:"namespace"`
Name string `json:"name"`

// Unmanaged controls if cluster version operator should stop managing.
// Default: false
Unmanaged bool `json:"unmanaged"`
}

// URL is a thin wrapper around string that ensures the string is a valid URL.
Expand Down
29 changes: 16 additions & 13 deletions pkg/cvo/cvo.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,14 @@ type Operator struct {

syncHandler func(key string) error

cvoConfigLister cvlistersv1.CVOConfigLister
operatorStatusLister oslistersv1.OperatorStatusLister

crdLister apiextlistersv1beta1.CustomResourceDefinitionLister
deployLister appslisterv1.DeploymentLister
crdListerSynced cache.InformerSynced
deployListerSynced cache.InformerSynced
crdLister apiextlistersv1beta1.CustomResourceDefinitionLister
deployLister appslisterv1.DeploymentLister
cvoConfigLister cvlistersv1.CVOConfigLister
crdListerSynced cache.InformerSynced
deployListerSynced cache.InformerSynced
cvoConfigListerSynced cache.InformerSynced

// queue only ever has one item, but it has nice error handling backoff/retry semantics
queue workqueue.RateLimitingInterface
Expand Down Expand Up @@ -113,13 +114,14 @@ func New(

optr.syncHandler = optr.sync

optr.cvoConfigLister = cvoConfigInformer.Lister()
optr.operatorStatusLister = operatorStatusInformer.Lister()

optr.crdLister = crdInformer.Lister()
optr.crdListerSynced = crdInformer.Informer().HasSynced
optr.deployLister = deployInformer.Lister()
optr.deployListerSynced = deployInformer.Informer().HasSynced
optr.cvoConfigLister = cvoConfigInformer.Lister()
optr.cvoConfigListerSynced = cvoConfigInformer.Informer().HasSynced

return optr
}
Expand All @@ -135,6 +137,7 @@ func (optr *Operator) Run(workers int, stopCh <-chan struct{}) {
if !cache.WaitForCacheSync(stopCh,
optr.crdListerSynced,
optr.deployListerSynced,
optr.cvoConfigListerSynced,
) {
return
}
Expand Down Expand Up @@ -248,6 +251,12 @@ func (optr *Operator) getConfig() (*cvv1.CVOConfig, error) {
upstream := cvv1.URL("http://localhost:8080/graph")
channel := "fast"
id, _ := uuid.NewRandom()
if id.Variant() != uuid.RFC4122 {
return nil, fmt.Errorf("invalid %q, must be an RFC4122-variant UUID: found %s", id, id.Variant())
}
if id.Version() != 4 {
return nil, fmt.Errorf("Invalid %q, must be a version-4 UUID: found %s", id, id.Version())
}

// XXX: generate CVOConfig from options calculated above.
config := &cvv1.CVOConfig{
Expand All @@ -257,13 +266,7 @@ func (optr *Operator) getConfig() (*cvv1.CVOConfig, error) {
},
Upstream: upstream,
Channel: channel,
ClusterID: id,
}
if config.ClusterID.Variant() != uuid.RFC4122 {
return nil, fmt.Errorf("invalid ClusterID %q, must be an RFC4122-variant UUID: found %s", config.ClusterID, config.ClusterID.Variant())
}
if config.ClusterID.Version() != 4 {
return nil, fmt.Errorf("Invalid ClusterID %q, must be a version-4 UUID: found %s", config.ClusterID, config.ClusterID.Version())
ClusterID: cvv1.ClusterID(id.String()),
}

actual, _, err := resourceapply.ApplyCVOConfigFromCache(optr.cvoConfigLister, optr.client.ClusterversionV1(), config)
Expand Down
8 changes: 7 additions & 1 deletion pkg/cvo/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package cvo
import (
"fmt"

"github.com/google/uuid"

"github.com/openshift/cluster-version-operator/lib/resourceapply"
cvv1 "github.com/openshift/cluster-version-operator/pkg/apis/clusterversion.openshift.io/v1"
osv1 "github.com/openshift/cluster-version-operator/pkg/apis/operatorstatus.openshift.io/v1"
Expand Down Expand Up @@ -76,5 +78,9 @@ func (optr *Operator) syncDegradedStatus(ierr error) error {
}

func checkForUpdate(config cvv1.CVOConfig) ([]cincinnati.Update, error) {
return cincinnati.NewClient(config.ClusterID).GetUpdates(string(config.Upstream), config.Channel, version.Version)
uuid, err := uuid.Parse(string(config.ClusterID))
if err != nil {
return nil, err
}
return cincinnati.NewClient(uuid).GetUpdates(string(config.Upstream), config.Channel, version.Version)
}
20 changes: 20 additions & 0 deletions pkg/cvo/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"

"github.com/openshift/cluster-version-operator/lib"
"github.com/openshift/cluster-version-operator/lib/resourceapply"
"github.com/openshift/cluster-version-operator/lib/resourcebuilder"
"github.com/openshift/cluster-version-operator/pkg/apis"
Expand All @@ -23,6 +24,12 @@ func (optr *Operator) syncUpdatePayload(config *cvv1.CVOConfig, payload *updateP
glog.V(4).Infof("Running sync for %s", taskName)
glog.V(6).Infof("Manifest: %s", string(manifest.Raw))

ov, ok := getOverrideForManifest(config.Overrides, manifest)
if ok && ov.Unmanaged {
glog.V(4).Infof("Skipping %s as unmanaged", taskName)
continue
}

if err := wait.ExponentialBackoff(wait.Backoff{
Duration: time.Second * 10,
Factor: 1.3,
Expand Down Expand Up @@ -55,6 +62,19 @@ func (optr *Operator) syncUpdatePayload(config *cvv1.CVOConfig, payload *updateP
return nil
}

// getOverrideForManifest returns the override and true when override exists for manifest.
func getOverrideForManifest(overrides []cvv1.ComponentOverride, manifest lib.Manifest) (cvv1.ComponentOverride, bool) {
for idx, ov := range overrides {
kind, namespace, name := manifest.GVK.Kind, manifest.Object().GetNamespace(), manifest.Object().GetName()
if ov.Kind == kind &&
(namespace == "" || ov.Namespace == namespace) && // cluster-scoped objects don't have namespace.
ov.Name == name {
return overrides[idx], true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why overrides[idx] instead of ov?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't like using the value from range for anything other than reading....

}
}
return cvv1.ComponentOverride{}, false
}

func ownerRefModifier(config *cvv1.CVOConfig) resourcebuilder.MetaV1ObjectModifierFunc {
oref := metav1.NewControllerRef(config, ownerKind)
return func(obj metav1.Object) {
Expand Down