-
Notifications
You must be signed in to change notification settings - Fork 33
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
ConsolePlugin resource #879
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
apiVersion: v1 | ||
kind: Namespace | ||
metadata: | ||
name: kuadrant-console | ||
--- | ||
apiVersion: apps/v1 | ||
kind: Deployment | ||
metadata: | ||
name: kuadrant-console | ||
namespace: kuadrant-console | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this namespace is quite arbitrary. I would try to make it configurable at operator build time (or runtime.. let's discuss about this). One candidate for the default value would be the namespace where the operator is installed. But it is ok as well to be in |
||
labels: | ||
app: kuadrant-console | ||
app.kubernetes.io/component: kuadrant-console | ||
app.kubernetes.io/instance: kuadrant-console | ||
app.kubernetes.io/name: kuadrant-console | ||
app.kubernetes.io/part-of: kuadrant-console | ||
app.openshift.io/runtime-namespace: kuadrant-console | ||
spec: | ||
replicas: 1 | ||
selector: | ||
matchLabels: | ||
app: kuadrant-console | ||
template: | ||
metadata: | ||
labels: | ||
app: kuadrant-console | ||
app.kubernetes.io/component: kuadrant-console | ||
app.kubernetes.io/instance: kuadrant-console | ||
app.kubernetes.io/name: kuadrant-console | ||
app.kubernetes.io/part-of: kuadrant-console | ||
spec: | ||
containers: | ||
- name: kuadrant-console | ||
image: quay.io/kuadrant/console-plugin:latest | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be parametrized as a variable at operator build time, same like Wasm-shim image. Kuadrant console plugin is a new dep for the kuadrant operator. |
||
ports: | ||
- containerPort: 9443 | ||
protocol: TCP | ||
imagePullPolicy: Always | ||
volumeMounts: | ||
- name: plugin-serving-cert | ||
readOnly: true | ||
mountPath: /var/serving-cert | ||
- name: nginx-conf | ||
readOnly: true | ||
mountPath: /etc/nginx/nginx.conf | ||
subPath: nginx.conf | ||
volumes: | ||
- name: plugin-serving-cert | ||
secret: | ||
secretName: plugin-serving-cert | ||
defaultMode: 420 | ||
- name: nginx-conf | ||
configMap: | ||
name: nginx-conf | ||
defaultMode: 420 | ||
restartPolicy: Always | ||
dnsPolicy: ClusterFirst | ||
strategy: | ||
type: RollingUpdate | ||
rollingUpdate: | ||
maxUnavailable: 25% | ||
maxSurge: 25% | ||
--- | ||
apiVersion: v1 | ||
kind: ConfigMap | ||
metadata: | ||
name: nginx-conf | ||
namespace: kuadrant-console | ||
labels: | ||
app: kuadrant-console | ||
app.kubernetes.io/component: kuadrant-console | ||
app.kubernetes.io/instance: kuadrant-console | ||
app.kubernetes.io/name: kuadrant-console | ||
app.kubernetes.io/part-of: kuadrant-console | ||
data: | ||
nginx.conf: | | ||
error_log /dev/stdout; | ||
events {} | ||
http { | ||
access_log /dev/stdout; | ||
include /etc/nginx/mime.types; | ||
default_type application/octet-stream; | ||
keepalive_timeout 65; | ||
|
||
server { | ||
listen 9443 ssl; | ||
listen [::]:9443 ssl; | ||
ssl_certificate /var/serving-cert/tls.crt; | ||
ssl_certificate_key /var/serving-cert/tls.key; | ||
|
||
add_header oauth_token "$http_Authorization"; | ||
|
||
location / { | ||
root /usr/share/nginx/html; | ||
} | ||
} | ||
} | ||
--- | ||
apiVersion: v1 | ||
kind: Service | ||
metadata: | ||
annotations: | ||
service.alpha.openshift.io/serving-cert-secret-name: plugin-serving-cert | ||
name: kuadrant-console | ||
namespace: kuadrant-console | ||
labels: | ||
app: kuadrant-console | ||
app.kubernetes.io/component: kuadrant-console | ||
app.kubernetes.io/instance: kuadrant-console | ||
app.kubernetes.io/name: kuadrant-console | ||
app.kubernetes.io/part-of: kuadrant-console | ||
spec: | ||
ports: | ||
- name: 9443-tcp | ||
protocol: TCP | ||
port: 9443 | ||
targetPort: 9443 | ||
selector: | ||
app: kuadrant-console | ||
type: ClusterIP | ||
sessionAffinity: None | ||
--- | ||
apiVersion: console.openshift.io/v1alpha1 | ||
kind: ConsolePlugin | ||
metadata: | ||
name: kuadrant-console | ||
spec: | ||
displayName: 'Kuadrant Console Plugin' | ||
service: | ||
name: kuadrant-console | ||
namespace: kuadrant-console | ||
port: 9443 | ||
basePath: '/' |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,11 @@ package controllers | |
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/go-logr/logr" | ||
authorinov1beta1 "github.com/kuadrant/authorino-operator/api/v1beta1" | ||
|
@@ -28,12 +33,16 @@ import ( | |
apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||
"k8s.io/apimachinery/pkg/util/yaml" | ||
"k8s.io/utils/env" | ||
istiov1alpha1 "maistra.io/istio-operator/api/v1alpha1" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
|
||
consolev1 "github.com/openshift/api/console/v1" | ||
|
||
maistrav1 "github.com/kuadrant/kuadrant-operator/api/external/maistra/v1" | ||
maistrav2 "github.com/kuadrant/kuadrant-operator/api/external/maistra/v2" | ||
kuadrantv1beta1 "github.com/kuadrant/kuadrant-operator/api/v1beta1" | ||
|
@@ -95,6 +104,9 @@ type KuadrantReconciler struct { | |
//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=httproutes,verbs=get;list;watch;update;patch | ||
//+kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=httproutes/status,verbs=get;update;patch | ||
|
||
// ConsolePlugin perms | ||
//+kubebuilder:rbac:groups=console.openshift.io,resources=consoleplugins,verbs=get;list;watch;create;update;patch;delete | ||
|
||
// Reconcile is part of the main kubernetes reconciliation loop which aims to | ||
// move the current state of the cluster closer to the desired state. | ||
// For more details, check Reconcile and its Result here: | ||
|
@@ -167,6 +179,17 @@ func (r *KuadrantReconciler) Reconcile(eventCtx context.Context, req ctrl.Reques | |
return statusResult, nil | ||
} | ||
|
||
if r.isConsolePluginAvailable() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implementing this on the kuadrant controller makes sense as long as the deployment has something to do with the Kuadrant CR. If not, I would suggest a new controller dedicated to this. |
||
logger.Info("ConsolePlugin API is available, proceeding to apply manifest") | ||
if err := r.applyManifest(ctx, "bundle/manifests/kuadrant-console-plugin.yaml", r.Client()); err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am afraid, this is not gonna work I see four approaches:
Each approach has pro's & con's. Maybe a combination of some of them. IDK. I would go first with the fourth approach. But let's discuss. |
||
logger.Error(err, "failed to apply manifest") | ||
return ctrl.Result{}, err | ||
} | ||
logger.Info("Manifest applied successfully") | ||
} else { | ||
logger.Info("ConsolePlugin API is not available, skipping creation") | ||
} | ||
|
||
logger.Info("successfully reconciled") | ||
return ctrl.Result{}, nil | ||
} | ||
|
@@ -479,3 +502,58 @@ func (r *KuadrantReconciler) SetupWithManager(mgr ctrl.Manager) error { | |
Owns(&authorinov1beta1.Authorino{}). | ||
Complete(r) | ||
} | ||
|
||
func (r *KuadrantReconciler) isConsolePluginAvailable() bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is already implemented in diff --git a/controllers/kuadrant_controller.go b/controllers/kuadrant_controller.go
index b7c89dd..7d7589f 100644
--- a/controllers/kuadrant_controller.go
+++ b/controllers/kuadrant_controller.go
@@ -177,7 +177,13 @@ func (r *KuadrantReconciler) Reconcile(eventCtx context.Context, req ctrl.Reques
return statusResult, nil
}
- if r.isConsolePluginAvailable() {
+ consolePluginGVK := consolev1.GroupVersion.WithKind("ConsolePlugin")
+ isConsolePluginAvailable, err := kuadrantgatewayapi.IsCRDInstalled(r.RestMapper, consolePluginGVK.Group, consolePluginGVK.Kind, consolePluginGVK.Version)
+ if err != nil {
+ return ctrl.Result{}, err
+ }
+
+ if isConsolePluginAvailable {
logger.Info("ConsolePlugin API is available, proceeding to apply manifest")
if err := r.applyManifest(ctx, "bundle/manifests/kuadrant-console-plugin.yaml", r.Client()); err != nil {
logger.Error(err, "failed to apply manifest")
@@ -501,17 +507,6 @@ func (r *KuadrantReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r)
}
-func (r *KuadrantReconciler) isConsolePluginAvailable() bool {
- gvk := consolev1.GroupVersion.WithKind("ConsolePlugin")
- mapping, err := r.RestMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
- if err != nil || mapping == nil {
- log.Log.Info("ConsolePlugin API is not available")
- return false
- }
- log.Log.Info("ConsolePlugin API is available")
- return true
-}
-
func (r *KuadrantReconciler) applyManifest(ctx context.Context, filePath string, k8sClient client.Client) error {
logger := logr.FromContextOrDiscard(ctx) |
||
gvk := consolev1.GroupVersion.WithKind("ConsolePlugin") | ||
mapping, err := r.RestMapper.RESTMapping(gvk.GroupKind(), gvk.Version) | ||
if err != nil || mapping == nil { | ||
log.Log.Info("ConsolePlugin API is not available") | ||
return false | ||
} | ||
log.Log.Info("ConsolePlugin API is available") | ||
return true | ||
} | ||
|
||
func (r *KuadrantReconciler) applyManifest(ctx context.Context, filePath string, k8sClient client.Client) error { | ||
logger := logr.FromContextOrDiscard(ctx) | ||
|
||
yamlFile, err := os.ReadFile(filepath.Clean(filePath)) | ||
if err != nil { | ||
logger.Error(err, "Failed to read YAML file", "file", filePath) | ||
return err | ||
} | ||
|
||
decoder := yaml.NewYAMLOrJSONDecoder(strings.NewReader(string(yamlFile)), 4096) | ||
|
||
for { | ||
obj := &unstructured.Unstructured{} | ||
|
||
if err := decoder.Decode(obj); err != nil { | ||
if errors.Is(err, io.EOF) { | ||
break | ||
} | ||
logger.Error(err, "Failed to decode YAML resource") | ||
return err | ||
} | ||
|
||
logger.Info("Applying resource", "kind", obj.GetKind(), "name", obj.GetName()) | ||
if err := r.applyResource(ctx, obj, k8sClient); err != nil { | ||
logger.Error(err, "Failed to apply resource", "kind", obj.GetKind(), "name", obj.GetName()) | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (r *KuadrantReconciler) applyResource(ctx context.Context, obj *unstructured.Unstructured, k8sClient client.Client) error { | ||
existing := obj.DeepCopy() | ||
err := k8sClient.Get(ctx, client.ObjectKey{Name: obj.GetName(), Namespace: obj.GetNamespace()}, existing) | ||
if apierrors.IsNotFound(err) { | ||
return k8sClient.Create(ctx, obj) | ||
} else if err != nil { | ||
return err | ||
} | ||
obj.SetResourceVersion(existing.GetResourceVersion()) | ||
return k8sClient.Update(ctx, obj) | ||
} |
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 source of truth of the bundle content (99% of it actually), is hosted in
${PROJECT}/config
folder. It should be there