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

feat(insights): optionally deploy a proxy for Insights #670

Merged
merged 22 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 18 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
22 changes: 19 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ ifneq ("$(wildcard $(GINKGO))","")
GO_TEST="$(GINKGO)" -cover -output-dir=.
endif

# Optional Red Hat Insights integration
ENABLE_INSIGHTS ?= false
ifeq ($(ENABLE_INSIGHTS), true)
KUSTOMIZE_DIR ?= config/insights
INSIGHTS_PROXY_NAMESPACE ?= quay.io/3scale
INSIGHTS_PROXY_NAME ?= apicast
INSIGHTS_PROXY_VERSION ?= insights-01
export INSIGHTS_PROXY_IMG ?= $(INSIGHTS_PROXY_NAMESPACE)/$(INSIGHTS_PROXY_NAME):$(INSIGHTS_PROXY_VERSION)
export INSIGHTS_BACKEND ?= cert.console.redhat.com
else
KUSTOMIZE_DIR ?= config/default
endif

##@ General

.PHONY: all
Expand Down Expand Up @@ -275,6 +288,9 @@ manifests: controller-gen ## Generate manifests e.g. CRD, RBAC, etc.
$(CONTROLLER_GEN) rbac:roleName=role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
envsubst < hack/image_tag_patch.yaml.in > config/default/image_tag_patch.yaml
envsubst < hack/image_pull_patch.yaml.in > config/default/image_pull_patch.yaml
ifeq ($(ENABLE_INSIGHTS), true)
envsubst < hack/insights_patch.yaml.in > config/insights/insights_patch.yaml
endif

.PHONY: fmt
fmt: add-license ## Run go fmt against code.
Expand Down Expand Up @@ -435,11 +451,11 @@ predeploy:

.PHONY: print_deploy_config
print_deploy_config: predeploy ## Print deployment configurations for the controller.
$(KUSTOMIZE) build config/default
$(KUSTOMIZE) build $(KUSTOMIZE_DIR)

.PHONY: deploy
deploy: check_cert_manager manifests kustomize predeploy ## Deploy controller in the configured cluster in ~/.kube/config
$(KUSTOMIZE) build config/default | $(CLUSTER_CLIENT) apply -f -
$(KUSTOMIZE) build $(KUSTOMIZE_DIR) | $(CLUSTER_CLIENT) apply -f -
ifeq ($(DISABLE_SERVICE_TLS), true)
@echo "Disabling TLS for in-cluster communication between Services"
@$(CLUSTER_CLIENT) -n $(DEPLOY_NAMESPACE) set env deployment/cryostat-operator-controller-manager DISABLE_SERVICE_TLS=true
Expand All @@ -449,7 +465,7 @@ endif
undeploy: ## Undeploy controller from the configured cluster in ~/.kube/config.
- $(CLUSTER_CLIENT) delete --ignore-not-found=$(ignore-not-found) -f config/samples/operator_v1beta1_cryostat.yaml
- $(CLUSTER_CLIENT) delete --ignore-not-found=$(ignore-not-found) -f config/samples/operator_v1beta1_clustercryostat.yaml
- $(KUSTOMIZE) build config/default | $(CLUSTER_CLIENT) delete --ignore-not-found=$(ignore-not-found) -f -
- $(KUSTOMIZE) build $(KUSTOMIZE_DIR) | $(CLUSTER_CLIENT) delete --ignore-not-found=$(ignore-not-found) -f -

.PHONY: deploy_bundle
deploy_bundle: check_cert_manager undeploy_bundle ## Deploy the controller in the bundle format with OLM.
Expand Down
17 changes: 17 additions & 0 deletions config/insights/insights_patch.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: manager
env:
- name: RELATED_IMAGE_INSIGHTS_PROXY
value: "quay.io/3scale/apicast:insights-01"
- name: INSIGHTS_ENABLED
value: "true"
- name: INSIGHTS_BACKEND_DOMAIN
value: "cert.console.redhat.com"
5 changes: 5 additions & 0 deletions config/insights/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
resources:
- ../default

patchesStrategicMerge:
- insights_patch.yaml
4 changes: 4 additions & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ spec:
env:
- name: WATCH_NAMESPACE
value: ""
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
limits:
cpu: 1000m
Expand Down
16 changes: 16 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ metadata:
creationTimestamp: null
name: role
rules:
- apiGroups:
- ""
resources:
- configmaps
- configmaps/finalizers
- secrets
- services
verbs:
- '*'
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -42,6 +51,13 @@ rules:
- statefulsets
verbs:
- '*'
- apiGroups:
- apps
resources:
- deployments
- deployments/finalizers
verbs:
- '*'
- apiGroups:
- apps.openshift.io
resources:
Expand Down
17 changes: 17 additions & 0 deletions hack/insights_patch.yaml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: manager
env:
- name: RELATED_IMAGE_INSIGHTS_PROXY
value: "${INSIGHTS_PROXY_IMG}"
- name: INSIGHTS_ENABLED
value: "true"
- name: INSIGHTS_BACKEND_DOMAIN
value: "${INSIGHTS_BACKEND}"
14 changes: 8 additions & 6 deletions internal/controllers/clustercryostat_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ type ClusterCryostatReconciler struct {
*ReconcilerConfig
}

func NewClusterCryostatReconciler(config *ReconcilerConfig) *ClusterCryostatReconciler {
func NewClusterCryostatReconciler(config *ReconcilerConfig) (*ClusterCryostatReconciler, error) {
delegate, err := newReconciler(config, &operatorv1beta1.ClusterCryostat{}, false)
if err != nil {
return nil, err
}
return &ClusterCryostatReconciler{
ReconcilerConfig: config,
delegate: &Reconciler{
ReconcilerConfig: config,
},
}
delegate: delegate,
}, nil
}

// +kubebuilder:rbac:groups="",resources=pods;services;services/finalizers;endpoints;persistentvolumeclaims;events;configmaps;secrets;serviceaccounts,verbs=*
Expand Down Expand Up @@ -94,7 +96,7 @@ func (r *ClusterCryostatReconciler) Reconcile(ctx context.Context, request ctrl.

// SetupWithManager sets up the controller with the Manager.
func (r *ClusterCryostatReconciler) SetupWithManager(mgr ctrl.Manager) error {
return r.delegate.setupWithManager(mgr, &operatorv1beta1.ClusterCryostat{}, r)
return r.delegate.setupWithManager(mgr, r)
}

func (r *ClusterCryostatReconciler) GetConfig() *ReconcilerConfig {
Expand Down
2 changes: 1 addition & 1 deletion internal/controllers/clustercryostat_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,6 @@ func (t *cryostatTestInput) expectTargetNamespaces() {
Expect(*cr.TargetNamespaceStatus).To(ConsistOf(t.TargetNamespaces))
}

func newClusterCryostatController(config *controllers.ReconcilerConfig) controllers.CommonReconciler {
func newClusterCryostatController(config *controllers.ReconcilerConfig) (controllers.CommonReconciler, error) {
return controllers.NewClusterCryostatReconciler(config)
}
34 changes: 27 additions & 7 deletions internal/controllers/common/common_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import (
"strings"
"time"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
Expand All @@ -37,21 +39,21 @@ type OSUtils interface {
GenPasswd(length int) string
}

type defaultOSUtils struct{}
type DefaultOSUtils struct{}

// GetEnv returns the value of the environment variable with the provided name. If no such
// variable exists, the empty string is returned.
func (o *defaultOSUtils) GetEnv(name string) string {
func (o *DefaultOSUtils) GetEnv(name string) string {
return os.Getenv(name)
}

// GetFileContents reads and returns the entire file contents specified by the path
func (o *defaultOSUtils) GetFileContents(path string) ([]byte, error) {
func (o *DefaultOSUtils) GetFileContents(path string) ([]byte, error) {
return ioutil.ReadFile(path)
}

// GenPasswd generates a psuedorandom password of a given length.
func (o *defaultOSUtils) GenPasswd(length int) string {
func (o *DefaultOSUtils) GenPasswd(length int) string {
rand.Seed(time.Now().UnixNano())
chars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
b := make([]byte, length)
Expand All @@ -63,13 +65,16 @@ func (o *defaultOSUtils) GenPasswd(length int) string {

// ClusterUniqueName returns a name for cluster-scoped objects that is
// uniquely identified by a namespace and name.
func ClusterUniqueName(kind string, name string, namespace string) string {
func ClusterUniqueName(gvk *schema.GroupVersionKind, name string, namespace string) string {
// Use the SHA256 checksum of the namespaced name as a suffix
nn := types.NamespacedName{Namespace: namespace, Name: name}
suffix := fmt.Sprintf("%x", sha256.Sum256([]byte(nn.String())))
return strings.ToLower(kind) + "-" + suffix
return strings.ToLower(gvk.Kind) + "-" + suffix
}

// MergeLabelsAndAnnotations copies labels and annotations from a source
// to the destination ObjectMeta, overwriting any existing labels and
// annotations of the same key.
func MergeLabelsAndAnnotations(dest *metav1.ObjectMeta, srcLabels, srcAnnotations map[string]string) {
// Check and create labels/annotations map if absent
if dest.Labels == nil {
Expand All @@ -83,8 +88,23 @@ func MergeLabelsAndAnnotations(dest *metav1.ObjectMeta, srcLabels, srcAnnotation
for k, v := range srcLabels {
dest.Labels[k] = v
}

for k, v := range srcAnnotations {
dest.Annotations[k] = v
}
}

// SeccompProfile returns a SeccompProfile for the restricted
// Pod Security Standard that, on OpenShift, is backwards-compatible
// with OpenShift < 4.11.
// TODO Remove once OpenShift < 4.11 support is dropped
func SeccompProfile(openshift bool) *corev1.SeccompProfile {
// For backward-compatibility with OpenShift < 4.11,
// leave the seccompProfile empty. In OpenShift >= 4.11,
// the restricted-v2 SCC will populate it for us.
if openshift {
return nil
}
return &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ type ImageTags struct {
}

type ServiceSpecs struct {
CoreURL *url.URL
GrafanaURL *url.URL
ReportsURL *url.URL
CoreURL *url.URL
GrafanaURL *url.URL
ReportsURL *url.URL
InsightsURL *url.URL
}

// TLSConfig contains TLS-related information useful when creating other objects
Expand Down Expand Up @@ -390,7 +391,7 @@ func NewPodForCR(cr *model.CryostatInstance, specs *ServiceSpecs, imageTags *Ima
// Ensure PV mounts are writable
FSGroup: &fsGroup,
RunAsNonRoot: &nonRoot,
SeccompProfile: seccompProfile(openshift),
SeccompProfile: common.SeccompProfile(openshift),
}
}

Expand Down Expand Up @@ -444,10 +445,6 @@ func NewReportContainerResource(cr *model.CryostatInstance) *corev1.ResourceRequ
return resources
}

// ALL capability to drop for restricted pod security. See:
// https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
const capabilityAll corev1.Capability = "ALL"

func NewPodForReports(cr *model.CryostatInstance, imageTags *ImageTags, tls *TLSConfig, openshift bool) *corev1.PodSpec {
resources := NewReportContainerResource(cr)
cpus := resources.Requests.Cpu().Value() // Round to 1 if cpu request < 1000m
Expand Down Expand Up @@ -537,7 +534,7 @@ func NewPodForReports(cr *model.CryostatInstance, imageTags *ImageTags, tls *TLS
nonRoot := true
podSc = &corev1.PodSecurityContext{
RunAsNonRoot: &nonRoot,
SeccompProfile: seccompProfile(openshift),
SeccompProfile: common.SeccompProfile(openshift),
}
}

Expand All @@ -549,7 +546,7 @@ func NewPodForReports(cr *model.CryostatInstance, imageTags *ImageTags, tls *TLS
containerSc = &corev1.SecurityContext{
AllowPrivilegeEscalation: &privEscalation,
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{capabilityAll},
Drop: []corev1.Capability{constants.CapabilityAll},
},
}
}
Expand Down Expand Up @@ -729,6 +726,17 @@ func NewCoreContainer(cr *model.CryostatInstance, specs *ServiceSpecs, imageTag
envs = append(envs, subprocessReportHeapEnv...)
}

// Define INSIGHTS_PROXY URL if Insights integration is enabled
if specs.InsightsURL != nil {
insightsEnvs := []corev1.EnvVar{
{
Name: "INSIGHTS_PROXY",
Value: specs.InsightsURL.String(),
},
}
envs = append(envs, insightsEnvs...)
}

if cr.Spec.MaxWsConnections != 0 {
maxWsConnections := strconv.Itoa(int(cr.Spec.MaxWsConnections))
maxWsConnectionsEnv := []corev1.EnvVar{
Expand Down Expand Up @@ -947,7 +955,7 @@ func NewCoreContainer(cr *model.CryostatInstance, specs *ServiceSpecs, imageTag
containerSc = &corev1.SecurityContext{
AllowPrivilegeEscalation: &privEscalation,
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{capabilityAll},
Drop: []corev1.Capability{constants.CapabilityAll},
},
}
}
Expand Down Expand Up @@ -1037,7 +1045,7 @@ func NewGrafanaContainer(cr *model.CryostatInstance, imageTag string, tls *TLSCo
containerSc = &corev1.SecurityContext{
AllowPrivilegeEscalation: &privEscalation,
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{capabilityAll},
Drop: []corev1.Capability{constants.CapabilityAll},
},
}
}
Expand Down Expand Up @@ -1097,7 +1105,7 @@ func NewJfrDatasourceContainer(cr *model.CryostatInstance, imageTag string) core
containerSc = &corev1.SecurityContext{
AllowPrivilegeEscalation: &privEscalation,
Capabilities: &corev1.Capabilities{
Drop: []corev1.Capability{capabilityAll},
Drop: []corev1.Capability{constants.CapabilityAll},
},
}
}
Expand Down Expand Up @@ -1195,18 +1203,6 @@ func newVolumeForCR(cr *model.CryostatInstance) []corev1.Volume {
}
}

func seccompProfile(openshift bool) *corev1.SeccompProfile {
// For backward-compatibility with OpenShift < 4.11,
// leave the seccompProfile empty. In OpenShift >= 4.11,
// the restricted-v2 SCC will populate it for us.
if openshift {
return nil
}
return &corev1.SeccompProfile{
Type: corev1.SeccompProfileTypeRuntimeDefault,
}
}

func useEmptyDir(cr *model.CryostatInstance) bool {
return cr.Spec.StorageOptions != nil && cr.Spec.StorageOptions.EmptyDir != nil && cr.Spec.StorageOptions.EmptyDir.Enabled

Expand Down
2 changes: 1 addition & 1 deletion internal/controllers/common/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const disableServiceTLS = "DISABLE_SERVICE_TLS"
func NewReconcilerTLS(config *ReconcilerTLSConfig) ReconcilerTLS {
configCopy := *config
if config.OSUtils == nil {
configCopy.OSUtils = &defaultOSUtils{}
configCopy.OSUtils = &DefaultOSUtils{}
}
return &reconcilerTLS{
ReconcilerTLSConfig: &configCopy,
Expand Down
Loading
Loading