Skip to content

Commit

Permalink
Observe both image tag and image registry versions during operator in…
Browse files Browse the repository at this point in the history
…stall

Signed-off-by: David Vossel <[email protected]>
  • Loading branch information
davidvossel committed Mar 8, 2019
1 parent 911e693 commit 21060d4
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 70 deletions.
12 changes: 12 additions & 0 deletions pkg/api/v1/openapi_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 14 additions & 7 deletions pkg/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,13 @@ const (
// This label will be set on all resources created by the operator
ManagedByLabel = "app.kubernetes.io/managed-by"
ManagedByLabelOperatorValue = "kubevirt-operator"
// This label represents the kubevirt version for an install strategy configmap.
InstallStrategyVersionLabel = "kubevirt.io/install-strategy-version"
// This annotation represents the kubevirt version for an install strategy configmap.
InstallStrategyVersionAnnotation = "kubevirt.io/install-strategy-version"
// This annotation represents the kubevirt registry used for an install strategy configmap.
InstallStrategyRegistryAnnotation = "kubevirt.io/install-strategy-registry"

// This label indicates the object is a part of the install strategy retrieval process.
InstallStrategyLabel = "kubevirt.io/install-strategy"

VirtualMachineInstanceFinalizer string = "foregroundDeleteVirtualMachine"
CPUManager string = "cpumanager"
Expand Down Expand Up @@ -1065,11 +1070,13 @@ type KubeVirtSpec struct {
// ---
// +k8s:openapi-gen=true
type KubeVirtStatus struct {
Phase KubeVirtPhase `json:"phase,omitempty"`
Conditions []KubeVirtCondition `json:"conditions,omitempty" optional:"true"`
OperatorVersion string `json:"operatorVersion,omitempty" optional:"true"`
TargetKubeVirtVersion string `json:"targetKubeVirtVersion,omitempty" optional:"true"`
ObservedKubeVirtVersion string `json:"observedKubeVirtVersion,omitempty" optional:"true"`
Phase KubeVirtPhase `json:"phase,omitempty"`
Conditions []KubeVirtCondition `json:"conditions,omitempty" optional:"true"`
OperatorVersion string `json:"operatorVersion,omitempty" optional:"true"`
TargetKubeVirtVersion string `json:"targetKubeVirtVersion,omitempty" optional:"true"`
TargetKubeVirtRegistry string `json:"targetKubeVirtRegistry,omitempty" optional:"true"`
ObservedKubeVirtVersion string `json:"observedKubeVirtVersion,omitempty" optional:"true"`
ObservedKubeVirtRegistry string `json:"observedKubeVirtRegistry,omitempty" optional:"true"`
}

// KubeVirtPhase is a label for the phase of a KubeVirt deployment at the current time.
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/virtinformers.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ func (f *kubeInformerFactory) DummyOperatorSCC() cache.SharedIndexInformer {

func (f *kubeInformerFactory) OperatorInstallStrategyConfigMaps() cache.SharedIndexInformer {
return f.getInformer("installStrategyConfigMapInformer", func() cache.SharedIndexInformer {
labelSelector, err := labels.Parse(kubev1.InstallStrategyVersionLabel)
labelSelector, err := labels.Parse(kubev1.InstallStrategyLabel)
if err != nil {
panic(err)
}
Expand All @@ -441,7 +441,7 @@ func (f *kubeInformerFactory) OperatorInstallStrategyConfigMaps() cache.SharedIn

func (f *kubeInformerFactory) OperatorInstallStrategyJob() cache.SharedIndexInformer {
return f.getInformer("installStrategyJobsInformer", func() cache.SharedIndexInformer {
labelSelector, err := labels.Parse(kubev1.InstallStrategyVersionLabel)
labelSelector, err := labels.Parse(kubev1.InstallStrategyLabel)
if err != nil {
panic(err)
}
Expand Down
57 changes: 39 additions & 18 deletions pkg/virt-operator/install-strategy/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,6 @@ type InstallStrategy struct {
customSccPrivileges []*customSccPrivilegedAccounts
}

func generateConfigMapName(imageTag string) string {
return fmt.Sprintf("kubevirt-install-strategy-%s", imageTag)
}

func NewInstallStrategyConfigMap(namespace string, imageTag string, imageRegistry string) (*corev1.ConfigMap, error) {

strategy, err := GenerateCurrentInstallStrategy(
Expand All @@ -97,11 +93,15 @@ func NewInstallStrategyConfigMap(namespace string, imageTag string, imageRegistr

configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: generateConfigMapName(imageTag),
Namespace: namespace,
GenerateName: "kubevirt-install-strategy-",
Namespace: namespace,
Labels: map[string]string{
v1.ManagedByLabel: v1.ManagedByLabelOperatorValue,
v1.InstallStrategyVersionLabel: imageTag,
v1.ManagedByLabel: v1.ManagedByLabelOperatorValue,
v1.InstallStrategyLabel: "",
},
Annotations: map[string]string{
v1.InstallStrategyVersionAnnotation: imageTag,
v1.InstallStrategyRegistryAnnotation: imageRegistry,
},
},
Data: map[string]string{
Expand Down Expand Up @@ -267,21 +267,42 @@ func GenerateCurrentInstallStrategy(namespace string,
return strategy, nil
}

func LoadInstallStrategyFromCache(stores util.Stores, namespace string, imageTag string) (*InstallStrategy, error) {
func LoadInstallStrategyFromCache(stores util.Stores, namespace string, imageTag string, imageRegistry string) (*InstallStrategy, error) {
var configMap *corev1.ConfigMap
var matchingConfigMaps []*corev1.ConfigMap

configMap := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: generateConfigMapName(imageTag),
Namespace: namespace,
},
for _, obj := range stores.InstallStrategyConfigMapCache.List() {
config, ok := obj.(*corev1.ConfigMap)
if !ok {
continue
}
if config.ObjectMeta.Annotations == nil {
continue
}

version, _ := config.ObjectMeta.Annotations[v1.InstallStrategyVersionAnnotation]
registry, _ := config.ObjectMeta.Annotations[v1.InstallStrategyRegistryAnnotation]
if version == imageTag && registry == imageRegistry {
matchingConfigMaps = append(matchingConfigMaps, config)
}
}

if len(matchingConfigMaps) == 0 {
return nil, fmt.Errorf("no install strategy configmap found for version %s with registry %s", imageTag, imageRegistry)
}
obj, exists, _ := stores.InstallStrategyConfigMapCache.Get(configMap)

if !exists {
return nil, fmt.Errorf("no install strategy configmap found for version %s", imageTag)
// choose the most recent configmap if multiple match.
mostRecentTime := metav1.Time{}
for _, config := range matchingConfigMaps {
if configMap == nil {
configMap = config
mostRecentTime = config.ObjectMeta.CreationTimestamp
} else if mostRecentTime.Before(&config.ObjectMeta.CreationTimestamp) {
configMap = config
mostRecentTime = config.ObjectMeta.CreationTimestamp
}
}

configMap = obj.(*corev1.ConfigMap)
data, ok := configMap.Data["manifests"]
if !ok {
return nil, fmt.Errorf("install strategy configmap %s does not contain 'manifests' key", configMap.Name)
Expand Down
32 changes: 22 additions & 10 deletions pkg/virt-operator/kubevirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,13 @@ func (c *KubeVirtController) generateInstallStrategyJob(kv *v1.KubeVirt) *batchv
Namespace: kv.Namespace,
Name: fmt.Sprintf("virt-install-strategy-job-%s", imageTag),
Labels: map[string]string{
v1.AppLabel: "",
v1.ManagedByLabel: v1.ManagedByLabelOperatorValue,
v1.InstallStrategyVersionLabel: imageTag,
v1.AppLabel: "",
v1.ManagedByLabel: v1.ManagedByLabelOperatorValue,
v1.InstallStrategyLabel: "",
},
Annotations: map[string]string{
v1.InstallStrategyVersionAnnotation: imageTag,
v1.InstallStrategyRegistryAnnotation: imageRegistry,
},
},
Spec: batchv1.JobSpec{
Expand Down Expand Up @@ -535,14 +539,22 @@ func (c *KubeVirtController) garbageCollectInstallStrategyJobs() error {
return nil
}

func (c *KubeVirtController) getInstallStrategyFromMap(version string) (*installstrategy.InstallStrategy, bool) {
func (c *KubeVirtController) getInstallStrategyFromMap(version string, registry string) (*installstrategy.InstallStrategy, bool) {
c.installStrategyMutex.Lock()
defer c.installStrategyMutex.Unlock()

strategy, ok := c.installStrategyMap[version]
strategy, ok := c.installStrategyMap[fmt.Sprintf("%s/%s", registry, version)]
return strategy, ok
}

func (c *KubeVirtController) cacheInstallStrategyInMap(strategy *installstrategy.InstallStrategy, version string, registry string) {

c.installStrategyMutex.Lock()
defer c.installStrategyMutex.Unlock()
c.installStrategyMap[fmt.Sprintf("%s/%s", registry, version)] = strategy

}

func (c *KubeVirtController) deleteAllInstallStrategy() error {
for _, obj := range c.stores.InstallStrategyConfigMapCache.List() {

Expand Down Expand Up @@ -586,18 +598,16 @@ func (c *KubeVirtController) loadInstallStrategy(kv *v1.KubeVirt) (*installstrat
}

// 1. see if we already loaded the install strategy
strategy, ok := c.getInstallStrategyFromMap(c.getImageTag(kv))
strategy, ok := c.getInstallStrategyFromMap(c.getImageTag(kv), c.getImageRegistry(kv))
if ok {
// we already loaded this strategy into memory
return strategy, false, nil
}

// 2. look for install strategy config map in cache.
strategy, err = installstrategy.LoadInstallStrategyFromCache(c.stores, kv.Namespace, c.getImageTag(kv))
strategy, err = installstrategy.LoadInstallStrategyFromCache(c.stores, kv.Namespace, c.getImageTag(kv), c.getImageRegistry(kv))
if err == nil {
c.installStrategyMutex.Lock()
defer c.installStrategyMutex.Unlock()
c.installStrategyMap[c.getImageTag(kv)] = strategy
c.cacheInstallStrategyInMap(strategy, c.getImageTag(kv), c.getImageRegistry(kv))
log.Log.Infof("Loaded install strategy for kubevirt version %s into cache", c.getImageTag(kv))
return strategy, false, nil
}
Expand Down Expand Up @@ -684,6 +694,7 @@ func (c *KubeVirtController) syncDeployment(kv *v1.KubeVirt) error {
util.SetOperatorVersion(kv)
// record the version we're targetting to install
kv.Status.TargetKubeVirtVersion = c.getImageTag(kv)
kv.Status.TargetKubeVirtRegistry = c.getImageRegistry(kv)

// Set phase to deploying
kv.Status.Phase = v1.KubeVirtPhaseDeploying
Expand Down Expand Up @@ -737,6 +748,7 @@ func (c *KubeVirtController) syncDeployment(kv *v1.KubeVirt) error {

// record the version just installed
kv.Status.ObservedKubeVirtVersion = c.getImageTag(kv)
kv.Status.ObservedKubeVirtRegistry = c.getImageRegistry(kv)

// add Created condition
util.UpdateCondition(kv, v1.KubeVirtConditionCreated, k8sv1.ConditionTrue, ConditionReasonDeploymentCreated, "All resources were created.")
Expand Down
47 changes: 14 additions & 33 deletions pkg/virt-operator/kubevirt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,8 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
extv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
extclientfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/testing"
"k8s.io/client-go/tools/cache"
Expand Down Expand Up @@ -353,8 +351,8 @@ var _ = Describe("KubeVirt Operator", func() {
}

addAll := func() {
repository := "somerepository"
version := "v9.9.9"
repository := defaultRegistry
version := defaultImageTag
pullPolicy := "IfNotPresent"
imagePullPolicy := k8sv1.PullPolicy(pullPolicy)
verbosity := "2"
Expand Down Expand Up @@ -779,9 +777,11 @@ var _ = Describe("KubeVirt Operator", func() {
Message: "All components are ready.",
},
},
OperatorVersion: version.Get().String(),
TargetKubeVirtVersion: "v9.9.9",
ObservedKubeVirtVersion: "v9.9.9",
OperatorVersion: version.Get().String(),
TargetKubeVirtVersion: defaultImageTag,
TargetKubeVirtRegistry: defaultRegistry,
ObservedKubeVirtVersion: defaultImageTag,
ObservedKubeVirtRegistry: defaultRegistry,
},
}

Expand Down Expand Up @@ -1052,43 +1052,24 @@ var _ = Describe("KubeVirt Operator", func() {
Expect(ok).To(BeTrue())

configMap := create.GetObject().(*k8sv1.ConfigMap)
Expect(configMap.Name).To(Equal("kubevirt-install-strategy-v9.9.9"))
Expect(configMap.GenerateName).To(Equal("kubevirt-install-strategy-"))

_, ok = configMap.Data["manifests"]
version, ok := configMap.ObjectMeta.Annotations[v1.InstallStrategyVersionAnnotation]
Expect(ok).To(BeTrue())

return true, create.GetObject(), nil
})

// This generates and posts the install strategy config map
installstrategy.DumpInstallStrategyToConfigMap(virtClient)
}, 15)

It("should update an existing install strategy config map", func(done Done) {
defer close(done)

kubeClient.Fake.PrependReactor("create", "configmaps", func(action testing.Action) (handled bool, obj runtime.Object, err error) {
create, ok := action.(testing.CreateAction)
Expect(ok).To(BeTrue())
Expect(version).To(Equal(defaultImageTag))

configMap := create.GetObject().(*k8sv1.ConfigMap)
Expect(configMap.Name).To(Equal("kubevirt-install-strategy-v9.9.9"))
return true, nil, errors.NewAlreadyExists(schema.GroupResource{}, configMap.Name)
})
kubeClient.Fake.PrependReactor("update", "configmaps", func(action testing.Action) (handled bool, obj runtime.Object, err error) {
update, ok := action.(testing.UpdateAction)
registry, ok := configMap.ObjectMeta.Annotations[v1.InstallStrategyRegistryAnnotation]
Expect(registry).To(Equal(defaultRegistry))
Expect(ok).To(BeTrue())

configMap := update.GetObject().(*k8sv1.ConfigMap)
Expect(configMap.Name).To(Equal("kubevirt-install-strategy-v9.9.9"))

_, ok = configMap.Data["manifests"]
Expect(ok).To(BeTrue())

return true, update.GetObject(), nil
return true, create.GetObject(), nil
})

// This should update an already existing install strategy
// This generates and posts the install strategy config map
installstrategy.DumpInstallStrategyToConfigMap(virtClient)
}, 15)
})
Expand Down

0 comments on commit 21060d4

Please sign in to comment.