Skip to content

Commit

Permalink
Extend CreateOptions (#272)
Browse files Browse the repository at this point in the history
* Support split createOptions and createOptions as json object

* maxium chunck to 8

* update

* revert default template with object as createOptions to make compatiable with iotedgedev

* revert

* add size info in error
  • Loading branch information
adashen authored Oct 30, 2018
1 parent 6ec3811 commit ee89987
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 4 deletions.
3 changes: 3 additions & 0 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ export class Constants {
public static inputNamePattern = "input1,input2,input3";
public static moduleSchemaVersion = "$schema-version";
public static groupId = "groupId";

public static TwinValueMaxSize = 512;
public static TwinValueMaxChunks = 8;
}

export enum ContainerState {
Expand Down
52 changes: 52 additions & 0 deletions src/common/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,22 @@ export class Utility {
});
}

public static convertCreateOptions(deployment: any): any {
if (deployment) {
const moduleProperties = deployment.modulesContent.$edgeAgent["properties.desired"];
const systemModules = moduleProperties.systemModules;
if (systemModules) {
moduleProperties.systemModules = Utility.serializeCreateOptionsForEachModule(systemModules);
}
const modules = moduleProperties.modules;
if (modules) {
moduleProperties.modules = Utility.serializeCreateOptionsForEachModule(modules);
}
}

return deployment;
}

// Temp utility to sovle the compatibale issue because of the schema change in IoT Hub Service.
// moduleContent -> modulesContent
public static updateSchema(deployment: any): any {
Expand All @@ -459,6 +475,42 @@ export class Utility {
return deployment;
}

public static serializeCreateOptions(settings: any, createOptions: any): any {
let optionStr: string;
if (typeof createOptions === "string") {
optionStr = createOptions;
} else {
optionStr = JSON.stringify(createOptions);
}
const re = new RegExp(`.{1,${Constants.TwinValueMaxSize}}`, "g");
const options = optionStr.match(re);
if (options.length > Constants.TwinValueMaxChunks) {
throw new Error("Size of createOptions too big. The maxium size of createOptions is 4K");
}
options.map((value, index) => {
if (index === 0) {
settings.createOptions = value;
} else {
const formattedNumber = (`0${index}`).slice(-2);
settings[`createOptions${formattedNumber}`] = value;
}
});

return settings;
}

private static serializeCreateOptionsForEachModule(modules: any): any {
for (const key in modules) {
if (modules.hasOwnProperty(key)) {
const moduleVar = modules[key];
if (moduleVar.settings && moduleVar.settings.createOptions) {
moduleVar.settings = Utility.serializeCreateOptions(moduleVar.settings, moduleVar.settings.createOptions);
}
}
}
return modules;
}

private static getLocalRegistryState(): ContainerState {
try {
const isRunning = Executor.execSync("docker inspect registry --format='{{.State.Running}}'");
Expand Down
2 changes: 1 addition & 1 deletion src/container/containerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export class ContainerManager {
const moduleExpanded: string = Utility.expandModules(data, moduleToImageMap);
const exceptStr = ["$edgeHub", "$edgeAgent", "$upstream"];
const generatedDeployFile: string = Utility.expandEnv(moduleExpanded, ...exceptStr);
const dpManifest = Utility.updateSchema(JSON.parse(generatedDeployFile));
const dpManifest = Utility.convertCreateOptions(Utility.updateSchema(JSON.parse(generatedDeployFile)));
// generate config file
await fse.ensureDir(configPath);
await fse.writeFile(deployFile, JSON.stringify(dpManifest, null, 2), { encoding: "utf8" });
Expand Down
86 changes: 86 additions & 0 deletions test/utility.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,92 @@ suite("utility tests", () => {
.modules.samplemodule.settings.image, "test.az.io/filter:0.0.1-amd64");
}).timeout(60 * 1000);

test("convertCreateOptions", async () => {
const input: string = await fse.readFile(path.resolve(__dirname, "../../testResources/deployment.template.json"), "utf8");
let deployment = JSON.parse(input);
const oldOptionObj = deployment.modulesContent.$edgeAgent["properties.desired"].modules.tempSensor.settings.createOptions;
deployment = Utility.convertCreateOptions(deployment);
const depStr = JSON.stringify(deployment, null, 2);
assert.equal(
deployment.modulesContent.$edgeAgent["properties.desired"].systemModules.edgeAgent.settings.createOptions,
deployment.modulesContent.$edgeAgent["properties.desired"].systemModules.edgeHub.settings.createOptions,
);

const settings = deployment.modulesContent.$edgeAgent["properties.desired"].modules.tempSensor.settings;
assert.equal(settings.hasOwnProperty("createOptions"), true);
assert.equal(settings.hasOwnProperty("createOptions01"), true);
assert.equal(settings.hasOwnProperty("createOptions02"), true);

const optionString = settings.createOptions + settings.createOptions01 + settings.createOptions02;
const optionObj = JSON.parse(optionString);
for (const key in oldOptionObj) {
if (oldOptionObj.hasOwnProperty(key)) {
assert.equal(optionObj.hasOwnProperty(key), true);
}
}
assert.equal(optionObj.Env.length, oldOptionObj.Env.length);
assert.equal(JSON.stringify(optionObj.Env), JSON.stringify(oldOptionObj.Env));
}).timeout(60 * 1000);

test("serializeCreateOptions", async () => {
const hostPort: any = {
HostPort: "43",
};

const hostPorts50: any[] = Array(50).fill(hostPort);
const PortBindingsVal = {
"43/udp": hostPorts50,
"42/tcp": [{
HostPort: "42",
}],
};

const createOptionsVal = {
Env: ["k1=v1", "k2=v2", "k3=v3"],
HostConfig: {
PortBindings: PortBindingsVal,
},
};

let settings = {
image: "test",
createOptions: createOptionsVal,
};

settings = Utility.serializeCreateOptions(settings, createOptionsVal);
const outStr = JSON.stringify(settings);

const expected = "{\"image\":\"test\",\"createOptions\":\"{\\\"Env\\\":[\\\"k1=v1\\\",\\\"k2=v2\\\",\\\"k3=v3\\\"],"
+ "\\\"HostConfig\\\":{\\\"PortBindings\\\":{\\\"43/udp\\\":[{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostP\",\"createOptions01\":\"ort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},"
+ "{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"},{\\\"HostPort\\\":\\\"43\\\"}],\\\"42/tcp\\\":[{\\\"HostPort\\\":\\\"42\\\"}]}}}\"}";
assert.equal(outStr, expected);
}).timeout(60 * 1000);

test("serializeCreateOptionsShort", async () => {
const createOptionsVal = {
Env: ["k1=v1", "k2=v2", "k3=v3"],
};

let settings = {
image: "test",
createOptions: createOptionsVal,
};

settings = Utility.serializeCreateOptions(settings, createOptionsVal);
const outStr = JSON.stringify(settings);
const expected = "{\"image\":\"test\",\"createOptions\":\"{\\\"Env\\\":[\\\"k1=v1\\\",\\\"k2=v2\\\",\\\"k3=v3\\\"]}\"}";
assert.equal(outStr, expected);
}).timeout(60 * 1000);

test("getValidModuleName", () => {
let valid: string = Utility.getValidModuleName("test Space");
assert.equal(valid, "test_Space");
Expand Down
77 changes: 74 additions & 3 deletions testResources/deployment.template.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@
"type": "docker",
"settings": {
"image": "$AGENT",
"createOptions": "{}"
"createOptions": {
"HostConfig":{
"PortBindings":{
"5671/tcp":[{"HostPort":"5671"}],
"8883/tcp":[{"HostPort":"8883"}],
"443/tcp":[{"HostPort":"443"}]
}
}
}
}
},
"edgeHub": {
Expand All @@ -24,7 +32,7 @@
"restartPolicy": "always",
"settings": {
"image": "microsoft/azureiotedge-hub:1.0-preview",
"createOptions": "{}"
"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
}
}
},
Expand All @@ -36,7 +44,70 @@
"restartPolicy": "always",
"settings": {
"image": "$IMAGE",
"createOptions": "{}"
"createOptions": {
"Env": [
"abcdefghij0=00",
"abcdefghij1=01",
"abcdefghij2=02",
"abcdefghij3=03",
"abcdefghij4=04",
"abcdefghij5=05",
"abcdefghij6=06",
"abcdefghij7=07",
"abcdefghij8=08",
"abcdefghij9=09",
"abcdefghij10=10",
"abcdefghij11=11",
"abcdefghij12=12",
"abcdefghij13=13",
"abcdefghij14=14",
"abcdefghij15=15",
"abcdefghij16=16",
"abcdefghij17=17",
"abcdefghij18=18",
"abcdefghij19=19",
"abcdefghij20=20",
"abcdefghij22=21",
"abcdefghij22=22",
"abcdefghij23=23",
"abcdefghij24=24",
"abcdefghij25=25",
"abcdefghij26=26",
"abcdefghij27=27",
"abcdefghij28=28",
"abcdefghij29=29",
"abcdefghij30=30",
"abcdefghij31=31",
"abcdefghij32=32",
"abcdefghij33=33",
"abcdefghij34=34",
"abcdefghij35=35",
"abcdefghij36=36",
"abcdefghij37=37",
"abcdefghij38=38",
"abcdefghij39=39",
"abcdefghij40=40",
"abcdefghij41=41",
"abcdefghij42=42",
"abcdefghij43=43",
"abcdefghij44=44",
"abcdefghij45=45",
"abcdefghij46=46",
"abcdefghij47=47",
"abcdefghij48=48",
"abcdefghij49=49",
"abcdefghij50=50",
"abcdefghij51=51",
"abcdefghij52=52",
"abcdefghij53=53",
"abcdefghij54=54",
"abcdefghij55=55",
"abcdefghij56=56",
"abcdefghij57=57",
"abcdefghij58=58",
"abcdefghij59=59"
]
}
}
},
"samplemodule": {
Expand Down

0 comments on commit ee89987

Please sign in to comment.