-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add JSON editor for schema-validated editing of configs (#340)
This adds a browser-based editor to view, edit and validate YAML and JSON config files in the configeditor/ subdirectory.
- Loading branch information
Showing
9 changed files
with
329 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ node_modules | |
yarn.lock | ||
package-lock.json | ||
public | ||
configeditor/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,5 +24,6 @@ test/ | |
.prettier* | ||
*release-please* | ||
*.md | ||
configeditor/ | ||
|
||
#!include:.gitignore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,3 +44,5 @@ kubernetes/**/resourcegroup.yaml | |
|
||
# Terratest | ||
.test-data | ||
|
||
configeditor/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<br /> | ||
<p align="center"> | ||
<h2 align="center">Autoscaler tool for Cloud Spanner</h2> | ||
<img alt="Autoscaler" src="../resources/BlogHeader_Database_3.max-2200x2200.jpg"> | ||
|
||
<p align="center"> | ||
Validating editor for Autoscaler configuration. | ||
<br /> | ||
<a href="../README.md">Home</a> | ||
· | ||
<a href="../src/scaler/README.md">Scaler component</a> | ||
· | ||
<a href="../src/poller/README.md">Poller component</a> | ||
· | ||
<a href="../src/forwarder/README.md">Forwarder component</a> | ||
· | ||
<a href="../terraform/README.md">Terraform configuration</a> | ||
· | ||
<a href="../terraform/README.md#Monitoring">Monitoring</a> | ||
</p> | ||
|
||
## Overview | ||
|
||
This directory contains a simple web-based autoscaler config file editor that | ||
validates that the JSON config is correct - both for JSON syntax errors and that | ||
the config has the correct set of parameters and values. | ||
|
||
For GKE configurations, a YAML ConfigMap equivalent is displayed below. | ||
|
||
While directly editing the YAML configMap for GKE is not supported, you | ||
can paste the configmap into the editor, and it will be converted to JSON for | ||
editing and validation. | ||
|
||
## Usage | ||
|
||
Build the editor and start the HTTP server on port `8080`: | ||
|
||
```sh | ||
npm run start-configeditor-server -- --port 8080 | ||
``` | ||
|
||
Then browse to `http://127.0.0.1:8080/` | ||
|
||
## Command line config validation | ||
|
||
The JSON and YAML configurations can also be validated using the command line: | ||
|
||
```sh | ||
npm install | ||
npm run validateConfigFile -- path/to/config_file | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#!/bin/bash | ||
# | ||
# Copyright 2024 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
# | ||
set -e | ||
|
||
SCRIPTDIR=$(dirname "$0") | ||
cd "$SCRIPTDIR" | ||
|
||
npm install --quiet | ||
mkdir -p build/vanilla-jsoneditor | ||
[[ ! -e build/vanilla-jsoneditor/standalone.js ]] && \ | ||
curl -o build/vanilla-jsoneditor/standalone.js \ | ||
https://cdn.jsdelivr.net/npm/vanilla-jsoneditor@0.23.8/standalone.js | ||
|
||
cp -r ../node_modules/js-yaml ../autoscaler-config.schema.json build/ | ||
|
||
[[ "$1" == "--quiet" ]] || cat <<EOF | ||
-------------------- | ||
Config editor built. | ||
-------------------- | ||
Open the following link in a browser to use the config editor | ||
file://$(pwd)/index.html | ||
or run: | ||
cd $(pwd) | ||
npx -y http-server -p 8080 -a 127.0.0.1 | ||
and then open http://127.0.0.1:8080 | ||
EOF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<!-- | ||
Copyright 2024 Google LLC | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
--> | ||
<head> | ||
<title>Autoscaler config file editor</title> | ||
<meta charset="utf-8" /> | ||
|
||
<script src="index.mjs" lang="javascript" type="module"></script> | ||
</head> | ||
|
||
<body> | ||
<h2>JSON Autoscaler config file editor</h2> | ||
<p>Copy/Paste your YAML or JSON autoscaler config in the editor below.</p> | ||
<p>The configuration will automatically be validated and any errors shown</p> | ||
<div id="loading"> | ||
Loading... | ||
<br /> | ||
If this Loading message does not disappear, check that you have run | ||
<tt>./build-configeditor.sh</tt> | ||
</div> | ||
<div id="jsoneditor" style="width: 95%; height: 600px"></div> | ||
<hr /> | ||
<h3>Equivalent GKE configmap YAML</h3> | ||
<textarea | ||
id="yamlequivalent" | ||
readonly="true" | ||
style="width: 90%; height: 400px; border: solid 2px slategray; margin-left: 53px" | ||
></textarea> | ||
<p> | ||
Powered by <a href="https://github.com/josdejong/svelte-jsoneditor">jsoneditoronline.org</a> | ||
</p> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
/** | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
/** | ||
* @fileoverview Support scripts for browser-based config editor. | ||
*/ | ||
|
||
// eslint-disable-next-line | ||
import { | ||
JSONEditor, | ||
createAjvValidator, | ||
renderJSONSchemaEnum, | ||
renderValue, | ||
} from "./build/vanilla-jsoneditor/standalone.js"; | ||
import schema from "./build/autoscaler-config.schema.json" with { type: "json" }; | ||
import * as JsYaml from "./build/js-yaml/dist/js-yaml.mjs"; | ||
|
||
/** @typedef {import("vanilla-jsoneditor").Content} Content */ | ||
|
||
/** @type {JSONEditor} */ | ||
let editor; | ||
|
||
/** | ||
* Checks if the JSON is valid, and if so, copy it to the YAML textarea. | ||
* | ||
* If it is not, but _is_ valid YAML, convert it to JSON and update both the | ||
* JSON editor and the YAML textarea. | ||
* | ||
* @param {Content} content | ||
* @param {Content} previousContent | ||
* @param {{ | ||
* contentErrors: import("vanilla-jsoneditor").ContentErrors | null, | ||
* patchResult: import("vanilla-jsoneditor").JSONPatchResult | null | ||
* }} changeStatus | ||
*/ | ||
function jsonEditorChangeHandler(newcontent, previousContent, changeStatus) { | ||
const yamlTextarea = document.getElementById("yamlequivalent"); | ||
|
||
if (changeStatus?.contentErrors?.parseError) { | ||
console.log( | ||
"jsonEditorChangeHandler - got JSON parsing errors %o", | ||
changeStatus.contentErrors, | ||
); | ||
if (newcontent.text?.search("\nkind: ConfigMap\n") >= 0) { | ||
// Check if it is valid YAML text to see if we need to convert it back | ||
// to JSON. | ||
try { | ||
const configMap = JsYaml.load(newcontent.text); | ||
if ( | ||
configMap && | ||
configMap.kind === "ConfigMap" && | ||
configMap.data && | ||
Object.values(configMap.data)[0] | ||
) { | ||
// The autoscaler ConfigMap data is YAML stored as text in a YAML, | ||
// so we need to re-parse the data object. | ||
const configMapData = JsYaml.load(Object.values(configMap.data)[0]); | ||
console.log("got yaml configMap data object: %o", configMapData); | ||
|
||
// Asynchronously update the content with the parsed configmap data. | ||
// This is because JSON editor likes to finish the onchange before | ||
// anything else happens! | ||
setTimeout(() => { | ||
/** @type {Content} */ | ||
const content = { json: configMapData }; | ||
editor.updateProps({ | ||
content, | ||
mode: "text", | ||
selection: null, | ||
}); | ||
editor.refresh(); | ||
// Trigger refresh of YAML textarea. | ||
updateYamlWithJsonContent(content); | ||
}, 100); | ||
return; | ||
} | ||
} catch (e) { | ||
console.log("not valid yaml " + e); | ||
} | ||
} | ||
// Some other unparsable JSON. | ||
yamlTextarea.setAttribute("disabled", "true"); | ||
} else { | ||
// Got valid JSON, even if it might not be valid Autoscaler config, we | ||
// update the YAML version. | ||
updateYamlWithJsonContent(newcontent); | ||
} | ||
} | ||
|
||
/** | ||
* Converts the content from JSONEditor to YAML and stores it in the YAML | ||
* textarea. | ||
* | ||
* @param {Content} content | ||
*/ | ||
function updateYamlWithJsonContent(content) { | ||
const yamlTextarea = document.getElementById("yamlequivalent"); | ||
yamlTextarea.removeAttribute("disabled"); | ||
const json = content.text ? JSON.parse(content.text) : content.json; | ||
|
||
const configMap = { | ||
apiVersion: "v1", | ||
kind: "ConfigMap", | ||
metadata: { | ||
name: "autoscaler-config", | ||
namespace: "spanner-autoscaler", | ||
}, | ||
data: { | ||
// Autoscaler configmap.data is YAML as text. | ||
"autoscaler-config.yaml": JsYaml.dump(json, { lineWidth: -1 }), | ||
}, | ||
}; | ||
yamlTextarea.value = JsYaml.dump(configMap, { lineWidth: -1 }); | ||
} | ||
|
||
/** | ||
* Handles addling rendering of Schema enums in JSONEditor. | ||
* | ||
* @param {import("vanilla-jsoneditor").RenderValueProps} props | ||
* @return {import("vanilla-jsoneditor").RenderValueComponentDescription[]} | ||
*/ | ||
function onRenderValue(props) { | ||
return renderJSONSchemaEnum(props, schema) || renderValue(props); | ||
} | ||
|
||
/** @type {Content} */ | ||
const EXAMPLE_CONFIG = { | ||
json: [ | ||
{ | ||
$comment: "Sample autoscaler config", | ||
projectId: "my-project", | ||
instanceId: "my-instance", | ||
units: "NODES", | ||
minSize: 1, | ||
maxSize: 3, | ||
stateDatabase: { | ||
name: "firestore", | ||
}, | ||
scalerPubSubTopic: "projects/my-project/topics/scaler-topic", | ||
}, | ||
], | ||
}; | ||
|
||
/** Handles DOMContentLoaded event. */ | ||
function onDOMContentLoaded() { | ||
editor = new JSONEditor({ | ||
target: document.getElementById("jsoneditor"), | ||
props: { | ||
content: EXAMPLE_CONFIG, | ||
mode: "text", | ||
schema, | ||
indentation: 2, | ||
validator: createAjvValidator({ schema }), | ||
onChange: jsonEditorChangeHandler, | ||
onRenderValue, | ||
}, | ||
}); | ||
updateYamlWithJsonContent(EXAMPLE_CONFIG); | ||
document.getElementById("loading").style.display = "none"; | ||
} | ||
|
||
document.addEventListener("DOMContentLoaded", onDOMContentLoaded, false); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters