Skip to content

Commit

Permalink
add ability to customize kfp-launcher ConfigMap data contents
Browse files Browse the repository at this point in the history
Allow the user to fully replace the `data` contents of the kfp-launcher ConfigMap.
The `kfp-launcher` component requires a ConfigMap to exist in the namespace
where it runs (i.e. the namespace where pipelines run). This ConfigMap contains
object storage configuration, as well as pipeline root (object store root path
where artifacts will be uploaded) configuration. Currently this ConfigMap *must*
be named "kfp-launcher". We currently deploy a default copy of the kfp-launcher
ConfigMap via DSPO, but a user may want to provide their own ConfigMap configuration,
so that they can specify multiple object storage sources and paths.

Add a `CustomKfpLauncherConfigMap` parameter to DSPA.ApiServer. When specified,
the `data` contents of the `kfp-launcher` ConfigMap that DSPO writes will be fully
replaced with the `data` contents of the ConfigMap specified here.

Fixes: https://issues.redhat.com/browse/RHOAIENG-4528

Co-authored-by: Achyut Madhusudan <amadhusu@redhat.com>
  • Loading branch information
gregsheremeta and Achyut Madhusudan committed Aug 6, 2024
1 parent c03a6ab commit 1f75522
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 1 deletion.
13 changes: 13 additions & 0 deletions api/v1alpha1/dspipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,19 @@ type APIServer struct {
// for the api server to use instead.
CustomServerConfig *ScriptConfigMap `json:"customServerConfigMap,omitempty"`

// When specified, the `data` contents of the `kfp-launcher` ConfigMap that DSPO writes
// will be fully replaced with the `data` contents of the ConfigMap specified here.
// This allows the user to fully replace the `data` contents of the kfp-launcher ConfigMap.
// The `kfp-launcher` component requires a ConfigMap to exist in the namespace
// where it runs (i.e. the namespace where pipelines run). This ConfigMap contains
// object storage configuration, as well as pipeline root (object store root path
// where artifacts will be uploaded) configuration. Currently this ConfigMap *must*
// be named "kfp-launcher". We currently deploy a default copy of the kfp-launcher
// ConfigMap via DSPO, but a user may want to provide their own ConfigMap configuration,
// so that they can specify multiple object storage sources and paths.
// +kubebuilder:validation:Optional
CustomKfpLauncherConfigMap string `json:"customKfpLauncherConfigMap,omitempty"`

// Default: true
// Deprecated: DSP V1 only, will be removed in the future.
// +kubebuilder:default:=true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,21 @@ spec:
description: 'Default: true Deprecated: DSP V1 only, will be removed
in the future.'
type: boolean
customKfpLauncherConfigMap:
description: When specified, the `data` contents of the `kfp-launcher`
ConfigMap that DSPO writes will be fully replaced with the `data`
contents of the ConfigMap specified here. This allows the user
to fully replace the `data` contents of the kfp-launcher ConfigMap.
The `kfp-launcher` component requires a ConfigMap to exist in
the namespace where it runs (i.e. the namespace where pipelines
run). This ConfigMap contains object storage configuration,
as well as pipeline root (object store root path where artifacts
will be uploaded) configuration. Currently this ConfigMap *must*
be named "kfp-launcher". We currently deploy a default copy
of the kfp-launcher ConfigMap via DSPO, but a user may want
to provide their own ConfigMap configuration, so that they can
specify multiple object storage sources and paths.
type: string
customServerConfigMap:
description: CustomServerConfig is a custom config file that you
can provide for the api server to use instead.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
apiVersion: v1
data:
{{ if .APIServer.CustomKfpLauncherConfigMap }}
{{.CustomKfpLauncherConfigMapData}}
{{ else }}
{{ if .ObjectStorageConnection.BasePath }}
defaultPipelineRoot: s3://{{.ObjectStorageConnection.Bucket}}/{{.ObjectStorageConnection.BasePath}}
{{ else }}
Expand All @@ -13,6 +16,7 @@ data:
secretName: {{.ObjectStorageConnection.CredentialsSecret.SecretName}}
accessKeyKey: {{.ObjectStorageConnection.CredentialsSecret.AccessKey}}
secretKeyKey: {{.ObjectStorageConnection.CredentialsSecret.SecretKey}}
{{ end }}
kind: ConfigMap
metadata:
name: kfp-launcher
Expand Down
1 change: 1 addition & 0 deletions config/samples/v2/dspa-all-fields/dspa_all_fields.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ metadata:
spec:
dspVersion: v2
apiServer:
customKfpLauncherConfigMap: configmapname
deploy: true
enableSamplePipeline: true
image: quay.io/opendatahub/ds-pipelines-api-server:latest
Expand Down
24 changes: 24 additions & 0 deletions controllers/dspipeline_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type DSPAParams struct {
Minio *dspa.Minio
MLMD *dspa.MLMD
WorkflowController *dspa.WorkflowController
CustomKfpLauncherConfigMapData string
DBConnection
ObjectStorageConnection

Expand Down Expand Up @@ -646,6 +647,29 @@ func (p *DSPAParams) ExtractParams(ctx context.Context, dsp *dspa.DataSciencePip
}
}

if p.APIServer.CustomKfpLauncherConfigMap != "" {
cm, err := util.GetConfigMap(ctx, p.APIServer.CustomKfpLauncherConfigMap, p.Namespace, client)
if err != nil {
if apierrs.IsNotFound(err) {
log.Info(fmt.Sprintf("ConfigMap referenced by CustomKfpLauncherConfig not found: [%s], Error: %v", p.APIServer.CustomKfpLauncherConfigMap, err))
return err
} else {
log.Info(fmt.Sprintf("Error fetching ConfigMap referenced by CustomKfpLauncherConfig: [%s], Error: %v", p.APIServer.CustomKfpLauncherConfigMap, err))
return err
}

} else {
// when setting a map into the `data` field of a ConfigMap, text/template works well with a json object
jsonData, err := json.Marshal(cm.Data)
if err != nil {
log.Info(fmt.Sprintf("Error reading data of ConfigMap referenced by CustomKfpLauncherConfig: [%s], Error: %v", p.APIServer.CustomKfpLauncherConfigMap, err))
return err
} else {
p.CustomKfpLauncherConfigMapData = string(jsonData)
}
}
}

// Track whether the "ca-bundle.crt" configmap key from odh-trusted-ca bundle
// was found, this will be used to decide whether we need to account for this
// ourselves later or not.
Expand Down
27 changes: 26 additions & 1 deletion controllers/dspipeline_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ limitations under the License.
package controllers

import (
"encoding/json"
"testing"

dspav1alpha1 "github.com/opendatahub-io/data-science-pipelines-operator/api/v1alpha1"
"github.com/opendatahub-io/data-science-pipelines-operator/controllers/testutil"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"testing"
)

type Client struct {
Expand Down Expand Up @@ -258,3 +260,26 @@ func TestExtractParams_CABundle(t *testing.T) {
func strPtr(v string) *string {
return &v
}

func TestExtractParams_WithCustomKfpLauncherConfigMap(t *testing.T) {
ctx, params, client := CreateNewTestObjects()
cmDataExpected := map[string]string{
"this-is-the-only-thing": "that-should-be-in-kfp-launcher-now",
}
cm := v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "my-custom-kfp-launcher",
Namespace: "testnamespace",
},
Data: cmDataExpected,
}
err := client.Create(ctx, &cm)
assert.Nil(t, err)

dspa := testutil.CreateDSPAWithCustomKfpLauncherConfigMap("my-custom-kfp-launcher")
err = params.ExtractParams(ctx, dspa, client.Client, client.Log)
assert.Nil(t, err)

cmDataExpectedJson, err := json.Marshal(cmDataExpected)
assert.Equal(t, string(cmDataExpectedJson), params.CustomKfpLauncherConfigMapData)
}
14 changes: 14 additions & 0 deletions controllers/testutil/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,17 @@ func CreateDSPAWithAPIServerPodtoPodTlsEnabled() *dspav1alpha1.DataSciencePipeli
func boolPtr(b bool) *bool {
return &b
}

func CreateDSPAWithCustomKfpLauncherConfigMap(configMapName string) *dspav1alpha1.DataSciencePipelinesApplication {
dspa := CreateEmptyDSPA()
dspa.Spec.DSPVersion = "v2"
// required, or we get an error because OCP certs aren't found
dspa.Spec.PodToPodTLS = boolPtr(false)
// required, or we get an error because this is required in v2
dspa.Spec.MLMD.Deploy = true
dspa.Spec.APIServer = &dspav1alpha1.APIServer{
Deploy: true,
CustomKfpLauncherConfigMap: configMapName,
}
return dspa
}

0 comments on commit 1f75522

Please sign in to comment.