Skip to content
Draft
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
10 changes: 10 additions & 0 deletions internal/controller/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,14 @@ ssl_ca_file = '/etc/certs/cm-olspostgresca/service-ca.crt'
MCPServerTimeout = 60
// MCP server SSE read timeout, sec
MCPServerHTTPReadTimeout = 30

/*** Data Exporter Constants ***/
// ExporterConfigCmName is the name of the exporter configmap
ExporterConfigCmName = "lightspeed-exporter-config"
// ExporterConfigVolumeName is the name of the volume for exporter configuration
ExporterConfigVolumeName = "exporter-config"
// ExporterConfigMountPath is the path where exporter config is mounted
ExporterConfigMountPath = "/etc/config"
// ExporterConfigFilename is the name of the exporter configuration file
ExporterConfigFilename = "config.yaml"
)
30 changes: 30 additions & 0 deletions internal/controller/ols_app_server_assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,36 @@ func (r *OLSConfigReconciler) generateOLSConfigMap(ctx context.Context, cr *olsv
return &cm, nil
}

func (r *OLSConfigReconciler) generateExporterConfigMap(cr *olsv1alpha1.OLSConfig) (*corev1.ConfigMap, error) {
exporterConfigContent := `service_id: "ols"
ingress_server_url: "https://console.redhat.com/api/ingress/v1/upload"
allowed_subdirs:
- feedback
- transcripts

# Collection settings
collection_interval: 5
cleanup_after_send: true
ingress_connection_timeout: 30`

cm := corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: ExporterConfigCmName,
Namespace: r.Options.Namespace,
Labels: generateAppServerSelectorLabels(),
},
Data: map[string]string{
ExporterConfigFilename: exporterConfigContent,
},
}

if err := controllerutil.SetControllerReference(cr, &cm, r.Scheme); err != nil {
return nil, err
}

return &cm, nil
}

func (r *OLSConfigReconciler) getAdditionalCAFileNames(cr *olsv1alpha1.OLSConfig) ([]string, error) {
if cr.Spec.OLSConfig.AdditionalCAConfigMapRef == nil {
return nil, nil
Expand Down
46 changes: 34 additions & 12 deletions internal/controller/ols_app_server_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,20 @@ func (r *OLSConfigReconciler) generateOLSDeployment(cr *olsv1alpha1.OLSConfig) (
},
}
volumes = append(volumes, olsUserDataVolume)

// Add exporter config volume
exporterConfigVolume := corev1.Volume{
Name: ExporterConfigVolumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: ExporterConfigCmName,
},
DefaultMode: &volumeDefaultMode,
},
},
}
volumes = append(volumes, exporterConfigVolume)
}

// User provided additional CA certificates
Expand Down Expand Up @@ -224,8 +238,13 @@ func (r *OLSConfigReconciler) generateOLSDeployment(cr *olsv1alpha1.OLSConfig) (
Name: OLSUserDataVolumeName,
MountPath: OLSUserDataMountPath,
}
exporterConfigVolumeMount := corev1.VolumeMount{
Name: ExporterConfigVolumeName,
MountPath: ExporterConfigMountPath,
ReadOnly: true,
}
if dataCollectorEnabled {
volumeMounts = append(volumeMounts, olsUserDataVolumeMount)
volumeMounts = append(volumeMounts, olsUserDataVolumeMount, exporterConfigVolumeMount)
}
if cr.Spec.OLSConfig.AdditionalCAConfigMapRef != nil {
additionalCAVolumeMount := corev1.VolumeMount{
Expand Down Expand Up @@ -357,26 +376,29 @@ func (r *OLSConfigReconciler) generateOLSDeployment(cr *olsv1alpha1.OLSConfig) (
return &deployment, nil
}

// Add telemetry container
telemetryContainer := corev1.Container{
Name: "lightspeed-service-user-data-collector",
Image: r.Options.LightspeedServiceImage,
// Add data exporter container
exporterContainer := corev1.Container{
Name: "lightspeed-to-dataverse-exporter",
Image: "quay.io/lightspeed-core/lightspeed-to-dataverse-exporter:dev-latest",
ImagePullPolicy: corev1.PullAlways,
SecurityContext: &corev1.SecurityContext{
AllowPrivilegeEscalation: &[]bool{false}[0],
ReadOnlyRootFilesystem: &[]bool{true}[0],
},
VolumeMounts: volumeMounts,
Env: []corev1.EnvVar{
{
Name: "OLS_CONFIG_FILE",
Value: path.Join(OLSConfigMountPath, OLSConfigFilename),
},
Args: []string{
"--mode",
"openshift",
"--config",
path.Join(ExporterConfigMountPath, ExporterConfigFilename),
"--log-level",
"DEBUG",
"--data-dir",
OLSUserDataMountPath,
},
Command: []string{"python3.11", "/app-root/ols/user_data_collection/data_collector.py"},
Resources: *data_collector_resources,
}
deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, telemetryContainer)
deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, exporterContainer)

// Add MCP sidecar container if introspection is enabled
if cr.Spec.OLSConfig.IntrospectionEnabled {
Expand Down
45 changes: 45 additions & 0 deletions internal/controller/ols_app_server_reconciliator.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ func (r *OLSConfigReconciler) reconcileAppServer(ctx context.Context, olsconfig
Name: "reconcile OLSConfigMap",
Task: r.reconcileOLSConfigMap,
},
{
Name: "reconcile ExporterConfigMap",
Task: r.reconcileExporterConfigMap,
},
{
Name: "reconcile Additional CA ConfigMap",
Task: r.reconcileOLSAdditionalCAConfigMap,
Expand Down Expand Up @@ -141,6 +145,47 @@ func (r *OLSConfigReconciler) reconcileOLSConfigMap(ctx context.Context, cr *ols
return nil
}

func (r *OLSConfigReconciler) reconcileExporterConfigMap(ctx context.Context, cr *olsv1alpha1.OLSConfig) error {
// Only create exporter configmap if data collector is enabled
dataCollectorEnabled, err := r.dataCollectorEnabled(cr)
if err != nil {
return err
}

if !dataCollectorEnabled {
r.logger.Info("Data collector not enabled, exporter configmap reconciliation skipped")
return nil
}

cm, err := r.generateExporterConfigMap(cr)
if err != nil {
return fmt.Errorf("failed to generate exporter configmap: %w", err)
}

foundCm := &corev1.ConfigMap{}
err = r.Client.Get(ctx, client.ObjectKey{Name: ExporterConfigCmName, Namespace: r.Options.Namespace}, foundCm)
if err != nil && errors.IsNotFound(err) {
r.logger.Info("creating a new exporter configmap", "configmap", cm.Name)
err = r.Create(ctx, cm)
if err != nil {
return fmt.Errorf("failed to create exporter configmap: %w", err)
}
return nil
} else if err != nil {
return fmt.Errorf("failed to get exporter configmap: %w", err)
}

// Update existing configmap
foundCm.Data = cm.Data
err = r.Update(ctx, foundCm)
if err != nil {
return fmt.Errorf("failed to update exporter configmap: %w", err)
}

r.logger.Info("Exporter configmap reconciled", "configmap", cm.Name)
return nil
}

func (r *OLSConfigReconciler) reconcileOLSAdditionalCAConfigMap(ctx context.Context, cr *olsv1alpha1.OLSConfig) error {
if cr.Spec.OLSConfig.AdditionalCAConfigMapRef == nil {
// no additional CA certs, skip
Expand Down