UNCLASSIFIED

Commit 0074177c authored by Matt Vasquez's avatar Matt Vasquez
Browse files

Merge branch 'mdb-initial-153' into 'development'

Initial commit for the MongoDB Enterprise Ops Manager Init container

See merge request !1
parents 1b5c9947 9e5a597a
Pipeline #27008 passed with stage
# Dockerfile for Ops Manager init container.
ARG BASE_REGISTRY=nexus-docker-secure.levelup-nexus.svc.cluster.local:18082
ARG BASE_IMAGE=redhat/ubi/ubi7
ARG BASE_TAG=7.8
FROM golang:1.13 as builder
USER root
RUN mkdir /build
ADD . /build/
WORKDIR /build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -a -i -o ./output/mmsconfiguration ./mmsconfiguration
#####
FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG}
ARG VERSION
LABEL name="MongoDB Enterprise Ops Manager Init" \
maintainer="support@mongodb.com" \
vendor="MongoDB" \
version="mongodb-enterprise-init-ops-manager-${VERSION}" \
release="1" \
summary="MongoDB Enterprise Ops Manager Init Image" \
description="Startup Scripts for MongoDB Enterprise Ops Manager"
RUN mkdir /scripts && mkdir -p /licenses
COPY --from=builder /build/output/mmsconfiguration /scripts/
COPY scripts/docker-entry-point.sh /scripts/
COPY LICENSE /licenses/mongodb-enterprise-ops-manager
USER 2000
ENTRYPOINT [ "/bin/cp", "-f", "/scripts/docker-entry-point.sh", "/scripts/mmsconfiguration", "/opt/scripts/" ]
HEALTHCHECK --timeout=30s CMD ls /scripts/docker-entry-point.sh || exit 1
@Library('DCCSCR@master') _
dccscrPipeline(version: "1.5.3")
Usage of the MongoDB Enterprise Operator for Kubernetes indicates
agreement with the MongoDB Development, Test, and Evaluation Agreement
* https://www.mongodb.com/legal/evaluation-agreement
# MongoDB Ops Manager Init
# MongoDB Enterprise Ops Manager - Init Container #
Init container for MongoDB Enterprise Ops Manager. This container image is used exclusively by the MongoDB Enterprise Kubernetes Operator to deploy MongoDB Ops Manager to Kubernetes or OpenShift clusters.
For more information about MongoDB Ops Manager, please visit <https://www.mongodb.com/products/ops-manager>.
Information about MongoDB can be found at <https://www.mongodb.com>.
## Documentation ##
Documentation for MongoDB Ops Manager is available at <https://docs.opsmanager.mongodb.com/current/>.
Documentation for the MongoDB Enterprise Kubernetes Operator is available at <https://docs.mongodb.com/kubernetes-operator>.
{
"resources": [
{
"url": "docker://docker.io/golang@sha256:2841da2227dc15e18ca5ec1e95f3cb166005361c0eb0313ce82d2e5ccff116dd",
"tag": "golang:1.13"
}
]
}
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
const (
mmsJvmParamsVar = "JAVA_MMS_UI_OPTS"
backupDaemonJvmParamsVar = "JAVA_DAEMON_OPTS"
omPropertyPrefix = "OM_PROP_"
lineBreak = "\n"
commentPrefix = "#"
propOverwriteFmt = "%s=\"${%s} %s\""
backupDaemon = "BACKUP_DAEMON"
)
func updateConfFile(confFile string) error {
confFilePropertyName := mmsJvmParamsVar
if _, isBackupDaemon := os.LookupEnv(backupDaemon); isBackupDaemon {
confFilePropertyName = backupDaemonJvmParamsVar
}
customJvmParamsVar := "CUSTOM_" + confFilePropertyName
jvmParams, jvmParamsEnvVarExists := os.LookupEnv(customJvmParamsVar)
if !jvmParamsEnvVarExists || jvmParams == "" {
fmt.Printf("%s not specified, not modifying %s\n", customJvmParamsVar, confFile)
return nil
}
newMmsJvmParams := fmt.Sprintf(propOverwriteFmt, confFilePropertyName, confFilePropertyName, jvmParams)
fmt.Printf("Appending %s to %s\n", newMmsJvmParams, confFile)
err := appendLinesToFile(confFile, getJvmParamDocString()+newMmsJvmParams+lineBreak)
return err
}
func updatePropertiesFile(propertiesFile string) error {
newProperties := getOmPropertiesFromEnvVars()
// If there are no exported mms properties, we can stop here
if len(newProperties) == 0 {
return nil
}
lines, err := readLinesFromFile(propertiesFile)
if err != nil {
return err
}
lines = updateMmsProperties(lines, newProperties)
fmt.Printf("Updating configuration properties file %s\n", propertiesFile)
err = writeLinesToFile(propertiesFile, lines)
return err
}
func readLinesFromFile(name string) ([]string, error) {
input, err := ioutil.ReadFile(name)
if err != nil {
return nil, fmt.Errorf("error reading file %s: %v", name, err)
}
return strings.Split(string(input), lineBreak), nil
}
func writeLinesToFile(name string, lines []string) error {
output := strings.Join(lines, lineBreak)
err := ioutil.WriteFile(name, []byte(output), 0775)
if err != nil {
return fmt.Errorf("error writing to file %s: %v", name, err)
}
return nil
}
func appendLinesToFile(name string, lines string) error {
f, err := os.OpenFile(name, os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("error opening file %s: %v", name, err)
}
if _, err = f.WriteString(lines); err != nil {
return fmt.Errorf("error writing to file %s: %v", name, err)
}
err = f.Close()
return err
}
func getOmPropertiesFromEnvVars() map[string]string {
props := map[string]string{}
for _, pair := range os.Environ() {
if !strings.HasPrefix(pair, omPropertyPrefix) {
continue
}
p := strings.SplitN(pair, "=", 2)
key := strings.Replace(p[0], omPropertyPrefix, "", 1)
key = strings.ReplaceAll(key, "_", ".")
props[key] = p[1]
}
return props
}
func updateMmsProperties(lines []string, newProperties map[string]string) []string {
seenProperties := map[string]bool{}
// Overwrite existing properties
for i, line := range lines {
if strings.HasPrefix(line, commentPrefix) || !strings.Contains(line, "=") {
continue
}
key := strings.Split(line, "=")[0]
if newVal, ok := newProperties[key]; ok {
lines[i] = fmt.Sprintf("%s=%s", key, newVal)
fmt.Printf("Setting %s=%s\n", key, newVal)
seenProperties[key] = true
}
}
// Add new properties
for key, val := range newProperties {
if _, ok := seenProperties[key]; !ok {
lines = append(lines, fmt.Sprintf("%s=%s", key, val))
fmt.Printf("Added %s=%s\n", key, val)
}
}
return lines
}
func getJvmParamDocString() string {
commentMarker := strings.Repeat("#", 55)
return fmt.Sprintf("%s\n## This is the custom JVM configuration set by the Operator\n%s\n\n", commentMarker, commentMarker)
}
func main() {
if len(os.Args) < 3 {
fmt.Printf("Incorrect arguments %s, must specify path to conf file and path to properties file"+lineBreak, os.Args[1:])
os.Exit(1)
}
confFile := os.Args[1]
propertiesFile := os.Args[2]
if err := updateConfFile(confFile); err != nil {
fmt.Println(err)
os.Exit(1)
}
if err := updatePropertiesFile(propertiesFile); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
package main
import (
"fmt"
"io/ioutil"
"math/rand"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func TestEditMmsConfiguration_UpdateConfFile_Mms(t *testing.T) {
confFile := _createTestConfFile()
_ = os.Setenv("CUSTOM_JAVA_MMS_UI_OPTS", "-Xmx4000m -Xms4000m")
err := updateConfFile(confFile)
assert.NoError(t, err)
updatedContent := _readLinesFromFile(confFile)
assert.Equal(t, updatedContent[7], "JAVA_MMS_UI_OPTS=\"${JAVA_MMS_UI_OPTS} -Xmx4000m -Xms4000m\"")
}
func TestEditMmsConfiguration_UpdateConfFile_BackupDaemon(t *testing.T) {
confFile := _createTestConfFile()
_ = os.Setenv("BACKUP_DAEMON", "something")
_ = os.Setenv("CUSTOM_JAVA_DAEMON_OPTS", "-Xmx4000m -Xms4000m")
err := updateConfFile(confFile)
assert.NoError(t, err)
updatedContent := _readLinesFromFile(confFile)
assert.Equal(t, updatedContent[7], "JAVA_DAEMON_OPTS=\"${JAVA_DAEMON_OPTS} -Xmx4000m -Xms4000m\"")
}
func TestEditMmsConfiguration_UpdatePropertiesFile(t *testing.T) {
val := fmt.Sprintf("test%d", rand.Intn(1000))
key := "OM_PROP_test_edit_mms_configuration_get_om_props"
_ = os.Setenv(key, val)
props := getOmPropertiesFromEnvVars()
assert.Equal(t, props["test.edit.mms.configuration.get.om.props"], val)
_ = os.Unsetenv(key)
}
func TestEditMmsConfiguration_GetOmPropertiesFromEnvVars(t *testing.T) {
_ = os.Setenv("OM_PROP_mms_test_prop", "somethingNew")
_ = os.Setenv("OM_PROP_mms_test_prop_new", "400")
propFile := _createTestPropertiesFile()
err := updatePropertiesFile(propFile)
assert.NoError(t, err)
updatedContent := _readLinesFromFile(propFile)
assert.Equal(t, updatedContent[0], "mms.prop=1234")
assert.Equal(t, updatedContent[1], "mms.test.prop5=")
assert.Equal(t, updatedContent[2], "mms.test.prop=somethingNew")
assert.Equal(t, updatedContent[3], "mms.test.prop.new=400")
}
func _createTestConfFile() string {
contents := "JAVA_MMS_UI_OPTS=\"${JAVA_MMS_UI_OPTS} -Xmx4352m -Xss328k -Xms4352m -XX:NewSize=600m -Xmn1500m -XX:ReservedCodeCacheSize=128m -XX:-OmitStackTraceInFastThrow\"\n"
contents += "JAVA_DAEMON_OPTS= \"${JAVA_DAEMON_OPTS} -DMONGO.BIN.PREFIX=\"\n\n"
return _writeTempFileWithContent(contents, "conf")
}
func _createTestPropertiesFile() string {
contents := "mms.prop=1234\nmms.test.prop5=\nmms.test.prop=something"
return _writeTempFileWithContent(contents, "prop")
}
func _readLinesFromFile(name string) []string {
content, _ := ioutil.ReadFile(name)
return strings.Split(string(content), "\n")
}
func _writeTempFileWithContent(content string, prefix string) string {
tmpfile, _ := ioutil.TempFile("", prefix)
_, _ = tmpfile.WriteString(content)
_ = tmpfile.Close()
return tmpfile.Name()
}
#!/usr/bin/env bash
set -euo pipefail
# the function reacting on SIGTERM command sent by the container on its shutdown. Redirects the signal
# to the child process ("tail" in this case)
cleanup () {
echo "Caught SIGTERM signal."
kill -TERM "$child"
}
# we need to change the Home directory for current bash so that the gen key was found correctly
# (the key is searched in "${HOME}/.mongodb-mms/gen.key")
HOME=${MMS_HOME}
# Execute script that updates properties and conf file used to start ops manager
echo "Updating configuration properties file ${MMS_PROP_FILE} and conf file ${MMS_CONF_FILE}"
/opt/scripts/mmsconfiguration ${MMS_CONF_FILE} ${MMS_PROP_FILE}
if [[ -z ${BACKUP_DAEMON+x} ]]; then
echo "Starting Ops Manager"
${MMS_HOME}/bin/mongodb-mms start_mms || {
echo "Startup of Ops Manager failed with code $?"
if [[ -f ${MMS_LOG_DIR}/mms0-startup.log ]]; then
echo
echo "mms0-startup.log:"
echo
cat "${MMS_LOG_DIR}/mms0-startup.log"
fi
if [[ -f ${MMS_LOG_DIR}/mms0.log ]]; then
echo
echo "mms0.log:"
echo
cat "${MMS_LOG_DIR}/mms0.log"
fi
if [[ -f ${MMS_LOG_DIR}/mms-migration.log ]]; then
echo
echo "mms-migration.log"
echo
cat "${MMS_LOG_DIR}/mms-migration.log"
fi
exit 1
}
trap cleanup SIGTERM
tail -F -n 1000 "${MMS_LOG_DIR}/mms0.log" "${MMS_LOG_DIR}/mms0-startup.log" "${MMS_LOG_DIR}/mms-migration.log" &
else
echo "Starting Ops Manager Backup Daemon"
${MMS_HOME}/bin/mongodb-mms start_backup_daemon
trap cleanup SIGTERM
tail -F "${MMS_LOG_DIR}/daemon.log" &
fi
child=$!
wait "$child"
  • Pipeline Status: SUCCESS
    Branch: development

    graph LR
      0([setup]):::INTERNAL_SUCCESS --> 1([Import Artifacts]):::SUCCESS --> 2((/)):::INTERNAL_SUCCESS --> 3([Stage Artifacts]):::SUCCESS --> 4((/)):::INTERNAL_SUCCESS --> 5([Build]):::SUCCESS --> 6([Publish, Scan & Report]):::INTERNAL_NOT_BUILT
    
    classDef SUCCESS font-size:10px
    classDef FAILURE fill:#f44, font-size:10px
    classDef SKIPPED font-size:10px
    classDef ABORTED fill:#889, font-size:10px
    classDef INTERNAL_SUCCESS font-size:10px, stroke-dasharray: 2, 1
    classDef INTERNAL_FAILURE fill:#f44, font-size:10px, stroke-dasharray: 2, 1
    classDef INTERNAL_SKIPPED font-size:10px, stroke-dasharray: 2, 1
    classDef INTERNAL_ABORTED fill:#889, font-size:10px, stroke-dasharray: 2, 1
    
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment