Skip to content

feature: full-spectrum runtime Docker configuration #4965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Nov 1, 2018
Merged
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
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/src
/swagger-ui-dist-package
/test
/node_modules
20 changes: 11 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Looking for information on environment variables?
# We don't declare them here — take a look at our docs.
# https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md

FROM nginx:1.15-alpine

RUN apk add nodejs

LABEL maintainer="fehguy"

ENV VERSION "v2.2.10"
ENV FOLDER "swagger-ui-2.2.10"
ENV API_URL "https://petstore.swagger.io/v2/swagger.json"
ENV API_URLS ""
ENV API_KEY "**None**"
ENV OAUTH_CLIENT_ID "**None**"
ENV OAUTH_CLIENT_SECRET "**None**"
Expand All @@ -15,16 +17,16 @@ ENV OAUTH_ADDITIONAL_PARAMS "**None**"
ENV SWAGGER_JSON "/app/swagger.json"
ENV PORT 8080
ENV BASE_URL ""
ENV CONFIG_URL ""

COPY nginx.conf /etc/nginx/
COPY ./docker/nginx.conf /etc/nginx/

# copy swagger files to the `/js` folder
COPY ./dist/* /usr/share/nginx/html/
COPY ./docker-run.sh /usr/share/nginx/
COPY ./docker/run.sh /usr/share/nginx/
COPY ./docker/configurator /usr/share/nginx/configurator

RUN chmod +x /usr/share/nginx/docker-run.sh
RUN chmod +x /usr/share/nginx/run.sh

EXPOSE 8080

CMD ["sh", "/usr/share/nginx/docker-run.sh"]
CMD ["sh", "/usr/share/nginx/run.sh"]
4 changes: 2 additions & 2 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {

// Build a system
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
Expand All @@ -52,6 +51,7 @@
],
layout: "StandaloneLayout"
})
// End Swagger UI call region

window.ui = ui
}
Expand Down
40 changes: 40 additions & 0 deletions docker/configurator/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const fs = require("fs")
const path = require("path")

const translator = require("./translator")
const configSchema = require("./variables")

const START_MARKER = "// Begin Swagger UI call region"
const END_MARKER = "// End Swagger UI call region"

const targetPath = path.normalize(process.cwd() + "/" + process.argv[2])

const originalHtmlContent = fs.readFileSync(targetPath, "utf8")

const startMarkerIndex = originalHtmlContent.indexOf(START_MARKER)
const endMarkerIndex = originalHtmlContent.indexOf(END_MARKER)

const beforeStartMarkerContent = originalHtmlContent.slice(0, startMarkerIndex)
const afterEndMarkerContent = originalHtmlContent.slice(endMarkerIndex + END_MARKER.length)

fs.writeFileSync(targetPath, `${beforeStartMarkerContent}
${START_MARKER}
const ui = SwaggerUIBundle({
${indent(translator(process.env, { injectBaseConfig: true }), 8, 2)}
})
${END_MARKER}
${afterEndMarkerContent}`)

function indent(str, len, fromLine) {

return str
.split("\n")
.map((line, i) => {
if(i + 1 >= fromLine) {
return `${Array(len + 1).join(" ")}${line}`
} else {
return line
}
})
.join("\n")
}
93 changes: 93 additions & 0 deletions docker/configurator/translator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Converts an object of environment variables into a Swagger UI config object
const configSchema = require("./variables")

const baseConfig = {
url: {
value: "https://petstore.swagger.io/v2/swagger.json",
schema: {
type: "string"
}
},
dom_id: {
value: "#swagger-ui",
schema: {
type: "string"
}
},
deepLinking: {
value: "true",
schema: {
type: "boolean"
}
},
presets: {
value: `[\n SwaggerUIBundle.presets.apis,\n SwaggerUIStandalonePreset\n]`,
schema: {
type: "array"
}
},
plugins: {
value: `[\n SwaggerUIBundle.plugins.DownloadUrl\n]`,
schema: {
type: "array"
}
},
layout: {
value: "StandaloneLayout",
schema: {
type: "string"
}
}
}

function objectToKeyValueString(env, { injectBaseConfig = false, schema = configSchema } = {}) {
let valueStorage = injectBaseConfig ? Object.assign({}, baseConfig) : {}
const keys = Object.keys(env)

// Compute an intermediate representation that holds candidate values and schemas.
//
// This is useful for deduping between multiple env keys that set the same
// config variable.

keys.forEach(key => {
const varSchema = schema[key]
const value = env[key]

if(!varSchema) return

const storageContents = valueStorage[varSchema.name]

if(storageContents) {
if(varSchema.legacy === true) {
// If we're looking at a legacy var, it should lose out to any already-set value
return
}
delete valueStorage[varSchema.name]
}

valueStorage[varSchema.name] = {
value,
schema: varSchema
}
})

// Compute a key:value string based on valueStorage's contents.

let result = ""

Object.keys(valueStorage).forEach(key => {
const value = valueStorage[key]

const escapedName = /[^a-zA-Z0-9]/.test(key) ? `"${key}"` : key

if (value.schema.type === "string") {
result += `${escapedName}: "${value.value}",\n`
} else {
result += `${escapedName}: ${value.value === "" ? `undefined` : value.value},\n`
}
})

return result.trim()
}

module.exports = objectToKeyValueString
105 changes: 105 additions & 0 deletions docker/configurator/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
const standardVariables = {
CONFIG_URL: {
type: "string",
name: "configUrl"
},
DOM_ID: {
type: "string",
name: "dom_id"
},
SPEC: {
type: "object",
name: "spec"
},
URL: {
type: "string",
name: "url"
},
URLS: {
type: "array",
name: "urls"
},
URLS_PRIMARY_NAME: {
type: "string",
name: "urls.primaryName"
},
LAYOUT: {
type: "string",
name: "layout"
},
DEEP_LINKING: {
type: "boolean",
name: "deepLinking"
},
DISPLAY_OPERATION_ID: {
type: "boolean",
name: "displayOperationId"
},
DEFAULT_MODELS_EXPAND_DEPTH: {
type: "number",
name: "defaultModelsExpandDepth"
},
DEFAULT_MODEL_EXPAND_DEPTH: {
type: "number",
name: "defaultModelExpandDepth"
},
DEFAULT_MODEL_RENDERING: {
type: "string",
name: "defaultModelRendering"
},
DISPLAY_REQUEST_DURATION: {
type: "boolean",
name: "displayRequestDuration"
},
DOC_EXPANSION: {
type: "string",
name: "docExpansion"
},
FILTER: {
type: "string",
name: "filter"
},
MAX_DISPLAYED_TAGS: {
type: "number",
name: "maxDisplayedTags"
},
SHOW_EXTENSIONS: {
type: "boolean",
name: "showExtensions"
},
SHOW_COMMON_EXTENSIONS: {
type: "boolean",
name: "showCommonExtensions"
},
OAUTH2_REDIRECT_URL: {
type: "string",
name: "oauth2RedirectUrl"
},
SHOW_MUTATED_REQUEST: {
type: "boolean",
name: "showMutatedRequest"
},
SUPPORTED_SUBMIT_METHODS: {
type: "array",
name: "supportedSubmitMethods"
},
VALIDATOR_URL: {
type: "string",
name: "validatorUrl"
}
}

const legacyVariables = {
API_URL: {
type: "string",
name: "url",
legacy: true
},
API_URLS: {
type: "array",
name: "urls",
legacy: true
}
}

module.exports = Object.assign({}, standardVariables, legacyVariables)
File renamed without changes.
24 changes: 2 additions & 22 deletions docker-run.sh → docker/run.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#! /bin/sh

set -e

BASE_URL=${BASE_URL:-/}
NGINX_ROOT=/usr/share/nginx/html
INDEX_FILE=$NGINX_ROOT/index.html

node /usr/share/nginx/configurator $INDEX_FILE

replace_in_index () {
if [ "$1" != "**None**" ]; then
sed -i "s|/\*||g" $INDEX_FILE
Expand Down Expand Up @@ -40,27 +41,6 @@ if [[ -f $SWAGGER_JSON ]]; then
REL_PATH="./$(basename $SWAGGER_JSON)"
sed -i "s|https://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE
else
sed -i "s|https://petstore.swagger.io/v2/swagger.json|$API_URL|g" $INDEX_FILE
sed -i "s|http://example.com/api|$API_URL|g" $INDEX_FILE
fi

if [[ -n "$VALIDATOR_URL" ]]; then
sed -i "s|.*validatorUrl:.*$||g" $INDEX_FILE
TMP_VU="$VALIDATOR_URL"
[[ "$VALIDATOR_URL" != "null" && "$VALIDATOR_URL" != "undefined" ]] && TMP_VU="\"${VALIDATOR_URL}\""
sed -i "s|\(url: .*,\)|\1\n validatorUrl: ${TMP_VU},|g" $INDEX_FILE
unset TMP_VU
fi

# replace `url` with `urls` option if API_URLS is set
if [[ -n "$API_URLS" ]]; then
sed -i "s|^\(\s*\)url: .*,|\1urls: $API_URLS,|g" $INDEX_FILE
fi

if [[ -n "$CONFIG_URL" ]]; then
sed -i "s|^\(\s*\)url: .*,|\1configUrl: '$CONFIG_URL',|g" $INDEX_FILE
sed -i "s|^\(\s*\)urls: .*,|\1configUrl: '$CONFIG_URL',|g" $INDEX_FILE
fi

# replace the PORT that nginx listens on if PORT is supplied
Expand Down
Loading