Skip to content

THREESCALE-15877: Fix File.exists? in a default system ConfigMap - #1190

Merged
borisurbanik merged 1 commit into
3scale:masterfrom
mdujava:THREESCALE-15877-service-dicovery-config
Oct 13, 2026
Merged

borisurbanik merged 1 commit into
3scale:masterfrom
mdujava:THREESCALE-15877-service-dicovery-config

Conversation

@mdujava

@mdujava mdujava commented Aug 28, 2026 •

Copy link
Copy Markdown
Member

With upgrade to Ruby 3.3, File.exists was deprecated.

Reference: 3scale/porta#4129

Verification

Ran a quick test against the PR in an empty live cluster by:

  1. Install 3scale operator 2.16 from registry.redhat.io/redhat/redhat-operator-index:v4.22
  2. Deploy minimal 3scale:

This consists of 3 external databases, a dummy secret for S3 config and an APIManager CR.

export NAMESPACE=3scale-test
oc new-project $NAMESPACE
make cluster/create/system-mysql
make cluster/create/system-redis
make cluster/create/backend-redis

Create a minimal S3 config (it is not functional)

cat << EOF | oc create -f -
kind: Secret
apiVersion: v1
metadata:
  name: s3-credentials
  namespace: $NAMESPACE
data:
  AWS_ACCESS_KEY_ID: c29tZXRoaW5nCg==
  AWS_BUCKET: c29tZXRoaW5nCg==
  AWS_REGION: dXMtd2VzdC0xCg==
  AWS_SECRET_ACCESS_KEY: c29tZXRoaW5nCg==
type: Opaque
EOF

Create a minimal APIManager CR which will deploy 3scale environment.

DOMAIN=$(oc get routes console -n openshift-console -o json | jq -r '.status.ingress[0].routerCanonicalHostname' | sed 's/router-default.//')
cat << EOF | oc create -f -
kind: APIManager
apiVersion: apps.3scale.net/v1alpha1
metadata:
  name: 3scale
  namespace: $NAMESPACE
spec:
  wildcardDomain: $DOMAIN
  system:
    fileStorage:
      simpleStorageService:
        configurationSecretRef:
          name: s3-credentials
  backend:
  externalComponents:
    backend:
      redis: true
    system:
      database: true
      redis: true
EOF

Verified that on 2.16 there is an UI element to select "import from openshift"

image
% oc get cm system -o json | jq -r '.data["service_discovery.yml"]'
production:
  enabled: <%= cluster_token_file_exists = File.exists?(cluster_token_file_path = '/var/run/secrets/kubernetes.io/serviceaccount/token') %>
  server_scheme: 'https'
  server_host: 'kubernetes.default.svc.cluster.local'
  server_port: 443
  bearer_token: "<%= File.read(cluster_token_file_path) if cluster_token_file_exists %>"
  authentication_method: service_account # can be service_account|oauth
  oauth_server_type: builtin # can be builtin|rh_sso
  client_id:
  client_secret:
  timeout: 1
  open_timeout: 1
  max_retry: 5
  verify_ssl: <%= OpenSSL::SSL::VERIFY_NONE %> # 0

After uninstalling of the operator and running this branch manually, there was no change to the value.

It's confirmed that after upgrade the screen will no longer display selection for "import from openshift":

image

Once the manual fix is applied:

  1. update config map system to change File.exists -> File.exist
  2. restart system-app oc rollout restart deployment system-app
image

@mdujava
mdujava requested a review from a team as a code owner August 28, 2026 09:58
@briangallagher

briangallagher commented Aug 28, 2026 •

Copy link
Copy Markdown
Contributor

✅ Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
✅ Open Source Security 0 0 0 0 0 issues
✅ Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@borisurbanik borisurbanik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdujava the fix here LGTM for new installation

I had a look at the JIRA issue, it seems to come from alpha testing.

From another look at the reconciler - and when you update the "model" here - so on new deployment you will get the right configmap, but the reconciler is very specific for this system map and it only handles creating configmap where it doesn't exist, or updating Zync endpoint (see

func systemConfigMapMutator(existingObj, desiredObj k8sclient.Object) (bool, error) {
existing, ok := existingObj.(*corev1.ConfigMap)
if !ok {
return false, fmt.Errorf("%T is not a *v1.ConfigMap", existingObj)
}
desired, ok := desiredObj.(*corev1.ConfigMap)
if !ok {
return false, fmt.Errorf("%T is not a *v1.ConfigMap", desiredObj)
}
zyncFieldKey := "zync.yml"
desiredZyncConfigString := desired.Data[zyncFieldKey]
existingZyncConfigString := existing.Data[zyncFieldKey]
// Define a struct to unmarshal the YAML into
type ZyncConfig struct {
Production struct {
Endpoint string `yaml:"endpoint"`
Authentication struct {
Token string `yaml:"token"`
} `yaml:"authentication"`
ConnectTimeout int `yaml:"connect_timeout"`
SendTimeout int `yaml:"send_timeout"`
ReceiveTimeout int `yaml:"receive_timeout"`
RootURL string `yaml:"root_url"`
} `yaml:"production"`
}
// Unmarshal the desiredZyncConfig
var desiredZyncConfig ZyncConfig
err := yaml.Unmarshal([]byte(desiredZyncConfigString), &desiredZyncConfig)
if err != nil {
log.Fatalf("error: %v", err)
}
// Extract the desiredEndpoint
desiredEndpoint := desiredZyncConfig.Production.Endpoint
// Update the endpoint in existingConfig with the one from desiredConfig
re := regexp.MustCompile(`(?m)^ *endpoint: '.*'`)
reconciledZyncConfigString := re.ReplaceAllString(existingZyncConfigString, fmt.Sprintf(" endpoint: '%s'", desiredEndpoint))
// Assign reconciledZyncConfigString to the ConfigMap's data
desired.Data[zyncFieldKey] = reconciledZyncConfigString
// Update the zync.yml field in the ConfigMap
updated := reconcilers.ConfigMapReconcileField(desired, existing, "zync.yml")
return updated, nil
}
)

I can approve this change to unblock testing - but it would be ideal to address also the upgrade path in the same PR.

@mdujava

mdujava commented Aug 28, 2026

Copy link
Copy Markdown
Member Author

but it would be ideal to address also the upgrade path in the same PR.

Do you think its safe to update this automatically or would we require manual step instead?

@borisurbanik

Copy link
Copy Markdown
Contributor

but it would be ideal to address also the upgrade path in the same PR.

Do you think its safe to update this automatically or would we require manual step instead?

This file looks like it's a template that needs to be filled out by customers to make it fully work - does our test fixture do any modifications to it after deployment / would that form normally work even without customers setting up client_id/secret for example? Could you test whether the functionality changes for customers that have the default configmap who never edited it?

The docs on this instruct customers go generate a configuration file that doesn't have any of this so I'd say manual note should be sufficient.

@codecov-commenter

codecov-commenter commented Aug 28, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 44.67%. Comparing base (c59a4c8) to head (242e2b3).
⚠️ Report is 20 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1190      +/-   ##
==========================================
+ Coverage   44.03%   44.67%   +0.63%     
==========================================
  Files         204      208       +4     
  Lines       20960    21227     +267     
==========================================
+ Hits         9230     9483     +253     
- Misses      10933    10944      +11     
- Partials      797      800       +3     
Flag Coverage Δ
unit 44.67% <100.00%> (+0.63%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
apis/apps/v1alpha1 (u) 63.56% <ø> (ø)
apis/capabilities/v1alpha1 (u) 3.50% <ø> (ø)
apis/capabilities/v1beta1 (u) 20.21% <ø> (ø)
controllers (i) 12.61% <82.35%> (+0.52%) ⬆️
pkg (u) 64.26% <92.80%> (+0.56%) ⬆️
Files with missing lines Coverage Δ
pkg/3scale/amp/component/system.go 83.41% <100.00%> (+0.56%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

With upgrade to Ruby 3.3, `File.exists` was deprecated.

Reference: 3scale/porta#4129
@mdujava
mdujava force-pushed the THREESCALE-15877-service-dicovery-config branch from a615c8e to 242e2b3 Compare October 9, 2026 09:34
@borisurbanik
borisurbanik merged commit 75e8fa1 into 3scale:master Oct 13, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants