This commit is contained in:
caes 2020-05-21 08:08:44 -04:00
commit 8f31113bdf
8 changed files with 2326 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
errors

89
README.md Normal file
View File

@ -0,0 +1,89 @@
# Adamocomp Data Parser
This library provides methods to interpret the adamocomp data file.
## Example Usage
``` javascript
const Parser = require('adamocomp/parser.js');
var parser = new Parser();
parser.get.data('gitlab repo').then(function(data){
// "data" contains all data for the gitlab deal
})
parser.get_formatted.data('gitlab repo').then(function(printable){
// Standard output as stringified json.
console.log(printable)
})
// parser.get_formatted.root('gitlab').then(function(str){
// console.log(str)
// }
// Output below
```
``` bash
node data_tool.js path "gitlab"
# ["gitlab"]
```
## Constructor Options
* `new Parser({options})`
| property | type | description | default |
|---|---|---|---|
| path | string | Path to data file | `${program_root}/data.json` |
## Methods
### `get.file()`
Type: async
Params: none
Returns: an object literal of the data file.
``` javascript
parser.get.file().then(function(file){
// 'file' is the entire data file
})
```
### `get.data(string)`
Type: async
| param | type | description |
|---|---|---|
| 1 | string | search string |
Returns: data tree underneath node corresponding to search string, if found, otherwise null.
``` javascript
parser.get.data(str).then(function(data){
console.log(JSON.stringify(data));
})
```
### `get.root(string)`
Type: async
| param | type | description |
|---|---|---|
| 1 | string | search string |
Returns: array of keys (directories) leading to deal, if found, or an empty array.
``` javascript
parser.get.root(str).then(function(nodes){
console.log(locations);
// ['gitlab']
})
```
### `get.list()`
Type: async
Params: none
Returns: array of all deployments in the environment.
``` javascript
parser.get.list().then(function(deployments){
console.log(location);
// ['gitlab', 'factorio/clusterio_host', 'factorio/factorio_host', etc.]
})
```
## Running Tests
`npm test`

1531
broker.sh Executable file

File diff suppressed because it is too large Load Diff

191
data-tool.js Executable file
View File

@ -0,0 +1,191 @@
#!/usr/bin/node
const Parser = require('./parser.js');
var parser = new Parser();
const yargs = require('yargs')
.scriptName("node data_tool.js")
.usage('$0 <cmd> [options] [args]')
.command(
'valid_deal [query]',
'Returns with exit code 0 if [query] matches'
+ ' at least one deal, otherwise 2.',
(yargs) => {
yargs.positional('query', {
type: 'string',
default: '',
describe: 'Key path.'
})
},
function(argv) {
parser.test
.valid_deal(argv.query)
.then(function(result) {
if (result) {
process.exit(0);
}
process.exit(2);
})
}
)
.command(
'valid_cluster [query]',
'Returns with exit code 0 if [query] matches'
+ ' at least one cluster, otherwise 2.',
(yargs) => {
yargs.positional('query', {
type: 'string',
default: '',
describe: 'Key path.'
})
},
function(argv) {
parser.test
.valid_cluster(argv.query)
.then(function(result) {
if (result) {
process.exit(0);
}
process.exit(2);
})
}
)
.command(
'valid_host [query]',
'Returns with exit code 0 if [query] matches'
+ ' at least one host, otherwise 2.',
(yargs) => {
yargs.positional('query', {
type: 'string',
default: '',
describe: 'Key path.'
})
},
function(argv) {
parser.test
.valid_host(argv.query)
.then(function(result) {
if (result) {
process.exit(0);
}
process.exit(2);
})
}
)
.command(
'get [query]',
'Prints an array of '.concat(
' paths matched by [query], or returns [].'
),
(yargs) => {
yargs.positional('query', {
type: 'string',
default: '',
describe: 'The key path to a datanode.'
})
},
function(argv) {
parser.get
.data(argv.query)
.then(function(arr) {
console.log(JSON.stringify(arr));
})
}
)
.command(
'root [query]',
'Returns json array of arrays of keys in order '.concat(
'locating query matches'
),
(yargs) => {
yargs.positional('query', {
type: 'string',
default: '',
describe: 'The key path to a datanode.'
})
},
function(argv) {
parser.get
.root(argv.query)
.then(function(arr) {
console.log(JSON.stringify(arr));
})
}
)
.command(
'path [query]',
'Returns array of paths under NAAS_HOME'
+ ' for each matching deal.',
(yargs) => {
yargs.positional('query', {
type: 'string',
default: '',
describe: 'The key path to a datanode.'
})
},
function(argv) {
parser.get
.path(argv.query)
.then(function(arr) {
console.log(JSON.stringify(arr));
})
}
)
.command(
'deals',
'Returns list of deals.',
function(argv) {
parser.get
.deals()
.then(function(arr) {
console.log(JSON.stringify(arr));
})
}
)
.command(
'hosts [query]',
'Returns list of hosts.',
(yargs) => {
yargs.positional('query', {
type: 'string',
default: '',
describe: 'The key path to a datanode.'
})
},
function(argv) {
parser.get
.host_list(argv.query)
.then(function(arr) {
console.log(JSON.stringify(arr));
})
}
)
.option(
'debug',
{
alias: 'd',
description: 'Print debug output (very verbose!)',
type: 'boolean',
global: true,
}
)
.option(
'path',
{
alias: 'p',
description: 'Path to data file.',
type: 'string',
global: true,
default: "/etc/adamocomp/data.json"
}
)
.help()
.argv;
if (yargs.path) {
parser.params.path = yargs.path;
}
if (yargs.debug) {
parser.params.debug_mode = yargs.debug;
}

200
data.json Normal file
View File

@ -0,0 +1,200 @@
{
"etc": {
"environment": [
"GITLAB_HOME=/opt/gitlab",
"ADAMOCOMP_HOME=/opt/adamocomp/",
"ADAMOCOMP_CONFDIR=/etc/adamocomp/"
]
},
"cmd": {
"shutdown": ["sudo shutdown now"]
},
"adamocomp": {
"repo": "sys/adamocomp.git",
"issue_path": "$ADAMOCOMP_HOME",
"suggest": [
"No git?"
]
},
"bash-logger": {
"repo": "sys/bash-logger.git",
"issue_path": "$ADAMOCOMP_HOME/bash-logger",
"run": "syslog.sh"
},
"gitlab": {
"repo": "sys/adamocomp.git",
"docker": {
"issue_path": "/opt/gitlab",
"image": "gitlab/gitlab-ce:latest",
"options": [
[
"--volume",
"/opt/gitlab/config:/etc/gitlab:Z",
"/opt/gitlab/logs:/var/log/gitlab:Z",
"/opt/gitlab/data:/var/opt/gitlab:Z"
],
[
"--publish",
"443:443",
"45000:45000",
"2222:22"
],
["--restart","always"],
["--hostname","gitlab.adamo.network"]
]
},
"suggest": [
"Running as a bootstrap."
]
},
"covid-data": {
"repo": "owid/covid-19-data/tree/master/public/data/ecdc",
"git_src": "https://github.com/",
"suggest": [
"Setup github retrieval."
]
},
"tmux-conf": {
"repo": "config/tmux-conf.git",
"issue_path": "~",
"issue_files": [".tmux.conf"]
},
"dictd": {
"apt": [
"install -y dict dictd dict-gcide dict-moby-thesaurus"
],
"systemctl": [
"enable dictd"
],
"bashrc": [
"alias thes='dict -d moby-thesaurus'",
"alias define='dict'"
],
"suggest": [
"Not debian?",
"No network?"
]
},
"list_matches": {
"repo": "function/list_matches.git",
"run": [
"list_matches.sh"
],
"suggest": [
"Use filenames.",
"One list element per line."
]
},
"adamonet": {
"britannia": {
"remote": {
"host": "britannia.adamonet",
"ports": {
"ssh": 22,
"znc": 31415
}
},
"local": {
"host": "localhost",
"ipv4": "207.148.15.96"
}
},
"internum": {
"clusterio": {
"integer": {
"remote": {
"host": "internum.adamonet",
"ports": {
"factorio": 49000
}
},
"local": {
"host": "factorarium.internum.adamonet",
"ports": {
"ssh": 22,
"factorio": 1000
}
}
},
"vacatium": {
"host": "integer.internum.adamonet",
"remote": {
"host": "internum.adamonet",
"ports": {
"factorio": 49001
}
},
"local": {
"host": "factorarium.internum.adamonet",
"ports": {
"ssh": 22,
"factorio": 1000
}
}
}
},
"austr": {
"remote": {
"host": "internum.adamonet",
"ports": {
"ssh": 40000,
"resilio-sync": 40001
}
},
"local": {
"host": "austr.internum.adamonet",
"ipv4": "192.168.6.150"
}
},
"syracusae": {
"remote": {
"host": "internum.adamonet",
"ports": {
"ssh": 46000,
"http": 46005
}
},
"local": {
"host": "syracusae.internum.adamonet",
"ipv4": "192.168.6.10"
}
},
"melita": {
"remote": {
"host": "internum.adamonet",
"ports": {
"ssh": 46001
}
},
"local": {
"ipv4": "192.168.6.20",
"host": "melita.internum.adamonet"
}
},
"factorarium": {
"remote": {
"host": "internum.adamonet",
"ports": {
"ssh": 46002
}
},
"local": {
"ipv4": "192.168.6.101",
"host": "factorarium.internum.adamonet"
}
},
"dockerpad": {
"remote": {
"host": "internum.adamonet",
"ports": {
"ssh": 46003
}
},
"local": {
"ipv4": "192.168.6.102",
"host": "dockerpad.internum.adamonet"
}
}
}
}
}

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "adamocomp",
"version": "0.0.1",
"description": "ballistic action library swiss-army knife",
"main": "parser.js",
"repository": {
"type": "git",
"url": "caes@git.adamonet:sys/adamocomp.git"
},
"author": "",
"dependencies": {
"yargs": "^15.3.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "ISC"
}

274
parser.js Normal file
View File

@ -0,0 +1,274 @@
'use strict';
const fs = require('fs');
function Parser(options) {
var self = this;
options = options || {};
function debug(message) {
if (self.params.debug_mode) {
console.log(`[DEBUG] ${message}`);
}
}
this.defaults = {
path : './data.json',
query_delim : '/',
debug_mode : false
}
this.params = Object.assign({}, self.defaults, options);
this.data = null;
this.test = {
'valid_deal' : function(query) {
return self.get.deals(query)
.then(function(data) {
if (query == "") return false;
if (data.length > 0) {
return true;
}
return false;
})
},
'valid_cluster' : function(query) {
return self.test.has_hosts(query)
},
'valid_host' : function(query) {
return self.test.has_hosts(query)
},
'has_hosts' : function(query) {
return self.get.hosts(query)
.then(host_list => {
if (query == "") return false;
debug("Host list: "+host_list);
if (host_list.length > 0) {
return true;
}
return false;
})
},
'is_object' : function(obj) {
return (typeof obj === 'object' && obj !== null);
}
}
this.xform = {
'query_str_to_arr' : function(str = "") {
if (!str || str == "" || str == '') {
debug("Transforming empty search string.");
return [];
}
var arr = str.split(self.params.query_delim);
var split_str=""
arr.forEach(term => {
split_str = split_str + " " + term;
})
arr = split_str.split(" ");
arr = arr.filter(term => term != '.');
arr = arr.filter(term => term != '');
debug("Query arr: "+arr);
return arr;
}
}
this.reduce = {
'once' : function(data = {},name = "") {
const addressed = self.address(data,[...name]);
return addressed.data;
},
'fuzzy' : function(data = {},names = []) {
if (!Array.isArray(names) || names.length < 1) {
return data;
}
var name = names.shift();
var result = self.reduce.once(data,name);
names.forEach(name => { result = [...result.map(tree => {
const matches = self.reduce.once(tree,name)
debug(matches);
return matches;
})]})
result.filter(obj => obj);
return result;
},
'exact' : function(data = {},names = []) {
if (!Array.isArray(names) || names.length < 1) {
return data;
}
const addressed = self.address(data,names);
debug("Reduced exact data: "+addressed);
return addressed.data;
}
}
this.address = function(data = {},names = []) {
if (!names || names.length < 1 || !data || data == {}) {
debug("nope");
return { paths: [['.']], data: [data] };
}
var match_paths = new Array();
var match_data = new Array();
var branches = new Array({
root: ".",
data: data
});
for(var i=0; i < branches.length; i++) {
const data = branches[i].data;
const root = branches[i].root;
for (const [name,value] of Object.entries(data)) {
if (self.test.is_object(value)) {
branches.push({
root: [...root,name],
data: value
});
}
if (name == names[0]) {
var match = data;
names.forEach(term => {
debug("Searching for term: "+term);
if (match && match[term]) {
match = match[term];
}
else { match = undefined }
});
if (match) {
const match_path=[...root]
match_paths.push(match_path)
match_data.push(match)
debug("match found:" +match_path+"; "+match);
}
}
}
}
return { paths: match_paths, data: match_data };
}
this.get = {
'raw' : function(){
return new Promise(function(resolve, reject){
if(!self.data){
fs.readFile(
self.params.path,
function(err, data) {
if(err) reject(err);
try {
JSON.parse(data);
self.data = JSON.parse(data)
resolve(self.data)
} catch(err){
reject(err)
}
}
)
} else {
resolve(self.data);
}
})
},
'reduced' : function(names = [],ascent = [],descent = []) {
return self.get.raw().then(entire_data => {
debug(`ascent: ${ascent}`);
debug(`names: ${names}`);
debug(`descent: ${descent}`);
if (names.length+ascent.length+descent.length<1) {
return entire_data;
}
const domain = self.reduce.fuzzy(entire_data,ascent);
const fence = self.reduce.exact(domain,names);
const product = self.reduce.fuzzy(fence,descent);
return product;
//return self.reduce.exact(entire_data,names);
})
},
'addressed' : function(names) {
return self.get.raw().then(entire_data => {
debug(`Addressing raw: ${JSON.stringify(names)}`);
return self.address(entire_data,names);
})
},
'deals' : function(query){
return self.get.addressed(
[...(self.xform.query_str_to_arr(query)),"repo"]
).then(addressed => { return addressed.paths; })
},
'hosts' : function(query){
return self.get.addressed(
[...(self.xform.query_str_to_arr(query))]
).then(cluster_data => {
debug("Cluster search data: "
+JSON.stringify(cluster_data))
const host_matches = cluster_data.data.map(data =>{
debug("Data in cluster: "+JSON.stringify(data))
const hosts = self.address(
data,
["remote","host"]
);
return hosts.paths;
})
return host_matches;
})
},
'host_list': function(query) {
return self.get.hosts(query).then(paths => {
const host_list = paths.map(path_list => {
const return_queries = path_list.map(path_arr => {
var query_str = "";
path_arr = path_arr.filter(e => e != '.');
path_arr.forEach(e => { query_str += e+" "; })
return query_str.trim();
})
return return_queries;
})
return host_list;
})
},
'root' : function(query){
return self.get.addressed(
[...(self.xform.query_str_to_arr(query))]
).then(addressed => { return addressed.paths; })
},
'path' : function(query) {
return self.get.root(query).then(roots => {
var paths = new Array();
debug(`Roots found: ${roots}`);
roots.forEach (
function(root, i, array) {
var str = "";
debug(`Formatting ${root}`);
root.forEach(
function(key,j,arr) {
debug(`${j}: ${key}`);
str = str + "/" + key;
}
)
debug(str);
var query_arr = query.split(" ");
query_arr.forEach(
function(term,j,arr) {
str = str + "/" + term;
})
str = str.slice(3)
paths.push(str);
}
);
return paths;
})
},
'cluster_data' : function(query) {
return self.get.reduced(
self.xform.query_str_to_arr(query),
["clusters"],
["ports","ssh"]
).then(data => { return data; })
},
'data' : function(query) {
return self.get.reduced(
self.xform.query_str_to_arr(query)
).then(data => { return data; })
}
}
};
module.exports = Parser;

21
test/test.js Normal file
View File

@ -0,0 +1,21 @@
const assert = require('assert');
const chai = require('chai');
const expect = require('chai').expect;
const fs = require('fs');
const Parser = require('../parser.js');
var parser = new Parser();
describe('Running tests:' , function() {
describe('Data file:', function(){
it('Attempting to read data file at ' + parser.params.path, function(done){
parser.get.file().then(function(data){
done()
}).catch(function(error){
done(error);
})
});
})
})