Preliminary scaffolding
This commit is contained in:
20
api/v1beta1/common_types.go
Normal file
20
api/v1beta1/common_types.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package v1beta1
|
||||||
|
|
||||||
|
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
||||||
|
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||||
|
|
||||||
|
// FirewallRuleSpec defines the desired state of FirewallRule.
|
||||||
|
type ServiceSpec struct {
|
||||||
|
Namespace string `json:"namespace,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FirewallSource struct {
|
||||||
|
Zones []string `json:"from_zones,omitempty"`
|
||||||
|
Networks []string `json:"from_networks,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FirewallDestination struct {
|
||||||
|
FirewallGroups []string `json:"firewall_group,omitempty"`
|
||||||
|
Services []ServiceSpec `json:"service,omitempty"`
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||||
|
|
||||||
// FirewallGroupSpec defines the desired state of FirewallGroup.
|
// FirewallGroupSpec defines the desired state of FirewallGroup.
|
||||||
|
|
||||||
type FirewallGroupSpec struct {
|
type FirewallGroupSpec struct {
|
||||||
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
// Important: Run "make" to regenerate code after modifying this file
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
@@ -38,14 +39,11 @@ type FirewallGroupSpec struct {
|
|||||||
ManualAddresses []string `json:"manualAddresses,omitempty"`
|
ManualAddresses []string `json:"manualAddresses,omitempty"`
|
||||||
ManualPorts []string `json:"manualPorts,omitempty"`
|
ManualPorts []string `json:"manualPorts,omitempty"`
|
||||||
|
|
||||||
|
AutoCreatedFrom ServiceSpec `json:"auto_created_from,omitempty"`
|
||||||
|
|
||||||
// AutoIncludeSelector defines which services to extract addresses from
|
// AutoIncludeSelector defines which services to extract addresses from
|
||||||
// +optional
|
// +optional
|
||||||
AutoIncludeSelector *metav1.LabelSelector `json:"autoIncludeSelector,omitempty"`
|
AutoIncludeSelector *metav1.LabelSelector `json:"autoIncludeSelector,omitempty"`
|
||||||
|
|
||||||
// AddressType can be "ip", "cidr", or "both"
|
|
||||||
// +kubebuilder:validation:Enum=ip;cidr;both
|
|
||||||
// +optional
|
|
||||||
AddressType string `json:"addressType,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FirewallGroupStatus defines the observed state of FirewallGroup.
|
// FirewallGroupStatus defines the observed state of FirewallGroup.
|
||||||
|
|||||||
@@ -24,12 +24,30 @@ import (
|
|||||||
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
|
||||||
|
|
||||||
// FirewallRuleSpec defines the desired state of FirewallRule.
|
// FirewallRuleSpec defines the desired state of FirewallRule.
|
||||||
|
// type ServiceSpec struct {
|
||||||
|
// Namespace string `json:"namespace,omitempty"`
|
||||||
|
// Name string `json:"name,omitempty"`
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type FirewallSource struct {
|
||||||
|
// Zones []string `json:"from_zones,omitempty"`
|
||||||
|
// Networks []string `json:"from_networks,omitempty"`
|
||||||
|
//}
|
||||||
|
|
||||||
|
//type FirewallDestination struct {
|
||||||
|
// FirewallGroups []string `json:"firewall_group,omitempty"`
|
||||||
|
// Services []ServiceSpec `json:"service,omitempty"`
|
||||||
|
//}
|
||||||
|
|
||||||
type FirewallRuleSpec struct {
|
type FirewallRuleSpec struct {
|
||||||
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
// Important: Run "make" to regenerate code after modifying this file
|
// Important: Run "make" to regenerate code after modifying this file
|
||||||
|
|
||||||
// Foo is an example field of FirewallRule. Edit firewallrule_types.go to remove/update
|
Name string `json:"name"`
|
||||||
Foo string `json:"foo,omitempty"`
|
Source FirewallSource `json:"source"`
|
||||||
|
Destination FirewallDestination `json:"destination"`
|
||||||
|
MatchFirewallGroupsInAllNamespaces bool `json:"match_firewall_groups_in_all_namespaces,omitempty"`
|
||||||
|
MatchServicesInAllNamespaces bool `json:"match_services_in_all_namespaces,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FirewallRuleStatus defines the observed state of FirewallRule.
|
// FirewallRuleStatus defines the observed state of FirewallRule.
|
||||||
|
|||||||
@@ -25,6 +25,31 @@ import (
|
|||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *FirewallDestination) DeepCopyInto(out *FirewallDestination) {
|
||||||
|
*out = *in
|
||||||
|
if in.FirewallGroups != nil {
|
||||||
|
in, out := &in.FirewallGroups, &out.FirewallGroups
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Services != nil {
|
||||||
|
in, out := &in.Services, &out.Services
|
||||||
|
*out = make([]ServiceSpec, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallDestination.
|
||||||
|
func (in *FirewallDestination) DeepCopy() *FirewallDestination {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(FirewallDestination)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FirewallGroup) DeepCopyInto(out *FirewallGroup) {
|
func (in *FirewallGroup) DeepCopyInto(out *FirewallGroup) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -97,6 +122,7 @@ func (in *FirewallGroupSpec) DeepCopyInto(out *FirewallGroupSpec) {
|
|||||||
*out = make([]string, len(*in))
|
*out = make([]string, len(*in))
|
||||||
copy(*out, *in)
|
copy(*out, *in)
|
||||||
}
|
}
|
||||||
|
out.AutoCreatedFrom = in.AutoCreatedFrom
|
||||||
if in.AutoIncludeSelector != nil {
|
if in.AutoIncludeSelector != nil {
|
||||||
in, out := &in.AutoIncludeSelector, &out.AutoIncludeSelector
|
in, out := &in.AutoIncludeSelector, &out.AutoIncludeSelector
|
||||||
*out = new(v1.LabelSelector)
|
*out = new(v1.LabelSelector)
|
||||||
@@ -143,7 +169,7 @@ func (in *FirewallRule) DeepCopyInto(out *FirewallRule) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
out.Spec = in.Spec
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
out.Status = in.Status
|
out.Status = in.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,6 +226,8 @@ func (in *FirewallRuleList) DeepCopyObject() runtime.Object {
|
|||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FirewallRuleSpec) DeepCopyInto(out *FirewallRuleSpec) {
|
func (in *FirewallRuleSpec) DeepCopyInto(out *FirewallRuleSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
in.Source.DeepCopyInto(&out.Source)
|
||||||
|
in.Destination.DeepCopyInto(&out.Destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleSpec.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallRuleSpec.
|
||||||
@@ -227,6 +255,31 @@ func (in *FirewallRuleStatus) DeepCopy() *FirewallRuleStatus {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *FirewallSource) DeepCopyInto(out *FirewallSource) {
|
||||||
|
*out = *in
|
||||||
|
if in.Zones != nil {
|
||||||
|
in, out := &in.Zones, &out.Zones
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
if in.Networks != nil {
|
||||||
|
in, out := &in.Networks, &out.Networks
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FirewallSource.
|
||||||
|
func (in *FirewallSource) DeepCopy() *FirewallSource {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(FirewallSource)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *FirewallZone) DeepCopyInto(out *FirewallZone) {
|
func (in *FirewallZone) DeepCopyInto(out *FirewallZone) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@@ -413,3 +466,18 @@ func (in *NetworkconfigurationStatus) DeepCopy() *NetworkconfigurationStatus {
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ServiceSpec) DeepCopyInto(out *ServiceSpec) {
|
||||||
|
*out = *in
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSpec.
|
||||||
|
func (in *ServiceSpec) DeepCopy() *ServiceSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ServiceSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,15 +37,15 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: FirewallGroupSpec defines the desired state of FirewallGroup.
|
|
||||||
properties:
|
properties:
|
||||||
addressType:
|
auto_created_from:
|
||||||
description: AddressType can be "ip", "cidr", or "both"
|
description: FirewallRuleSpec defines the desired state of FirewallRule.
|
||||||
enum:
|
properties:
|
||||||
- ip
|
name:
|
||||||
- cidr
|
type: string
|
||||||
- both
|
namespace:
|
||||||
type: string
|
type: string
|
||||||
|
type: object
|
||||||
autoIncludeSelector:
|
autoIncludeSelector:
|
||||||
description: AutoIncludeSelector defines which services to extract
|
description: AutoIncludeSelector defines which services to extract
|
||||||
addresses from
|
addresses from
|
||||||
|
|||||||
@@ -37,12 +37,45 @@ spec:
|
|||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
spec:
|
spec:
|
||||||
description: FirewallRuleSpec defines the desired state of FirewallRule.
|
|
||||||
properties:
|
properties:
|
||||||
foo:
|
destination:
|
||||||
description: Foo is an example field of FirewallRule. Edit firewallrule_types.go
|
properties:
|
||||||
to remove/update
|
firewall_group:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
service:
|
||||||
|
items:
|
||||||
|
description: FirewallRuleSpec defines the desired state of FirewallRule.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
namespace:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
match_firewall_groups_in_all_namespaces:
|
||||||
|
type: boolean
|
||||||
|
match_services_in_all_namespaces:
|
||||||
|
type: boolean
|
||||||
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
source:
|
||||||
|
properties:
|
||||||
|
from_networks:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
from_zones:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- destination
|
||||||
|
- name
|
||||||
|
- source
|
||||||
type: object
|
type: object
|
||||||
status:
|
status:
|
||||||
description: FirewallRuleStatus defines the observed state of FirewallRule.
|
description: FirewallRuleStatus defines the observed state of FirewallRule.
|
||||||
|
|||||||
@@ -6,4 +6,3 @@ metadata:
|
|||||||
app.kubernetes.io/managed-by: kustomize
|
app.kubernetes.io/managed-by: kustomize
|
||||||
name: firewallrule-sample
|
name: firewallrule-sample
|
||||||
spec:
|
spec:
|
||||||
# TODO(user): Add fields here
|
|
||||||
|
|||||||
@@ -18,10 +18,14 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
|
||||||
unifiv1beta1 "github.com/vegardengen/unifi-network-operator/api/v1beta1"
|
unifiv1beta1 "github.com/vegardengen/unifi-network-operator/api/v1beta1"
|
||||||
@@ -41,6 +45,7 @@ type FirewallRuleReconciler struct {
|
|||||||
// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallrules/status,verbs=get;update;patch
|
// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallrules/status,verbs=get;update;patch
|
||||||
// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallrules/finalizers,verbs=update
|
// +kubebuilder:rbac:groups=unifi.engen.priv.no,resources=firewallrules/finalizers,verbs=update
|
||||||
// +kubebuilder:rbac:groups="",resources=configmaps,verbs=list;get;watch
|
// +kubebuilder:rbac:groups="",resources=configmaps,verbs=list;get;watch
|
||||||
|
// +kubebuilder:rbac:groups="",resources=services,verbs=list;get;watch
|
||||||
|
|
||||||
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
// Reconcile is part of the main kubernetes reconciliation loop which aims to
|
||||||
// move the current state of the cluster closer to the desired state.
|
// move the current state of the cluster closer to the desired state.
|
||||||
@@ -69,13 +74,117 @@ func (r *FirewallRuleReconciler) Reconcile(ctx context.Context, req ctrl.Request
|
|||||||
return ctrl.Result{}, err
|
return ctrl.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var zoneCRDs unifiv1beta1.FirewallZoneList
|
||||||
|
var networkCRDs unifiv1beta1.NetworkconfigurationList
|
||||||
|
|
||||||
|
err = r.List(ctx, &zoneCRDs, client.InNamespace(defaultNs))
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Could not list firewall zones")
|
||||||
|
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneCRDNames := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, zoneCRD := range zoneCRDs.Items {
|
||||||
|
zoneCRDNames[zoneCRD.Name] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.List(ctx, &networkCRDs, client.InNamespace(defaultNs))
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err, "Could not list networks")
|
||||||
|
return ctrl.Result{RequeueAfter: 10 * time.Minute}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
networkCRDNames := make(map[string]struct{})
|
||||||
|
|
||||||
|
for _, networkCRD := range networkCRDs.Items {
|
||||||
|
networkCRDNames[networkCRD.Name] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var firewallRule unifiv1beta1.FirewallRule
|
||||||
|
|
||||||
|
if err := r.Get(ctx, req.NamespacedName, &firewallRule); err != nil {
|
||||||
|
return ctrl.Result{}, client.IgnoreNotFound(err)
|
||||||
|
}
|
||||||
|
log.Info(firewallRule.Spec.Name)
|
||||||
|
|
||||||
return ctrl.Result{}, nil
|
return ctrl.Result{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *FirewallRuleReconciler) mapFirewallGroupToFirewallRules(ctx context.Context, obj client.Object) []ctrl.Request {
|
||||||
|
var requests []ctrl.Request
|
||||||
|
service, ok := obj.(*corev1.Service)
|
||||||
|
if !ok {
|
||||||
|
return requests
|
||||||
|
}
|
||||||
|
|
||||||
|
var allFirewallRules unifiv1beta1.FirewallRuleList
|
||||||
|
|
||||||
|
if err := r.List(ctx, &allFirewallRules); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rule := range allFirewallRules.Items {
|
||||||
|
if rule.Spec.MatchFirewallGroupsInAllNamespaces || rule.Namespace == service.Namespace {
|
||||||
|
annotationKey := "unifi.engen.priv.no/firewall-rule"
|
||||||
|
annotationVal := rule.Name
|
||||||
|
if val, ok := service.Annotations[annotationKey]; ok && (annotationVal == "" || val == annotationVal) {
|
||||||
|
requests = append(requests, ctrl.Request{
|
||||||
|
NamespacedName: types.NamespacedName{
|
||||||
|
Name: rule.Name,
|
||||||
|
Namespace: rule.Namespace,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return requests
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FirewallRuleReconciler) mapServiceToFirewallRules(ctx context.Context, obj client.Object) []ctrl.Request {
|
||||||
|
var requests []ctrl.Request
|
||||||
|
service, ok := obj.(*corev1.Service)
|
||||||
|
if !ok {
|
||||||
|
return requests
|
||||||
|
}
|
||||||
|
|
||||||
|
var allFirewallRules unifiv1beta1.FirewallRuleList
|
||||||
|
|
||||||
|
if err := r.List(ctx, &allFirewallRules); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rule := range allFirewallRules.Items {
|
||||||
|
if rule.Spec.MatchServicesInAllNamespaces || rule.Namespace == service.Namespace {
|
||||||
|
annotationKey := "unifi.engen.priv.no/firewall-rule"
|
||||||
|
annotationVal := rule.Name
|
||||||
|
if val, ok := service.Annotations[annotationKey]; ok && (annotationVal == "" || val == annotationVal) {
|
||||||
|
requests = append(requests, ctrl.Request{
|
||||||
|
NamespacedName: types.NamespacedName{
|
||||||
|
Name: rule.Name,
|
||||||
|
Namespace: rule.Namespace,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return requests
|
||||||
|
}
|
||||||
|
|
||||||
// SetupWithManager sets up the controller with the Manager.
|
// SetupWithManager sets up the controller with the Manager.
|
||||||
func (r *FirewallRuleReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
func (r *FirewallRuleReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
||||||
return ctrl.NewControllerManagedBy(mgr).
|
return ctrl.NewControllerManagedBy(mgr).
|
||||||
For(&unifiv1beta1.FirewallRule{}).
|
For(&unifiv1beta1.FirewallRule{}).
|
||||||
Named("firewallrule").
|
Named("firewallrule").
|
||||||
|
Watches(
|
||||||
|
&corev1.Service{},
|
||||||
|
handler.EnqueueRequestsFromMapFunc(r.mapServiceToFirewallRules),
|
||||||
|
).
|
||||||
|
Watches(
|
||||||
|
&unifiv1beta1.FirewallGroup{},
|
||||||
|
handler.EnqueueRequestsFromMapFunc(r.mapFirewallGroupToFirewallRules),
|
||||||
|
).
|
||||||
Complete(r)
|
Complete(r)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user