-
Notifications
You must be signed in to change notification settings - Fork 544
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
add OperatorGroup #480
add OperatorGroup #480
Conversation
a4e3db4
to
5be1916
Compare
var b strings.Builder | ||
nsCount := len(namespaceList.Items) | ||
for i := 0; i < nsCount-1; i++ { | ||
fmt.Fprintf(&b, "%v,", namespaceList.Items[i]) |
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 might require .Name here, but maybe there's a better way to do all this in general?
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.
If you don't need to use .Name (which I think we may need to), you can use strings.Join(namespaceList.Items, ",")
here as an alternative.
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 it makes sense for namespaces
in the status to just be a list of strings. Normally when we do object references we try and include GVK but namespaces are pretty ingrained (e.g. metadata.namespace
is just a string on every kube object).
If we make that change, then this part just becomes what @njhale suggested
controller-tools.k8s.io: "1.0" | ||
name: operatorgroups.operators.coreos.com.operators.coreos.com | ||
spec: | ||
group: operators.coreos.com.operators.coreos.com |
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 looks like a weird merge? should be operators.coreos.com
- metadata | ||
- spec | ||
version: v1alpha2 | ||
status: |
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.
don't commit the status (it will be ingored anyway, but no reason to have it)
|
||
type OperatorGroupSpec struct { | ||
Selector metav1.LabelSelector `json:"selector"` | ||
ServiceAccount corev1.ServiceAccount `json:"serviceAccount"` |
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 we want both of these to be omittempty
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 reason being that if the selector is not present, that all namespaces are selected by default? What account would be used in the absence of a specified service account?
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.
Yep, and in absence of a serviceaccount we'd use the one that OLM is running as (system:controller:operator-lifecycle-manager)
} | ||
|
||
type OperatorGroupStatus struct { | ||
Namespaces []corev1.Namespace `json:"namespaces"` |
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 "last updated time" here
var b strings.Builder | ||
nsCount := len(namespaceList.Items) | ||
for i := 0; i < nsCount-1; i++ { | ||
fmt.Fprintf(&b, "%v,", namespaceList.Items[i]) |
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 it makes sense for namespaces
in the status to just be a list of strings. Normally when we do object references we try and include GVK but namespaces are pretty ingrained (e.g. metadata.namespace
is just a string on every kube object).
If we make that change, then this part just becomes what @njhale suggested
f58875a
to
788d864
Compare
The failing images test will pass once #489 is merged. |
/test images |
nsCount := len(namespaceList.Items) | ||
|
||
if len(op.Status.Namespaces) == nsCount { | ||
for i, v := range namespaceList.Items { |
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 it would be better to implement this as a set (map[string]struct{}{}
) instead of a list; I'm not sure if we get order guarantees from List
|
||
for _, deploy := range strategyDetailsDeployment.DeploymentSpecs { | ||
deploy.Spec.Template.Annotations["olm.targetNamespaces"] = nsList.String() | ||
_, err := a.client.Operators().ClusterServiceVersions(currentNamespace).Update(csv) |
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'll have a better chance of this succeeding if we send a Patch
update.
if err != nil { | ||
return fmt.Errorf("CSV update for '%v' failed: %v\n", csvName, err) | ||
} | ||
a.requeueCSV(csvName, currentNamespace) |
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 will requeue the same csv multiple times if there're multiple deployments in the same csv
I'm also not sure we need to requeue - if this update causes the csv deployment to go unhealthy, we should detect that as an issue in the CSV anyway.
} | ||
DoUpdate: | ||
if needsUpdate { | ||
if err := a.updateDeploymentAnnotation(&op); err != nil { |
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 going to update for every single namespace that's new, I don't think we want it to be in the loop. that way you can just break the loop and don't need a label/goto
2c80629
to
1e96092
Compare
return err | ||
} | ||
operatorGroupOpts := metav1.ListOptions{LabelSelector: selector.String()} | ||
// TODO(jpeeler): this needs to use user impersonation with op.Spec.ServiceAccount |
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.
nit: remove this comment (I don't think we'll want to use impersonation here)
|
||
nsCount := len(namespaceList.Items) | ||
|
||
if len(op.Status.Namespaces) == nsCount { |
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 it would make sense to pull this out into a helper like namespacesChanged(clusterNamespaces, statusNamespaces) bool
op.Status.LastUpdated = timeNow() | ||
|
||
// make string list made up of comma separated namespaces | ||
var nsList strings.Builder |
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 don't we pull out the list of namespaces as just a list of strings before we get here? then you can just strings.join()
here
and actually if you you make a new type like type NamespaceNameList []string
, you can implement the Stringer
interface and have it call strings.join
so that this reads more nicely
managerPolicyRules := []rbacv1.PolicyRule{} | ||
apiEditPolicyRules := []rbacv1.PolicyRule{} | ||
apiViewPolicyRules := []rbacv1.PolicyRule{} | ||
for _, owned := range csv.Spec.CustomResourceDefinitions.Owned { |
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 also want to range over csv.Spec.ApiServiceDefinitions
which hold descriptions of APIs provided by aggregated apiservers.
return fmt.Errorf("could not assert strategy implementation as deployment for CSV %s", csvName) | ||
} | ||
|
||
managerPolicyRules := []rbacv1.PolicyRule{} |
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 rbac generation is broadly doing the right thing, but the installplan takes care of some of this already:
- for any CRD it installs, it creates a
<that-crd>-edit
ClusterRole<that-crd>-view
ClusterRole
All that's really left for this control loop to do is make sure there's an <operatorgroup>-edit
and an <operatorgroup>-view
ClusterRole available (which I see that you have!)
So I think most of this will remain the same, you just don't need to worry about the specific edit/view clusterroles
if err != nil { | ||
return err | ||
} | ||
for _, sa := range strategyDetailsDeployment.Permissions { |
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.
These generated roles aren't for the serviceaccount for the operator to use, they're for end users and administrators.
It's so that a cluster admin can bind jpeeler
to etcd-edit
in namespace foo
to give access to operator-provided services.
(we will need a separate thing to ensure that the serviceaccount for the operator has the correct permissions in target namespaces)
5d3c426
to
abc9379
Compare
Reason: v1alpha1.CSVReasonCopied, | ||
LastUpdateTime: timeNow(), | ||
} | ||
newCSV.Annotations["OriginalCSV"] = fmt.Sprintf("Namespace:%v, ResourceVersion:%v", csv.GetNamespace(), csv.GetResourceVersion()) |
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 make this more machine readable <namespace>/<csvname>
?
also we should follow the annotation key convention we used before, I think it would be olm.originalCSV
?
09ef2c4
to
bb9d5fa
Compare
@ecordell I'm working on rebasing next, but I just pushed the simple e2e and associated fixes. |
084c6f0
to
ec652c6
Compare
csvs in target namespaces should be annotated
also gets rid of stale code
f5c3a60
to
5b7d140
Compare
/retest |
/retest |
/retest Looks like CI operator is having a bad day:
|
client versioned.Interface | ||
resolver install.StrategyResolverInterface | ||
lister operatorlister.OperatorLister | ||
csvLister map[string]csvlister.ClusterServiceVersionLister |
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.
After some fixes in PR-536 get in, we can update this to extend operatorlister.OperatorLister
.
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 great overall! A few minor things:
@@ -21,6 +24,7 @@ import ( | |||
"k8s.io/api/apps/v1" | |||
corev1 "k8s.io/api/core/v1" |
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.
nit: import ordering
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 you elaborate? I just always let goimports do its thing.
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 doesn't look split up correctly. It should be:
import(
standard packages
external stuff
internal stuff
)
From what I can see, it looks like:
import (
standard packages
internal stuff
external stuff
)
} | ||
} | ||
if k8serrors.IsAlreadyExists(err) { | ||
fetchedCSV, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(ns.Name).Get(csv.GetName(), metav1.GetOptions{}) |
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.
If you check for a pre-existing CSV before attempting to create or update, you can make use of the lister to avoid making an extra API call.
Instead of creating operator groups in a "second phase", create the resources at the same time along with everything else. This removes a small amount of namespace specific code from NewFakeOperator and makes things more consistent.
return error as the last argument
This is already handled in a more clear way in removeDanglingChildCSVs.
Essentially, optimize for the update case rather than create since creates only happen once.
spec: | ||
properties: | ||
selector: | ||
type: object |
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 should be explicit about accepting a label selector here, see: https://github.com/operator-framework/operator-lifecycle-manager/blob/master/deploy/chart/templates/0000_30_02-clusterserviceversion.crd.yaml#L153-L182
} | ||
|
||
type OperatorGroupStatus struct { | ||
Namespaces []*corev1.Namespace `json:"namespaces"` |
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'm still a little concerned that this could get too long. []string
seems slightly safer. Perhaps the real answer is to wait for CRDs to support arbitrary subresources and implement a /namespaces
subresource (so that we can paginate)
_, err := opClientFake.KubernetesInterface().CoreV1().Namespaces().Create(&v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}) | ||
if err != nil { | ||
return nil, err | ||
for _, ns := range namespaces { |
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.
not a big deal, but if you're passing the objects in like this you can just append the namespaces to k8sObjs
and they'll exist in the fake for testing. or you can remove the explicit namespaces
param and build the object list in the tests
/test e2e-aws-olm |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ecordell 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 |
/test e2e-aws-olm |
…roup add OperatorGroup
So far the reconcile loop only looks at the namespace selector and writes the results to the status and an annotation on each deployment.