Skip to content
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

Handle preexisting operator #192

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
38 changes: 38 additions & 0 deletions api/v1/configurationpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ package v1
import (
"errors"
"fmt"
"strings"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// A custom type is required since there is no way to have a kubebuilder marker
Expand Down Expand Up @@ -40,6 +42,14 @@ const (
Inform RemediationAction = "Inform"
)

func (ra RemediationAction) IsInform() bool {
return strings.EqualFold(string(ra), string(Inform))
}

func (ra RemediationAction) IsEnforce() bool {
return strings.EqualFold(string(ra), string(Enforce))
}

Comment on lines +45 to +52
Copy link
Member

Choose a reason for hiding this comment

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

Oooh, these are nice. 😄

// ComplianceState shows the state of enforcement
type ComplianceState string

Expand Down Expand Up @@ -277,6 +287,18 @@ const (
MustOnlyHave ComplianceType = "Mustonlyhave"
)

func (c ComplianceType) IsMustHave() bool {
return strings.EqualFold(string(c), string(MustHave))
}

func (c ComplianceType) IsMustOnlyHave() bool {
return strings.EqualFold(string(c), string(MustOnlyHave))
}

func (c ComplianceType) IsMustNotHave() bool {
return strings.EqualFold(string(c), string(MustNotHave))
}

// MetadataComplianceType describes how to check compliance for the labels/annotations of a given object
// +kubebuilder:validation:Enum=MustHave;Musthave;musthave;MustOnlyHave;Mustonlyhave;mustonlyhave
type MetadataComplianceType string
Expand All @@ -303,6 +325,22 @@ type ObjectResource struct {
Metadata ObjectMetadata `json:"metadata,omitempty"`
}

func ObjectResourceFromObj(obj client.Object) ObjectResource {
name := obj.GetName()
if name == "" {
name = "*"
}

return ObjectResource{
Kind: obj.GetObjectKind().GroupVersionKind().Kind,
APIVersion: obj.GetObjectKind().GroupVersionKind().GroupVersion().String(),
Metadata: ObjectMetadata{
Name: name,
Namespace: obj.GetNamespace(),
},
}
}

// ObjectMetadata contains the resource metadata for an object being processed by the policy
type ObjectMetadata struct {
// Name of the referent. More info:
Expand Down
95 changes: 49 additions & 46 deletions api/v1beta1/operatorpolicy_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
package v1beta1

import (
operatorv1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"

policyv1 "open-cluster-management.io/config-policy-controller/api/v1"
)
Expand Down Expand Up @@ -36,39 +36,6 @@ const (
DeleteIfUnused RemovalAction = "DeleteIfUnused"
)

type TargetNsOrSelector struct {
// 'namespaces' and 'selector' both define an array/set of target namespaces that
// should be affected on the cluster. Only one of 'namespaces' or 'selector'
// should be specified, and if both are set then 'selector' will be omitted.
Namespace []string `json:"namespaces,omitempty"`
// 'namespaces' and 'selector' both define an array/set of target namespaces that
// should be affected on the cluster. Only one of 'namespaces' or 'selector'
// should be specified, and if both are set then 'selector' will be omitted.
Selector *metav1.LabelSelector `json:"selector,omitempty"`
}

// OperatorGroup specifies an OLM OperatorGroup. More info:
// https://olm.operatorframework.io/docs/concepts/crds/operatorgroup/
type OperatorGroup struct {
// Name of the referent
Name string `json:"name,omitempty"`
// Namespace of the referent
Namespace string `json:"namespace,omitempty"`
// Target namespaces of the referent
Target TargetNsOrSelector `json:"target,omitempty"`
// Name of the OLM ServiceAccount that defines permissions for member operators
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
}

// SubscriptionSpec extends an OLM subscription with a namespace field. More info:
// https://olm.operatorframework.io/docs/concepts/crds/subscription/
type SubscriptionSpec struct {
operatorv1.SubscriptionSpec `json:",inline"`
// Namespace of the referent
Namespace string `json:"namespace,omitempty"`
}

// RemovalBehavior defines resource behavior when policy is removed
type RemovalBehavior struct {
// Kind OperatorGroup
Expand Down Expand Up @@ -97,30 +64,66 @@ type StatusConfig struct {
type OperatorPolicySpec struct {
Severity policyv1.Severity `json:"severity,omitempty"` // low, medium, high
RemediationAction policyv1.RemediationAction `json:"remediationAction,omitempty"` // inform, enforce
ComplianceType policyv1.ComplianceType `json:"complianceType"` // Compliant, NonCompliant
// OperatorGroup requires at least 1 of target namespaces, or label selectors
// to be set to scope member operators' namespaced permissions. If both are provided,
// only the target namespace will be used and the label selector will be omitted.
ComplianceType policyv1.ComplianceType `json:"complianceType"` // musthave

// Include the name, namespace, and any `spec` fields for the OperatorGroup.
// For more info, see `kubectl explain operatorgroup.spec` or
// https://olm.operatorframework.io/docs/concepts/crds/operatorgroup/
// +kubebuilder:pruning:PreserveUnknownFields
// +optional
OperatorGroup *OperatorGroup `json:"operatorGroup,omitempty"`
// Subscription defines an Application that can be installed
OperatorGroup *runtime.RawExtension `json:"operatorGroup,omitempty"`

// Include the namespace, and any `spec` fields for the Subscription.
// For more info, see `kubectl explain subscription.spec` or
// https://olm.operatorframework.io/docs/concepts/crds/subscription/
// +kubebuilder:validation:Required
Subscription SubscriptionSpec `json:"subscription"`
// +kubebuilder:pruning:PreserveUnknownFields
Subscription runtime.RawExtension `json:"subscription"`
mprahl marked this conversation as resolved.
Show resolved Hide resolved

// Versions is a list of nonempty strings that specifies which installed versions are compliant when
// in 'inform' mode, and which installPlans are approved when in 'enforce' mode
Versions []policyv1.NonEmptyString `json:"versions,omitempty"`
RemovalBehavior RemovalBehavior `json:"removalBehavior,omitempty"`
StatusConfig StatusConfig `json:"statusConfig,omitempty"`
Versions []policyv1.NonEmptyString `json:"versions,omitempty"`

// FUTURE
//nolint:dupword
// RemovalBehavior RemovalBehavior `json:"removalBehavior,omitempty"`
//nolint:dupword
// StatusConfig StatusConfig `json:"statusConfig,omitempty"`
}

// OperatorPolicyStatus defines the observed state of OperatorPolicy
type OperatorPolicyStatus struct {
// Most recent compliance state of the policy
ComplianceState policyv1.ComplianceState `json:"compliant,omitempty"`
// Historic details on the condition of the policy
Condition []metav1.Condition `json:"conditions,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
// List of resources processed by the policy
RelatedObject policyv1.RelatedObject `json:"relatedObject"`
RelatedObjects []policyv1.RelatedObject `json:"relatedObjects"`
}

func (status OperatorPolicyStatus) RelatedObjsOfKind(kind string) map[int]policyv1.RelatedObject {
objs := make(map[int]policyv1.RelatedObject)

for i, related := range status.RelatedObjects {
if related.Object.Kind == kind {
objs[i] = related
}
}

return objs
}

// Searches the conditions of the policy, and returns the index and condition matching the
// given condition Type. It will return -1 as the index if no condition of the specified
// Type is found.
func (status OperatorPolicyStatus) GetCondition(condType string) (int, metav1.Condition) {
for i, cond := range status.Conditions {
if cond.Type == condType {
Copy link
Contributor

Choose a reason for hiding this comment

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

What if multiple conditions match? is it okay to return only the first match?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it's ok to just return the first match. Ideally we would have some way of enforcing that there are not multiple conditions of the same type (the actual k8s APIs can use listType=map like this, but that didn't seem to be available for CRDs). We'll just need to be careful not to accidentally put the same condition twice.

Copy link
Contributor

Choose a reason for hiding this comment

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

good to learn Thanks

return i, cond
}
}

return -1, metav1.Condition{}
}

//+kubebuilder:object:root=true
Expand Down
83 changes: 15 additions & 68 deletions api/v1beta1/zz_generated.deepcopy.go

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

Loading
Loading