-
Notifications
You must be signed in to change notification settings - Fork 545
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve and unpack operators from bundle images #1081
Conversation
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jpeeler The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks promising! Here's the feedback/questions I have so far:
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1" | ||
"github.com/operator-framework/operator-registry/pkg/registry" | ||
) | ||
|
||
// Generation represents a set of operators and their required/provided API surfaces at a point in time. | ||
type Generation interface { | ||
AddOperator(o OperatorSurface) error | ||
AddPendingOperator(l LaunchBundleImageInfo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other methods take an interface as input, which is a classic go idiom. Is there some way we can use OperatorSurface
without changing its API (e.g. tack new fields on OperatorSourceInfo
, for which there is already a getter)? If not, does it make sense to define a new interface?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will circle back to this.
b192cb9
to
1f749ec
Compare
1f749ec
to
c4d3879
Compare
c4d3879
to
6b025da
Compare
6b025da
to
7a35d3b
Compare
@@ -132,12 +137,14 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo | |||
client: crClient, | |||
lister: lister, | |||
namespace: operatorNamespace, | |||
resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient), | |||
resolver: resolver.NewOperatorsV1alpha1Resolver(lister, crClient, opClient.KubernetesInterface(), operatorNamespace), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used for launching the bundle image (LaunchBundleImage).
return nil, nil, nil, err | ||
} | ||
for _, ip := range ips { | ||
for _, lookup := range ip.Status.BundleLookups { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm missing why this is needed - can't you just return the whole set of pending operators as BundleLookups
that the installplan should unpack?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do have a TODO here to investigate improving. Without it install plans get duplicated due to the next loop doing a resolve (again) and repeating. The only way that I can see to avoid this is by checking all the install plans for the image.
for bundleImageInfo := range gen.PendingOperators() { | ||
// TODO: switch image to standalone image, but this image can be used upstream as well | ||
// change to use configmapRegistryImage | ||
//configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:latest", r.operatorNamespace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to clarify our discussion last night, you should use the actual variable "configmapRegistryImage" from pkg/catalogoperator.go NewOperator
, not quay.io/openshift/origin-operator-registry:latest
@@ -68,6 +69,29 @@ func (r *ResourceQueueSet) Requeue(namespace, name string) error { | |||
return fmt.Errorf("couldn't find queue for resource") | |||
} | |||
|
|||
// TODO: this may not actually be required if the requeue is done on the namespace rather than the installplan | |||
// RequeueAfter requeues the resource in the set with the given name and namespace (just like Requeue), but only does so after duration has passed | |||
func (r *ResourceQueueSet) RequeueAfter(namespace, name string, duration time.Duration) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we watch Jobs
and requeue owner installplans when we see them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it's a good idea and is something I was considering.
// change to use configmapRegistryImage | ||
//configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/openshift/origin-operator-registry:latest", r.operatorNamespace) | ||
|
||
configmap, job, err := configmap.LaunchBundleImage(r.kubeclient, bundleImageInfo.image, "quay.io/jpeeler/bundle-init-image:latest", r.operatorNamespace) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where do these get cleaned up?
(this is not necessarily blocking, we can follow up with GC)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could return the pending operators from the resolver without launching them?
then when we create the installplan, write the "bundlelookups" into it
then when we process the installplan, launch jobs for any bundlelookups that don't have corresponding jobs?
this would also mean that when we launch, we have an installplan, so we can add ownerrefs, so we can watch jobs and requeue based on ownerref 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you are correct that they aren't yet
7a35d3b
to
ff053aa
Compare
This isn't merge-able 😩 The e2e currently has exactly double steps, which seems like resources are getting added from the bundle (which in this case has a CSV) and the bundle image. Code generation has not been done, unit tests aren't updated. |
a0ce61c
to
98c5c60
Compare
98c5c60
to
c92e933
Compare
/hold This is a blocking PR that needs to be merged first (but could possibly change due to feedback received here): |
7ff60a6
to
0f9ef8d
Compare
0f9ef8d
to
f287292
Compare
e750321
to
bc0b9e0
Compare
bc0b9e0
to
8f29811
Compare
8f29811
to
530adf5
Compare
530adf5
to
69ece0d
Compare
Specifically, pulls in v1.5.5.
This extracts bundle data from an image and uses that data to populate the installplan. (The code here depends on later commits.)
WIP: this is currently using a local custom image.
Instead use image that is pullable from quay. Test data has been updated to include image building files.
The test data for generating this custom image uses a go script to generate and populate an operator registry database that references a bundle image.
69ece0d
to
9707998
Compare
/retest |
@jpeeler: The following tests failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
@@ -1033,6 +1044,96 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip | |||
return reference.GetReference(res) | |||
} | |||
|
|||
func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) { | |||
for _, bundleLookup := range plan.Status.BundleLookups { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Over the course of our work on OLM, we've developed an idiomatic way of reconciling resources:
- Build state from cluster
- Inform cluster action from state; or
- Update resource status from state
I think that we can run into trouble if we jump straight to 2. without first performing 1., or by coupling 2. and 3.
In this case, do you think we can:
- build the state before actioning on it; i.e. Check for
ConfigMaps
/Jobs
before creating them - update the
InstallPlan
object once per reconciliation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good plan - we just need a deterministic way to name the configmaps/jobs from the installplan. InstallPlanName + image name would make sense, or a hash of that info.
@@ -85,6 +87,7 @@ type Operator struct { | |||
catalogSubscriberIndexer map[string]cache.Indexer | |||
clientAttenuator *scoped.ClientAttenuator | |||
serviceAccountQuerier *scoped.UserDefinedServiceAccountQuerier | |||
bundleLoader *configmap.BundleLoader |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in an ideal world this would be an interface. It would be nice if we had other options than unpacking into a configmap in the future. But we can do that as a separate refactoring after this merges.
csvProvidedAPIsIndexer: map[string]cache.Indexer{}, | ||
catalogSubscriberIndexer: map[string]cache.Indexer{}, | ||
serviceAccountQuerier: scoped.NewUserDefinedServiceAccountQuerier(logger, crClient), | ||
clientAttenuator: scoped.NewClientAttenuator(logger, config, opClient, crClient), | ||
bundleLoader: configmap.NewBundleLoader(), | ||
configmapRegistryImage: configmapRegistryImage, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably want a separate variable for "bundleUnpackerImage". In OpenShift this will end up the same image (registry image) but they do different things and there's no reason they should have to be the same.
@@ -1033,6 +1044,96 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip | |||
return reference.GetReference(res) | |||
} | |||
|
|||
func (o *Operator) checkBundleLookups(plan *v1alpha1.InstallPlan) (bool, error) { | |||
for _, bundleLookup := range plan.Status.BundleLookups { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good plan - we just need a deterministic way to name the configmaps/jobs from the installplan. InstallPlanName + image name would make sense, or a hash of that info.
} | ||
|
||
// extract data from configmap and write to install plan | ||
bundle, err := o.bundleLoader.Load(configmap) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense but is not critical, IMO. Installing via installplan steps ensures we install via a well-tested path. But, this would be a great followup and will enable installplans to install larger sets of objects.
Superseded by #1215, which has now merged. |
@jpeeler: PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
No description provided.