Skip to content

Commit f8f095f

Browse files
Closes #204 - Mounting nexus.properties in a ConfigMap (#212)
* Closes #204 - Mounting nexus.properties in a ConfigMap Signed-off-by: Ricardo Zanini <[email protected]> * Fixing Operatorr SDK install script Signed-off-by: Ricardo Zanini <[email protected]> * Fixing curl output Signed-off-by: Ricardo Zanini <[email protected]> * Incorporating java properties to Nexus CR Signed-off-by: Ricardo Zanini <[email protected]> * Lint fix and addheaders downgrade Signed-off-by: Ricardo Zanini <[email protected]> * Explicit set Red Hat image to Dockerbuild and fix permission issues Signed-off-by: Ricardo Zanini <[email protected]>
1 parent 239adff commit f8f095f

32 files changed

+647
-955
lines changed

.github/workflows/nexus-operator-integration-checks.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212
branches:
1313
- main
1414
env:
15-
OPERATOR_SDK_VERSION: v1.2.0
15+
OPERATOR_SDK_VERSION: v1.4.2
1616
GO_VERSION: 1.15
1717
jobs:
1818
golint:

Dockerfile

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Build the manager binary
2-
FROM golang:1.15 as builder
2+
# See Red Hat catalog: https://catalog.redhat.com/software/containers/ubi8/go-toolset/5ce8713aac3db925c03774d1?container-tabs=overview
3+
FROM registry.access.redhat.com/ubi8/go-toolset:1.15.14 as builder
34

45
WORKDIR /workspace
56
# Copy the Go Modules manifests
@@ -15,12 +16,14 @@ COPY api/ api/
1516
COPY controllers/ controllers/
1617
COPY pkg/ pkg/
1718

19+
USER root
1820
# Build
1921
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go
2022

2123
FROM registry.access.redhat.com/ubi8/ubi-minimal:latest
2224
WORKDIR /
2325
COPY --from=builder /workspace/manager .
26+
RUN chown -R 1001 manager
2427
USER 1001
2528

2629
ENTRYPOINT ["/manager"]

Makefile

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ K8S_VERSION=1.19.0
3939
test: generate-installer fmt vet bundle
4040
mkdir -p ${ENVTEST_ASSETS_DIR}
4141
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.6.3/hack/setup-envtest.sh # this is a workaround while we don't upgrade the sdk
42-
#sed -i "s,#\!.*,#\!\/bin\/bash,g" ${ENVTEST_ASSETS_DIR}/setup-envtest.sh
43-
#sed -i "/pipefail/d" ${ENVTEST_ASSETS_DIR}/setup-envtest.sh
4442
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; ENVTEST_K8S_VERSION=$(K8S_VERSION) fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./... -coverprofile cover.out
4543

4644
generate-installer: generate manifests kustomize

README.md

+17-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ Table of Contents
1717
* [Automatic Updates](#automatic-updates)
1818
* [Successful Updates](#successful-updates)
1919
* [Failed Updates](#failed-updates)
20+
* [Custom Configuration](#custom-configuration)
2021
* [Networking](#networking)
2122
* [Use NodePort](#use-nodeport)
2223
* [Network on OpenShift](#network-on-openshift)
23-
* [Network on Kubernetes 1.14+](#network-on-kubernetes-114)
24+
* [Network on Kubernetes 1.14 ](#network-on-kubernetes-114)
2425
* [NGINX Ingress troubleshooting](#nginx-ingress-troubleshooting)
2526
* [Ignoring external changes to Ingress/Route resources](#ignoring-external-changes-to-ingressroute-resources)
2627
* [TLS/SSL](#tlsssl)
@@ -235,6 +236,21 @@ $ kubectl get events
235236
9m45s Warning UpdateFailed nexus/nexus3 Failed to update to 3.26.1. Human intervention may be required
236237
# (output omitted)
237238
```
239+
## Custom Configuration
240+
241+
Starting on version 0.6.0, the operator now mounts a [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) with
242+
the contents of the [`nexus.properties`](https://help.sonatype.com/repomanager3/installation/configuring-the-runtime-environment) file
243+
in the path `$NEXUS_DATA/etc/nexus.properties`.
244+
245+
The Nexus Operator mount this file with the contents of the field `Spec.Properties` using [the Java properties format](https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader-).
246+
If you change this field, the operator will deploy a new pod _immediately_ to reflect the changes applied in the `ConfigMap`.
247+
248+
**Don't update** the managed `ConfigMap` directly, otherwise the operator will replace its contents with `Spec.Properties` field.
249+
Always use the Nexus CR as the only source of truth. See this [example](examples/nexus3-centos-no-volume-custom-properties.yaml) to
250+
learn how to properly set your properties directly in the CR.
251+
252+
> **Beware!** Since we don't support HA yet, the server will be unavailable until the next pod comes up. Try to update the configuration only
253+
> when you can afford to have the server unavailable.
238254
239255
## Networking
240256

RELEASE_NOTES.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
- \#205 - Provide a way to specify user-defined ingress annotations
66
- \#200 - OpenShift: Allow to configure "host" in the "route" manifest
77
- \#201 - Provide a way to specify a separate PVC for the blob store
8+
- \#204 - Feature request: allow setting settings in nexus.properties (feature flags, etc)
89

910
### Bug Fixes

api/v1alpha1/nexus_types.go

+6
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ type NexusSpec struct {
109109
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true
110110
// +optional
111111
ServerOperations ServerOperationsOpts `json:"serverOperations,omitempty"`
112+
113+
// Properties describes the configuration properties in the Java properties format that will be included in the nexus.properties file mounted with the Nexus server deployment.
114+
// For example: nexus.conan.hosted.enabled: true
115+
// +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true
116+
// +optional
117+
Properties map[string]string `json:"properties,omitempty"`
112118
}
113119

114120
// NexusPersistence is the structure for the data persistent

api/v1alpha1/zz_generated.deepcopy.go

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha1/zz_generated.openapi.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bundle.Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LABEL operators.operatorframework.io.bundle.manifests.v1=manifests/
55
LABEL operators.operatorframework.io.bundle.metadata.v1=metadata/
66
LABEL operators.operatorframework.io.bundle.package.v1=nexus-operator
77
LABEL operators.operatorframework.io.bundle.channels.v1=alpha
8-
LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.2.0
8+
LABEL operators.operatorframework.io.metrics.builder=operator-sdk-v1.4.2
99
LABEL operators.operatorframework.io.metrics.mediatype.v1=metrics+v1
1010
LABEL operators.operatorframework.io.metrics.project_layout=go.kubebuilder.io/v2
1111
LABEL operators.operatorframework.io.test.config.v1=tests/scorecard/

bundle/manifests/apps.m88i.io_nexus.yaml

+8-3
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ spec:
118118
exposeAs:
119119
description: 'Type of networking exposure: NodePort, Route or Ingress. Defaults to Route on OpenShift and Ingress on Kubernetes. Routes are only available on Openshift and Ingresses are only available on Kubernetes.'
120120
enum:
121-
- NodePort
122-
- Route
123-
- Ingress
121+
- NodePort
122+
- Route
123+
- Ingress
124124
type: string
125125
host:
126126
description: Host where the Nexus service is exposed. This attribute is required if the service is exposed via Ingress.
@@ -1074,6 +1074,11 @@ spec:
10741074
required:
10751075
- persistent
10761076
type: object
1077+
properties:
1078+
additionalProperties:
1079+
type: string
1080+
description: 'Properties describes the configuration properties in the Java properties format that will be included in the nexus.properties file mounted with the Nexus server deployment. For example: nexus.conan.hosted.enabled: true'
1081+
type: object
10771082
readinessProbe:
10781083
description: ReadinessProbe describes how the Nexus container readiness probe should work
10791084
properties:

bundle/manifests/nexus-operator.clusterserviceversion.yaml

+12-7
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ metadata:
3838
containerImage: quay.io/m88i/nexus-operator:0.6.0
3939
createdAt: "2019-11-16T13:12:22Z"
4040
description: Nexus Operator to deploy and manage Nexus 3.x servers
41-
operators.operatorframework.io/builder: operator-sdk-v1.2.0
41+
operators.operatorframework.io/builder: operator-sdk-v1.4.2
4242
operators.operatorframework.io/project_layout: go.kubebuilder.io/v2
4343
repository: https://github.com/m88i/nexus-operator
4444
support: m88i Labs
@@ -133,7 +133,12 @@ spec:
133133
- configmaps
134134
verbs:
135135
- create
136+
- delete
136137
- get
138+
- list
139+
- patch
140+
- update
141+
- watch
137142
- apiGroups:
138143
- ""
139144
resources:
@@ -296,13 +301,13 @@ spec:
296301
labels:
297302
name: nexus-operator
298303
links:
299-
- name: Documentation
300-
url: https://github.com/m88i/nexus-operator/blob/main/README.md
301-
- name: Nexus Operator source code repository
302-
url: https://github.com/m88i/nexus-operator
304+
- name: Documentation
305+
url: https://github.com/m88i/nexus-operator/blob/main/README.md
306+
- name: Nexus Operator source code repository
307+
url: https://github.com/m88i/nexus-operator
303308
maintainers:
304-
305-
name: m88i Labs
309+
310+
name: m88i Labs
306311
maturity: alpha
307312
provider:
308313
name: m88i Labs

bundle/metadata/annotations.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ annotations:
44
operators.operatorframework.io.bundle.mediatype.v1: registry+v1
55
operators.operatorframework.io.bundle.metadata.v1: metadata/
66
operators.operatorframework.io.bundle.package.v1: nexus-operator
7-
operators.operatorframework.io.metrics.builder: operator-sdk-v1.2.0
7+
operators.operatorframework.io.metrics.builder: operator-sdk-v1.4.2
88
operators.operatorframework.io.metrics.mediatype.v1: metrics+v1
99
operators.operatorframework.io.metrics.project_layout: go.kubebuilder.io/v2
1010
operators.operatorframework.io.test.config.v1: tests/scorecard/

config/crd/bases/apps.m88i.io_nexus.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,14 @@ spec:
16861686
required:
16871687
- persistent
16881688
type: object
1689+
properties:
1690+
additionalProperties:
1691+
type: string
1692+
description: 'Properties describes the configuration properties in the
1693+
Java properties format that will be included in the nexus.properties
1694+
file mounted with the Nexus server deployment. For example: nexus.conan.hosted.enabled:
1695+
true'
1696+
type: object
16891697
readinessProbe:
16901698
description: ReadinessProbe describes how the Nexus container readiness
16911699
probe should work

config/manifests/bases/nexus-operator.clusterserviceversion.yaml

+6-6
Original file line numberDiff line numberDiff line change
@@ -291,13 +291,13 @@ spec:
291291
labels:
292292
name: nexus-operator
293293
links:
294-
- name: Documentation
295-
url: https://github.com/m88i/nexus-operator/blob/main/README.md
296-
- name: Nexus Operator source code repository
297-
url: https://github.com/m88i/nexus-operator
294+
- name: Documentation
295+
url: https://github.com/m88i/nexus-operator/blob/main/README.md
296+
- name: Nexus Operator source code repository
297+
url: https://github.com/m88i/nexus-operator
298298
maintainers:
299-
300-
name: m88i Labs
299+
300+
name: m88i Labs
301301
maturity: alpha
302302
provider:
303303
name: m88i Labs

config/rbac/role.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,12 @@ rules:
6464
- configmaps
6565
verbs:
6666
- create
67+
- delete
6768
- get
69+
- list
70+
- patch
71+
- update
72+
- watch
6873
- apiGroups:
6974
- ""
7075
resources:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2021 Nexus Operator and/or its authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package deployment
16+
17+
import (
18+
corev1 "k8s.io/api/core/v1"
19+
20+
"github.com/m88i/nexus-operator/pkg/util"
21+
22+
"github.com/m88i/nexus-operator/api/v1alpha1"
23+
"github.com/m88i/nexus-operator/controllers/nexus/resource/meta"
24+
)
25+
26+
const nexusPropertiesFilename = "nexus.properties"
27+
28+
func newConfigMap(nexus *v1alpha1.Nexus) *corev1.ConfigMap {
29+
return &corev1.ConfigMap{
30+
ObjectMeta: meta.DefaultObjectMeta(nexus),
31+
Data: map[string]string{
32+
nexusPropertiesFilename: util.FromMapToJavaProperties(nexus.Spec.Properties),
33+
},
34+
}
35+
}

controllers/nexus/resource/deployment/deployment.go

+35-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
"strconv"
2121
"strings"
2222

23+
"github.com/m88i/nexus-operator/pkg/framework"
24+
2325
appsv1 "k8s.io/api/apps/v1"
2426
corev1 "k8s.io/api/core/v1"
2527
"k8s.io/apimachinery/pkg/api/resource"
@@ -46,7 +48,9 @@ const (
4648
heapSizeDefault = "1718m"
4749
maxDirectMemorySizeDefault = "2148m"
4850
nexusDataDir = "/nexus-data"
49-
nexusContainerName = "nexus-server"
51+
// see: https://help.sonatype.com/repomanager3/installation/configuring-the-runtime-environment
52+
nexusConfigFileMountPath = nexusDataDir + "/etc/" + nexusPropertiesFilename
53+
nexusContainerName = "nexus-server"
5054
)
5155

5256
var (
@@ -154,6 +158,7 @@ func addVolumes(nexus *v1alpha1.Nexus, deployment *appsv1.Deployment) {
154158
addInstallationVolume(nexus, deployment)
155159
}
156160
addExtraVolumes(nexus, deployment)
161+
addConfigMapVolume(nexus, deployment)
157162
}
158163

159164
func addInstallationVolume(nexus *v1alpha1.Nexus, deployment *appsv1.Deployment) {
@@ -188,6 +193,35 @@ func addExtraVolumes(nexus *v1alpha1.Nexus, deployment *appsv1.Deployment) {
188193
}
189194
}
190195

196+
func addConfigMapVolume(nexus *v1alpha1.Nexus, deployment *appsv1.Deployment) {
197+
volumeName := fmt.Sprintf("%s-config", nexus.Name)
198+
deployment.Spec.Template.Spec.Volumes =
199+
append(deployment.Spec.Template.Spec.Volumes, corev1.Volume{
200+
Name: volumeName,
201+
VolumeSource: corev1.VolumeSource{
202+
ConfigMap: &corev1.ConfigMapVolumeSource{
203+
LocalObjectReference: corev1.LocalObjectReference{
204+
Name: nexus.Name,
205+
},
206+
Items: []corev1.KeyToPath{
207+
{
208+
Key: nexusPropertiesFilename,
209+
Path: nexusPropertiesFilename,
210+
},
211+
},
212+
DefaultMode: &framework.ReadWritePermission,
213+
},
214+
},
215+
})
216+
deployment.Spec.Template.Spec.Containers[0].VolumeMounts =
217+
append(deployment.Spec.Template.Spec.Containers[0].VolumeMounts, corev1.VolumeMount{
218+
Name: volumeName,
219+
MountPath: nexusConfigFileMountPath,
220+
ReadOnly: false,
221+
SubPath: nexusPropertiesFilename,
222+
})
223+
}
224+
191225
func applyJVMArgs(nexus *v1alpha1.Nexus, deployment *appsv1.Deployment) {
192226
jvmMemory, directMemSize := calculateJVMMemory(deployment.Spec.Template.Spec.Containers[0].Resources.Limits)
193227
jvmArgsMap[jvmArgsXms] = jvmMemory

controllers/nexus/resource/deployment/deployment_test.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ func Test_newDeployment_WithoutPersistence(t *testing.T) {
5858
assert.Equal(t, int32(nexusContainerPort), deployment.Spec.Template.Spec.Containers[0].LivenessProbe.HTTPGet.Port.IntVal)
5959
assert.Equal(t, int32(nexusContainerPort), deployment.Spec.Template.Spec.Containers[0].ReadinessProbe.HTTPGet.Port.IntVal)
6060

61-
assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 0)
62-
assert.Len(t, deployment.Spec.Template.Spec.Volumes, 0)
61+
assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 1)
62+
assert.Len(t, deployment.Spec.Template.Spec.Volumes, 1)
63+
assert.Equal(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath, nexusConfigFileMountPath)
6364

6465
assert.Equal(t, appName, deployment.Labels[meta.AppLabel])
6566
assert.Equal(t, appName, deployment.Spec.Template.Labels[meta.AppLabel])
@@ -88,8 +89,8 @@ func Test_newDeployment_WithPersistence(t *testing.T) {
8889
deployment := newDeployment(nexus)
8990

9091
assert.Len(t, deployment.Spec.Template.Spec.Containers, 1)
91-
assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 1)
92-
assert.Len(t, deployment.Spec.Template.Spec.Volumes, 1)
92+
assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 2)
93+
assert.Len(t, deployment.Spec.Template.Spec.Volumes, 2)
9394
assert.Equal(t, nexusDataDir, deployment.Spec.Template.Spec.Containers[0].VolumeMounts[0].MountPath)
9495
}
9596

@@ -250,8 +251,8 @@ func Test_newDeployment_WithExtraVolumes(t *testing.T) {
250251
}
251252

252253
deployment := newDeployment(nexus)
253-
assert.Len(t, deployment.Spec.Template.Spec.Volumes, 2)
254-
assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 2)
254+
assert.Len(t, deployment.Spec.Template.Spec.Volumes, 3)
255+
assert.Len(t, deployment.Spec.Template.Spec.Containers[0].VolumeMounts, 3)
255256
assert.True(t, deploymentContainsNexusVolume(deployment, nexus.Spec.Persistence.ExtraVolumes[0]))
256257
assert.True(t, deploymentContainsNexusVolume(deployment, nexus.Spec.Persistence.ExtraVolumes[1]))
257258
}

0 commit comments

Comments
 (0)