Skip to content

Commit 4baf557

Browse files
author
Sean Sundberg
authored
Adds support for optional dependencies (#13)
* Adds optional fields to module dependency models * Checks for optional flag when getting source module * Handles resolution of optional module dependencies * Populates the output name from the BOM, if provided * Adds script to launch terraform env to apply output * Adds common services BOM Signed-off-by: Sean Sundberg <[email protected]>
1 parent a0a4109 commit 4baf557

File tree

11 files changed

+187
-22
lines changed

11 files changed

+187
-22
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ compiled
1111
.rpt2_cache
1212
docs
1313
output/
14+
credentials.properties

credentials.template

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Add the values for the Credentials to access the IBM Cloud
2+
# Instructions to access this information can be found in the README.MD
3+
classic.username=""
4+
classic.api.key=""
5+
ibmcloud.api.key=""
6+
# Authentication to OCP can either be performed with username/password or token
7+
# If token is provided it will take precedence
8+
login.user=""
9+
login.password=""
10+
login.token=""
11+
server.url=""

examples/common-services.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: cloud.ibm.com/v1alpha1
2+
kind: BillOfMaterial
3+
metadata:
4+
name: common-services
5+
spec:
6+
modules:
7+
- github.com/cloud-native-toolkit/terraform-ibm-access-group
8+
- github.com/cloud-native-toolkit/terraform-ibm-activity-tracker
9+
- github.com/cloud-native-toolkit/terraform-ibm-object-storage
10+
- github.com/cloud-native-toolkit/terraform-ibm-key-protect
11+
- github.com/cloud-native-toolkit/terraform-ibm-logdna
12+
- github.com/cloud-native-toolkit/terraform-ibm-vpc
13+
- github.com/cloud-native-toolkit/terraform-ibm-sysdig
14+
variables: []

launch.sh

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/bin/bash
2+
3+
# IBM Cloud Garage, Catalyst Team
4+
5+
SCRIPT_DIR="$(cd $(dirname $0); pwd -P)"
6+
SRC_DIR="$(cd "${SCRIPT_DIR}/output" ; pwd -P)"
7+
8+
DOCKER_IMAGE="quay.io/ibmgaragecloud/cli-tools:v0.12.0-lite"
9+
10+
helpFunction()
11+
{
12+
RED='\033[0;31m'
13+
CYAN='\033[0;36m'
14+
LIGHT_GRAY='\033[0;37m'
15+
GREEN='\033[0;32m'
16+
NC='\033[0m' # No Color
17+
18+
error="$1"
19+
20+
echo "Iteration Zero Setup"
21+
echo -e "This script will help setup setup a development environment and tools on the IBM Public Kubernetes Service"
22+
echo ""
23+
echo -e "${CYAN}Usage:${NC} $0"
24+
echo ""
25+
if [[ "${error}" =~ "file is not found" ]]; then
26+
echo -e "${RED}${error}${NC}"
27+
echo -e "Credentials should be provided in a file named ${CYAN}'${ENV}.properties'${NC}"
28+
else
29+
echo -e "${RED}${error}${NC}"
30+
echo -e "The ${ENV}.properties file should contain the following values:"
31+
echo -e " ${GREEN}ibmcloud.api.key${NC} is the IBM Cloud api key"
32+
echo -e " ${GREEN}classic.username${NC} is the Classic Infrastructure user name or API user name (e.g. [email protected])"
33+
echo -e " ${GREEN}classic.api.key${NC} is the Classic Infrastructure api key"
34+
fi
35+
36+
echo ""
37+
exit 1 # Exit script after printing help
38+
}
39+
40+
ENV="credentials"
41+
42+
function prop {
43+
grep "${1}" ${ENV}.properties | grep -vE "^#" | cut -d'=' -f2 | sed 's/"//g'
44+
}
45+
46+
if [[ -f "${ENV}.properties" ]]; then
47+
# Load the credentials
48+
IBMCLOUD_API_KEY=$(prop 'ibmcloud.api.key')
49+
CLASSIC_API_KEY=$(prop 'classic.api.key')
50+
CLASSIC_USERNAME=$(prop 'classic.username')
51+
LOGIN_USER=$(prop 'login.user')
52+
LOGIN_PASSWORD=$(prop 'login.password')
53+
LOGIN_TOKEN=$(prop 'login.token')
54+
SERVER_URL=$(prop 'server.url')
55+
else
56+
helpFunction "The ${ENV}.properties file is not found."
57+
fi
58+
59+
SUFFIX=$(echo $(basename ${SCRIPT_DIR}) | base64 | sed -E "s/[^a-zA-Z0-9_.-]//g" | sed -E "s/.*(.{5})/\1/g")
60+
CONTAINER_NAME="ibm-garage-cli-tools-${SUFFIX}"
61+
62+
echo "Cleaning up old container: ${CONTAINER_NAME}"
63+
64+
DOCKER_CMD="docker"
65+
${DOCKER_CMD} kill ${CONTAINER_NAME} 1> /dev/null 2> /dev/null
66+
${DOCKER_CMD} rm ${CONTAINER_NAME} 1> /dev/null 2> /dev/null
67+
68+
if [[ -n "$1" ]]; then
69+
echo "Pulling container image: ${DOCKER_IMAGE}"
70+
${DOCKER_CMD} pull "${DOCKER_IMAGE}"
71+
fi
72+
73+
echo "Initializing container ${CONTAINER_NAME} from ${DOCKER_IMAGE}"
74+
${DOCKER_CMD} run -itd --name ${CONTAINER_NAME} \
75+
-v ${SRC_DIR}:/home/devops/src \
76+
-e TF_VAR_ibmcloud_api_key="${IBMCLOUD_API_KEY}" \
77+
-e TF_VAR_login_user="${LOGIN_USER}" \
78+
-e TF_VAR_login_password="${LOGIN_PASSWORD}" \
79+
-e TF_VAR_login_token="${LOGIN_TOKEN}" \
80+
-e TF_VAR_server_url="${SERVER_URL}" \
81+
-e IBMCLOUD_API_KEY="${IBMCLOUD_API_KEY}" \
82+
-e IAAS_CLASSIC_USERNAME="${CLASSIC_USERNAME}" \
83+
-e IAAS_CLASSIC_API_KEY="${CLASSIC_API_KEY}" \
84+
-w /home/devops/src \
85+
${DOCKER_IMAGE}
86+
87+
echo "Attaching to running container..."
88+
${DOCKER_CMD} attach ${CONTAINER_NAME}

src/commands/iascable-build.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ export const builder = (yargs: Argv<any>) => {
4747
.option('name', {
4848
description: 'The name for the tile. Required if you want to generate the tile metadata.',
4949
demandOption: false,
50-
default: 'component'
5150
})
5251
.option('tileDescription', {
5352
description: 'The description of the tile.',
@@ -67,18 +66,20 @@ export const builder = (yargs: Argv<any>) => {
6766
export const handler = async (argv: Arguments<IascableInput & CommandLineInput>) => {
6867
process.env.LOG_LEVEL = argv.debug ? 'debug' : 'info';
6968

70-
console.log('Name:', argv.name);
71-
7269
const cmd: IascableApi = Container.get(IascableApi);
7370
const logger: LoggerApi = Container.get(LoggerApi).child('build');
7471

7572
const bom: BillOfMaterialModel | undefined = await loadBillOfMaterial(argv.input, argv.name);
73+
74+
const name = bom?.metadata?.name || 'component';
75+
console.log('Name:', name);
76+
7677
const options: IascableOptions = buildCatalogBuilderOptions(argv);
7778

7879
try {
7980
const result = await cmd.build(argv.catalogUrl, bom, options);
8081

81-
await outputResult(join('output', argv.name), result);
82+
await outputResult(join('output', name), result);
8283
} catch (err) {
8384
logger.error('Error building config', {err})
8485
}

src/errors/module-not-found.error.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
export class ModuleNotFound extends Error {
3-
constructor(readonly source: string) {
4-
super(`Unable to find module: ${source}`);
3+
constructor(readonly source: string, readonly module?: string) {
4+
super(`Unable to find module (${module}): ${source}`);
55
}
66
}
77

src/models/bill-of-material.model.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class BillOfMaterial implements BillOfMaterialModel {
7878
name: nameOrValue
7979
};
8080
} else {
81-
const metadata = Object.assign({}, nameOrValue.metadata, name ? {name} : {name: nameOrValue.metadata?.name || 'default'});
81+
const metadata = Object.assign({}, nameOrValue.metadata, name ? {name} : {name: nameOrValue.metadata?.name || 'component'});
8282

8383
Object.assign(this, nameOrValue, {metadata});
8484
}

src/models/module.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export function isSingleModuleVersion(module: Module | SingleModuleVersion): mod
4848
export interface ModuleDependency {
4949
id: string;
5050
refs: ModuleRef[];
51+
optional?: boolean;
5152
}
5253

5354
export interface ModuleVersion {

src/models/variables.model.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,27 @@ export class TerraformVariableImpl implements TerraformVariable {
171171
return '';
172172
}
173173

174-
const value = (this.type === 'bool' || this.type === 'number') ? this.defaultValue : `"${this.defaultValue}"`;
174+
const typeFormatter = getTypeFormatter(this.type);
175+
176+
const value = typeFormatter(this.defaultValue);
175177

176178
return `
177179
default = ${value}`;
178180
}
179181
}
182+
183+
const getTypeFormatter = (type: string) => {
184+
const formatter = typeFormatters[type] || defaultFormatter;
185+
186+
return formatter;
187+
}
188+
189+
const defaultFormatter: (value: string) => string = (value: string) => `"${value}"`;
190+
191+
const typeFormatters: {[type: string]: (value: string) => string} = {
192+
'bool': (value: string) => value,
193+
'number': (value: string) => value,
194+
// tslint:disable-next-line:triple-equals
195+
'list(string)': (value: any) => value == '' ? '[]' : value,
196+
'string': defaultFormatter,
197+
}

src/services/module-selector/selected-modules.model.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,15 @@ export class SelectedModules {
133133

134134
this.resolveModuleDependencies(depModule);
135135
} catch (error) {
136-
this.addMissingModule(moduleRef);
136+
if (!dep.optional) {
137+
this.addMissingModule(moduleRef);
138+
}
137139
}
138140
}
139141

140142
this.addModuleRef(moduleRef);
143+
} else if (moduleRefs.length === 0 && dep.optional) {
144+
// nothing to do
141145
} else if (moduleRefs.length === 0) {
142146
throw new Error(`Unable to find dependent module(s) (${moduleId}): ${dep.refs.map(r => r.source)}`);
143147
} else {

0 commit comments

Comments
 (0)