Skip to content

Commit

Permalink
get variability inputs from env
Browse files Browse the repository at this point in the history
  • Loading branch information
milesstoetzner committed Aug 11, 2023
1 parent 8eeb6d7 commit b141544
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 36 deletions.
13 changes: 12 additions & 1 deletion docs/docs/contributing/notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,17 @@ word = ("a" ... "z" | "A" ... "Z")[word]
* = word
```

## Environment

All environment variables are prefixed by `OPENTOSCA_VINTNER_`.
When the following environment variables are read, they are tried to be parsed as JSON.
If they can not be parsed, they are treated as string.

- `OPENTOSCA_VINTNER_VARIABILITY_INPUT_${KEY}`
- `OPENTOSCA_VINTNER_DEPLOYMENT_INPUT_${KEY}`
- `OPENTOSCA_VINTNER_VARIABILITY_PRESETS`

These environment variables should be used with caution.

## Limitations

Expand All @@ -189,4 +200,4 @@ In the following, we briefly discuss limitations of our prototypical implementat
1. We expect that each relationship templates is used exactly once.
1. We expect that `relationship` at requirement assignments is a string.
1. We expect that names of hosting relations match `/^(.*_)?host(_.*)?$/` since we do not implement the TOSCA type system.
1. We expect that names of connection relations match `/^(.*_)?connection(_.*)?$/` since we do not implement the TOSCA type system.
1. We expect that names of connection relations match `/^(.*_)?connection(_.*)?$/` since we do not implement the TOSCA type system.
80 changes: 71 additions & 9 deletions docs/docs/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,35 @@ submit sensor data used for adapting the instance
| instance | true | string | instance name |
| inputs | true | InputAssignmentMap | sensor data |

## vintner instances clean

deletes all instances


=== "CLI"
```shell linenums="1"
vintner instances clean
```

=== "cURL"
```shell linenums="1"
curl --header "Content-Type: application/json" \
--request POST \
${SERVER_ADDRESS}/instances/clean
```

=== "JavaScript"
```javascript linenums="1"
const axios = require("axios")
await axios.post(SERVER_ADDRESS + "/instances/clean")
```

=== "Python"
```python linenums="1"
import requests
requests.post(SERVER_ADDRESS + "/instances/clean")
```

## vintner instances code

opens the instance directory in visual studio code
Expand Down Expand Up @@ -249,7 +278,7 @@ deploys instance
| Option | Mandatory | Type | Description |
| --- | --- | --- | --- |
| instance | true | string | instance name |
| inputs | false | string | path to the deployment inputs |
| inputs | false | string | path to the deployment inputs (env: OPENTOSCA_VINTNER_DEPLOYMENT_INPUT_${KEY}) |
| verbose | false | boolean | verbose |

## vintner instances info
Expand Down Expand Up @@ -465,8 +494,8 @@ resolves variability
| Option | Mandatory | Type | Description |
| --- | --- | --- | --- |
| instance | true | string | instance name |
| presets | false | string... | names of variability presets (default: []) |
| inputs | false | string | path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML]) |
| presets | false | string... | names of variability presets(env: OPENTOSCA_VINTNER_VARIABILITY_PRESETS) (default: []) |
| inputs | false | string | path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML], env: OPENTOSCA_VINTNER_VARIABILITY_INPUT_${KEY}) |

## vintner instances swap

Expand Down Expand Up @@ -618,7 +647,7 @@ update instance
| Option | Mandatory | Type | Description |
| --- | --- | --- | --- |
| instance | true | string | instance name |
| inputs | false | string | path to the deployment inputs |
| inputs | false | string | path to the deployment inputs (env: OPENTOSCA_VINTNER_DEPLOYMENT_INPUT_${KEY}) |
| verbose | false | boolean | verbose |

## vintner orchestrators enable
Expand Down Expand Up @@ -978,7 +1007,7 @@ cleans up the filesystem

=== "CLI"
```shell linenums="1"
vintner setup clean --force
vintner setup clean
```

=== "cURL"
Expand All @@ -1000,6 +1029,10 @@ cleans up the filesystem
requests.post(SERVER_ADDRESS + "/setup/clean")
```

| Option | Mandatory | Type | Description |
| --- | --- | --- | --- |
| force | false | boolean | force clean up |

## vintner setup code

opens the home directory in visual studio code
Expand Down Expand Up @@ -1348,8 +1381,8 @@ resolves variability
| Option | Mandatory | Type | Description |
| --- | --- | --- | --- |
| template | true | string | path to variable service template |
| presets | false | strings... | names of variability presets (default: []) |
| inputs | false | string | path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML]) |
| presets | false | strings... | names of variability presets (env: OPENTOSCA_VINTNER_VARIABILITY_PRESETS) (default: []) |
| inputs | false | string | path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML, env: OPENTOSCA_VINTNER_VARIABILITY_INPUT_<NAME>) |
| output | true | string | path of the output |

## vintner template stats
Expand Down Expand Up @@ -1469,6 +1502,35 @@ unpackages a CSAR
| template | true | string | path to variable service template |
| output | true | string | path of the output |

## vintner templates clean

removes all templates


=== "CLI"
```shell linenums="1"
vintner templates clean
```

=== "cURL"
```shell linenums="1"
curl --header "Content-Type: application/json" \
--request POST \
${SERVER_ADDRESS}/templates/clean
```

=== "JavaScript"
```javascript linenums="1"
const axios = require("axios")
await axios.post(SERVER_ADDRESS + "/templates/clean")
```

=== "Python"
```python linenums="1"
import requests
requests.post(SERVER_ADDRESS + "/templates/clean")
```

## vintner templates code

opens the template directory in visual studio code
Expand Down Expand Up @@ -1562,8 +1624,8 @@ imports a new template
| --- | --- | --- | --- |
| template | true | string | template name |
| path | true | string | path or link to the CSAR |
| git-repository | false | string | git repository to clone |
| git-checkout | false | string | git checkout to checkout after cloning |
| git-repository | false | string | git repository |
| git-checkout | false | string | git checkout |

## vintner templates inspect

Expand Down
18 changes: 12 additions & 6 deletions src/cli/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,11 @@ template
.command('resolve')
.description('resolves variability')
.requiredOption('--template <string>', 'path to variable service template')
.option('--presets [strings...]', 'names of variability presets', [])
.option('--inputs [string]', 'path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML])')
.option('--presets [strings...]', 'names of variability presets (env: OPENTOSCA_VINTNER_VARIABILITY_PRESETS)', [])
.option(
'--inputs [string]',
'path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML, env: OPENTOSCA_VINTNER_VARIABILITY_INPUT_<NAME>)'
)
.requiredOption('--output <string>', 'path of the output')
.action(
hae.exit(async options => {
Expand Down Expand Up @@ -491,8 +494,11 @@ instances
.command('resolve')
.description('resolves variability')
.requiredOption('--instance <string>', 'instance name')
.option('--presets [string...]', 'names of variability presets', [])
.option('--inputs [string]', 'path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML])')
.option('--presets [string...]', 'names of variability presets(env: OPENTOSCA_VINTNER_VARIABILITY_PRESETS)', [])
.option(
'--inputs [string]',
'path to the variability inputs (supported: [YAML, FeatureIDE ExtendedXML], env: OPENTOSCA_VINTNER_VARIABILITY_INPUT_${KEY})'
)
.action(
hae.exit(async options => {
await Controller.instances.resolve(options)
Expand All @@ -514,7 +520,7 @@ instances
.command('deploy')
.description('deploys instance')
.requiredOption('--instance <string>', 'instance name')
.option('--inputs [string]', 'path to the deployment inputs')
.option('--inputs [string]', 'path to the deployment inputs (env: OPENTOSCA_VINTNER_DEPLOYMENT_INPUT_${KEY})')
.option('--verbose [boolean]', 'verbose')
.action(
hae.exit(async options => {
Expand All @@ -537,7 +543,7 @@ instances
.command('update')
.description('update instance')
.requiredOption('--instance <string>', 'instance name')
.option('--inputs [string]', 'path to the deployment inputs')
.option('--inputs [string]', 'path to the deployment inputs (env: OPENTOSCA_VINTNER_DEPLOYMENT_INPUT_${KEY})')
.option('--verbose [boolean]', 'verbose')
.action(
hae.exit(async options => {
Expand Down
2 changes: 1 addition & 1 deletion src/controller/instances/continue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default async function (options: InstancesContinueOptions) {

await lock.try(instance.getLockKey(), async () => {
if (!instance.exists()) throw new Error(`Instance "${instance.getName()}" does not exist`)
if (options.inputs) instance.setServiceInputs(options.inputs, utils.now())
instance.setServiceInputs(utils.now(), options.inputs)
await Plugins.getOrchestrator().continue(instance, {verbose: options.verbose})
})
}
2 changes: 1 addition & 1 deletion src/controller/instances/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default async function (options: InstancesDeployOptions) {

await lock.try(instance.getLockKey(), async () => {
if (!instance.exists()) throw new Error(`Instance "${instance.getName()}" does not exist`)
if (options.inputs) instance.setServiceInputs(options.inputs, utils.now())
instance.setServiceInputs(utils.now(), options.inputs)
await Plugins.getOrchestrator().deploy(instance, {verbose: options.verbose})
})
}
2 changes: 1 addition & 1 deletion src/controller/instances/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default async function (options: InstanceResolveOptions) {
const result = await Resolver.resolve({
template: instance.loadVariableServiceTemplate(),
inputs: await Resolver.loadInputs(options.inputs),
presets: options.presets,
presets: Resolver.loadPresets(options.presets),
})

// Store used variability inputs
Expand Down
3 changes: 1 addition & 2 deletions src/controller/instances/update.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as check from '#check'
import Plugins from '#plugins'
import {Instance} from '#repository/instances'
import * as utils from '#utils'
Expand All @@ -9,6 +8,6 @@ export type InstancesUpdateOptions = {instance: string; inputs?: string; time?:
export default async function (options: InstancesUpdateOptions) {
const instance = new Instance(options.instance)
if (!instance.exists()) throw new Error(`Instance "${instance.getName()}" does not exist`)
if (check.isDefined(options.inputs)) instance.setServiceInputs(options.inputs, options.time ?? utils.now())
instance.setServiceInputs(options.time ?? utils.now(), options.inputs)
await Plugins.getOrchestrator().update(instance, {time: options.time, verbose: options.verbose})
}
3 changes: 2 additions & 1 deletion src/controller/template/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export default async function (options: TemplateResolveOptions) {
assert.isDefined(options.template, 'Template not defined')
if (check.isUndefined(options.output)) throw new Error(`Output not defined`)
const inputs = await Resolver.loadInputs(options.inputs)
const presets = Resolver.loadPresets(options.presets)
const template = files.loadYAML<ServiceTemplate>(options.template)
const result = await Resolver.resolve({template, inputs, presets: options.presets})
const result = await Resolver.resolve({template, inputs, presets})
files.storeYAML(options.output, result.template)
}
8 changes: 6 additions & 2 deletions src/repository/instances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,12 @@ export class Instance {
return template
}

setServiceInputs(path: string, time: number) {
files.copy(path, this.getServiceInputs(time))
setServiceInputs(time: number, path?: string) {
const inputs = utils.getPrefixedEnv('OPENTOSCA_VINTNER_DEPLOYMENT_INPUT_')
if (check.isDefined(path)) _.merge(inputs, files.loadYAML(path))
if (utils.isEmpty(inputs)) return this

files.storeYAML(this.getServiceInputs(time), inputs)
this.setInfo({...this.loadInfo(), service_inputs_timestamp: time})
return this
}
Expand Down
25 changes: 22 additions & 3 deletions src/resolver/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ import * as files from '#files'
import Graph from '#graph/graph'
import {ServiceTemplate} from '#spec/service-template'
import {InputAssignmentMap} from '#spec/topology-template'
import * as utils from '#utils'
import * as featureIDE from '#utils/feature-ide'
import * as _ from 'lodash'
import * as process from 'process'
import Checker from './checker'
import Solver from './solver'
import Transformer from './transformer'

export default {
resolve,
loadInputs,
loadPresets,
}

export type ResolveOptions = {
Expand Down Expand Up @@ -58,7 +62,22 @@ async function resolve(options: ResolveOptions): Promise<ResolveResult> {
}

async function loadInputs(file?: string) {
if (check.isUndefined(file)) return {}
if (file.endsWith('.xml')) return featureIDE.loadConfiguration(file)
return files.loadYAML<InputAssignmentMap>(file)
const inputs = utils.getPrefixedEnv('OPENTOSCA_VINTNER_VARIABILITY_INPUT_')

if (check.isDefined(file)) {
if (file.endsWith('.xml')) return featureIDE.loadConfiguration(file)
_.merge(inputs, files.loadYAML<InputAssignmentMap>(file))
}

return inputs
}

function loadPresets(presets: string[] = []): string[] {
if (utils.isEmpty(presets)) {
const entry = Object.entries(process.env).find(it => it[0] === 'OPENTOSCA_VINTNER_VARIABILITY_PRESETS')
if (!check.isDefined(entry)) return []
if (!check.isDefined(entry[1])) return []
return utils.looseParse(entry[1])
}
return presets
}
10 changes: 1 addition & 9 deletions src/utils/feature-ide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,7 @@ export async function loadConfiguration(file: string): Promise<InputAssignmentMa
`${effectiveFeatureName}_${overrideAttributeName ?? originalAttributeName}`
)

let value = attribute.$.value
try {
value = JSON.parse(value)
} catch (e) {
// Ignore
// Value will be treated as string
}

result[effectiveAttributeName] = value
result[effectiveAttributeName] = utils.looseParse(attribute.$.value)
})
})

Expand Down
22 changes: 22 additions & 0 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as check from '#check'
import day from '#utils/day'
import _ from 'lodash'
import process from 'process'

export function mapIsEmpty<K, V>(map: Map<K, V>) {
return map.size === 0
Expand Down Expand Up @@ -163,3 +164,24 @@ export function sumObjects(objects: {[key: string]: number}[]) {
return a
}, {})
}

export function looseParse(value: any) {
try {
return JSON.parse(value)
} catch (e) {
return value
}
}

export function getPrefixedEnv(prefix: string) {
return Object.entries(process.env).reduce<{[key: string]: any}>((acc, [key, value]) => {
if (!check.isDefined(value)) return acc
if (!key.startsWith(prefix)) return acc

const name = key.slice(prefix.length).toLowerCase()
const parsed = looseParse(value)

acc[name] = parsed
return acc
}, {})
}
Loading

0 comments on commit b141544

Please sign in to comment.