Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add output path option for generate deployment manifest task #10607

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
"loc.input.help.defaultPlatform": "In your **.template.json**, you can leave the modules platform unspecified. For these modules, the **default platform** will be used.",
"loc.input.label.fillRegistryCredential": "Add registry credential to deployment manifest",
"loc.input.help.fillRegistryCredential": "Add registry credential for pushing docker images to deployment manifest",
"loc.input.label.deploymentManifestOutputPath": "Output path",
"loc.input.help.deploymentManifestOutputPath": "The output path of generated deployment manifest",
"loc.input.label.bypassModules": "Bypass module(s)",
"loc.input.help.bypassModules": "Select the module(s) that you **DO NOT** need to build(or push) in the .template.json, specify module names and separate with comma.\n Example: if you have 2 modules **SampleModule1,SampleModule2** in your .template.json, you want to just build or push **SampleModule1**, then you set the bypass modules as **SampleModule2**. Leave empty if you would like to build all the modules in .template.json.",
"loc.messages.BuildingModules": "Building module images...",
Expand All @@ -57,7 +59,7 @@
"loc.messages.DependencyInstallSuccess": "%s installed with version: %s",
"loc.messages.DependencyInstallFail": "%s installation failed, see detailed error in debug mode",
"loc.messages.TemplateFileInvalid": "The path of template file is not valid: %s",
"loc.messages.ContainerRegistryInvalid": "Failed to fetch container registry authentication token, please check you container registry setting in build task. The token is %s",
"loc.messages.ContainerRegistryInvalid": "Failed to fetch container registry authentication token, please check you container registry setting in build task. The username for container registry is %s",
"loc.messages.DeploymentFileNotFound": "Deployment file can't be found. Please ensure Path of deployment file is correctly set in the task.",
"loc.messages.ValidDeploymentFileNotFound": "Cannot find a valid deployment file. Please ensure Path of deployment file is correctly set in the task.",
"loc.messages.AzureSdkNotFound": "Azure SDK not found",
Expand All @@ -66,5 +68,9 @@
"loc.messages.InvalidRegistryCredentialWarning": "Failed to login %s with given credential. %s",
"loc.messages.CheckModuleImageExistenceError": "%s does not exist or the credential is not set correctly. Error: %s",
"loc.messages.StartGenerateDeploymentManifest": "Start generating deployment manifest...",
"loc.messages.FinishGenerateDeploymentManifest": "Finished generating deployment manifest."
"loc.messages.FinishGenerateDeploymentManifest": "Finished generating deployment manifest.",
"loc.messages.LoginRegistrySucess": "Successfully logged in to registry %s",
"loc.messages.SkipSettingEnvironmentVariable": "The environment variable %s already exists. Skip setting this environment variable.",
"loc.messages.SkipSettingEnvironmentVariableForSecret": "Environment variable %s already exist. Skip setting environment varialbe for secret: %s.",
"loc.messages.OverrideDeploymentManifestOutputPath": "The %s environment variable will be overriden by the output path parameter."
}
18 changes: 5 additions & 13 deletions Tasks/AzureIoTEdgeV2/buildimage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,13 @@ export async function run() {

util.setupIotedgedev();

let envList = {
[Constants.iotedgedevEnv.deploymentFileOutputFolder]: tl.getVariable(Constants.outputFileFolder),
};
let envList = process.env;
util.setEnvrionmentVarialbe(envList, Constants.iotedgedevEnv.deploymentFileOutputFolder, tl.getVariable(Constants.outputFileFolder));
blackchoey marked this conversation as resolved.
Show resolved Hide resolved

// Pass task variable to sub process
let tlVariables = tl.getVariables();
for (let v of tlVariables) {
// The variables in VSTS build contains dot, need to convert to underscore.
let name = v.name.replace('.', '_').toUpperCase();
if (!envList[name]) {
envList[name] = v.value;
}
}
util.populateSecretToEnvironmentVariable(envList);

tl.debug(`Following variables will be passed to the iotedgedev command: ${JSON.stringify(envList)}`);
tl.debug(`Following variables will be passed to the iotedgedev command: ${Object.keys(envList).join(", ")}`);

let outputStream: EchoStream = new EchoStream();

Expand All @@ -49,7 +41,7 @@ export async function run() {
let outLog: string = outputStream.content;
let filterReg: RegExp = /Expanding '[^']*' to '([^']*)'/g;
let matches: RegExpMatchArray = filterReg.exec(outLog);
if(matches && matches[1]) {
if (matches && matches[1]) {
tl.setVariable(Constants.outputVariableDeploymentPathKey, matches[1]);
tl.setVariable('_' + Constants.outputVariableDeploymentPathKey, matches[1]);
tl.debug(`Set ${Constants.outputVariableDeploymentPathKey} to ${matches[1]}`);
Expand Down
3 changes: 2 additions & 1 deletion Tasks/AzureIoTEdgeV2/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default class Constants {
registryUsername: "CONTAINER_REGISTRY_USERNAME",
registryPassword: "CONTAINER_REGISTRY_PASSWORD",
bypassModules: "BYPASS_MODULES",
deploymentFileOutputPath: "DEPLOYMENT_CONFIG_FILE",
deploymentFileOutputName: "DEPLOYMENT_CONFIG_FILE",
deploymentFileOutputFolder: "CONFIG_OUTPUT_DIR",
};
public static outputFileFolder = "Build.ArtifactStagingDirectory";
Expand All @@ -25,6 +25,7 @@ export default class Constants {
public static defaultDockerHubHostname = "docker.io";
public static variableKeyDisableTelemetry = "DISABLE_TELEMETRY";
public static execSyncSilentOption = { silent: true } as IExecSyncOptions;
public static defaultExecOption = {} as IExecSyncOptions;
public static UTF8 = "utf8";
public static outputVariableDeploymentPathKey = "DEPLOYMENT_FILE_PATH";
}
16 changes: 14 additions & 2 deletions Tasks/AzureIoTEdgeV2/deployimage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import util from "./util";
import Constants from "./constant";
import { IExecSyncOptions } from 'azure-pipelines-task-lib/toolrunner';
import { TelemetryEvent } from './telemetry';
import * as stream from "stream";
import EchoStream from './echostream';
import { IExecOptions } from 'azure-pipelines-task-lib/toolrunner';

class azureclitask {
private static isLoggedIn = false;
Expand Down Expand Up @@ -87,10 +90,15 @@ class azureclitask {
// If error when get iot hub information, ignore.
}

let outputStream: EchoStream = new EchoStream();
let execOptions: IExecOptions = {
errStream: outputStream as stream.Writable
} as IExecOptions;

let result1 = tl.execSync('az', script1, Constants.execSyncSilentOption);
let result2 = await tl.exec('az', script2);
let result2 = await tl.exec('az', script2, execOptions);
if (result2 !== 0) {
throw new Error(`Error for deployment`);
throw new Error(`Failed to create deployment. Error: ${outputStream.content}`);
}
}
catch (err) {
Expand Down Expand Up @@ -222,8 +230,12 @@ class imagevalidationtask {
tl.debug(JSON.stringify(loginResult));
if (loginResult.code != 0) {
tl.warning(tl.loc("InvalidRegistryCredentialWarning", credential.address, loginResult.stderr));
} else {
tl.loc("LoginRegistrySucess", credential.address);
}
});
} else {
tl.debug("No registry credentials found in deployment manifest.")
}

tl.setVariable("DOCKER_CLI_EXPERIMENTAL", "enabled");
Expand Down
34 changes: 21 additions & 13 deletions Tasks/AzureIoTEdgeV2/genconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,25 @@ export async function run() {
util.setTaskRootPath(path.dirname(templateFilePath));

util.setupIotedgedev();

let envList = {
[Constants.iotedgedevEnv.deploymentFileOutputFolder]: tl.getVariable(Constants.outputFileFolder),
};

// Pass task variable to sub process
let tlVariables = tl.getVariables();
for (let v of tlVariables) {
// The variables in VSTS build contains dot, need to convert to underscore.
let name = v.name.replace('.', '_').toUpperCase();
if (!envList[name]) {
envList[name] = v.value;
}

let outputPath = tl.getInput('deploymentManifestOutputPath', true);
let outputFileFolder = path.dirname(outputPath);
let outputFileName = path.basename(outputPath);

let envList = process.env;
if (envList[Constants.iotedgedevEnv.deploymentFileOutputFolder]) {
tl.loc("OverrideDeploymentManifestOutputPath", Constants.iotedgedevEnv.deploymentFileOutputFolder);
}
tl.debug(`Setting deployment manifest output folder to ${outputFileFolder}`);
util.setEnvrionmentVarialbe(envList, Constants.iotedgedevEnv.deploymentFileOutputFolder, outputFileFolder);
if (envList[Constants.iotedgedevEnv.deploymentFileOutputName]) {
tl.loc("OverrideDeploymentManifestOutputPath", Constants.iotedgedevEnv.deploymentFileOutputName);
}
tl.debug(`Setting deployment manifest output file name to ${outputFileName}`)
util.setEnvrionmentVarialbe(envList, Constants.iotedgedevEnv.deploymentFileOutputName, outputFileName)

// Pass task variable to sub process
util.populateSecretToEnvironmentVariable(envList);

let execOptions: IExecOptions = {
cwd: tl.cwd(),
Expand All @@ -38,4 +43,7 @@ export async function run() {
command += ` --file "${templateFilePath}"`;
command += ` --platform "${defaultPlatform}"`;
await tl.exec(`${Constants.iotedgedev}`, command, execOptions);

tl.setVariable(Constants.outputVariableDeploymentPathKey, outputPath);
tl.debug(`Set ${Constants.outputVariableDeploymentPathKey} to ${outputPath}`);
}
28 changes: 12 additions & 16 deletions Tasks/AzureIoTEdgeV2/pushimage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ function getRegistryAuthenticationToken(): RegistryCredential {
}

if (token == null || token.username == null || token.password == null || token.serverUrl == null) {
throw Error(tl.loc('ContainerRegistryInvalid', JSON.stringify(token)));
let username = "";
if (token != null && token.username != null) {
username = token.username;
}
throw Error(tl.loc('ContainerRegistryInvalid', username));
}
return token;
}
Expand Down Expand Up @@ -52,24 +56,16 @@ export async function run() {
*/
tl.execSync(`docker`, `login -u "${registryAuthenticationToken.username}" -p "${registryAuthenticationToken.password}" ${registryAuthenticationToken.serverUrl}`, Constants.execSyncSilentOption)

let envList = {
[Constants.iotedgedevEnv.bypassModules]: bypassModules,
[Constants.iotedgedevEnv.registryServer]: registryAuthenticationToken.serverUrl,
[Constants.iotedgedevEnv.registryUsername]: registryAuthenticationToken.username,
[Constants.iotedgedevEnv.registryPassword]: registryAuthenticationToken.password,
};
let envList = process.env;
util.setEnvrionmentVarialbe(envList, Constants.iotedgedevEnv.bypassModules, bypassModules);
util.setEnvrionmentVarialbe(envList, Constants.iotedgedevEnv.registryServer, registryAuthenticationToken.serverUrl);
util.setEnvrionmentVarialbe(envList, Constants.iotedgedevEnv.registryUsername, registryAuthenticationToken.username);
util.setEnvrionmentVarialbe(envList, Constants.iotedgedevEnv.registryPassword, registryAuthenticationToken.password);

// Pass task variable to sub process
let tlVariables = tl.getVariables();
for (let v of tlVariables) {
// The variables in VSTS build contains dot, need to convert to underscore.
let name = v.name.replace('.', '_').toUpperCase();
if (!envList[name]) {
envList[name] = v.value;
}
}
util.populateSecretToEnvironmentVariable(envList);

tl.debug(`Following variables will be passed to the iotedgedev command: ${JSON.stringify(envList)}`);
tl.debug(`Following variables will be passed to the iotedgedev command: ${Object.keys(envList).join(", ")}`);

try {
let execOptions: IExecOptions = {
Expand Down
26 changes: 20 additions & 6 deletions Tasks/AzureIoTEdgeV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 1,
"Patch": 5
"Minor": 2,
"Patch": 0
},
"preview": true,
"preview": false,
"showEnvironmentVariables": true,
"instanceNameFormat": "Azure IoT Edge - $(action)",
"groups": [
{
Expand Down Expand Up @@ -51,7 +52,7 @@
"name": "deploymentFilePath",
"type": "filePath",
"label": "Deployment file",
"defaultValue": "$(System.DefaultWorkingDirectory)/**/*.json",
"defaultValue": "$(System.DefaultWorkingDirectory)/config/deployment.json",
"required": true,
"visibleRule": "action == Deploy to IoT Edge devices",
"helpMarkDown": "Select the deployment json file.\n If this task is in **release pipeline**, you need to set the location of deployment file in artifact.(The default value works for most conditions).\n If this task is in **build pipeline**, you need to set it to the path of **Path of output deployment file**."
Expand Down Expand Up @@ -200,6 +201,15 @@
},
"helpMarkDown": "Add registry credential for pushing docker images to deployment manifest"
},
{
"name": "deploymentManifestOutputPath",
"type": "filePath",
"label": "Output path",
"defaultValue": "$(System.DefaultWorkingDirectory)/config/deployment.json",
"visibleRule": "action == Generate deployment manifest",
"required": true,
"helpMarkDown": "The output path of generated deployment manifest"
},
{
"name": "bypassModules",
"type": "string",
Expand Down Expand Up @@ -247,7 +257,7 @@
"DependencyInstallSuccess": "%s installed with version: %s",
"DependencyInstallFail": "%s installation failed, see detailed error in debug mode",
"TemplateFileInvalid": "The path of template file is not valid: %s",
"ContainerRegistryInvalid": "Failed to fetch container registry authentication token, please check you container registry setting in build task. The token is %s",
"ContainerRegistryInvalid": "Failed to fetch container registry authentication token, please check you container registry setting in build task. The username for container registry is %s",
"DeploymentFileNotFound": "Deployment file can't be found. Please ensure Path of deployment file is correctly set in the task.",
"ValidDeploymentFileNotFound": "Cannot find a valid deployment file. Please ensure Path of deployment file is correctly set in the task.",
"AzureSdkNotFound": "Azure SDK not found",
Expand All @@ -256,7 +266,11 @@
"InvalidRegistryCredentialWarning": "Failed to login %s with given credential. %s",
"CheckModuleImageExistenceError": "%s does not exist or the credential is not set correctly. Error: %s",
"StartGenerateDeploymentManifest": "Start generating deployment manifest...",
"FinishGenerateDeploymentManifest": "Finished generating deployment manifest."
"FinishGenerateDeploymentManifest": "Finished generating deployment manifest.",
"LoginRegistrySucess": "Successfully logged in to registry %s",
"SkipSettingEnvironmentVariable": "The environment variable %s already exists. Skip setting this environment variable.",
"SkipSettingEnvironmentVariableForSecret": "Environment variable %s already exist. Skip setting environment varialbe for secret: %s.",
"OverrideDeploymentManifestOutputPath": "The %s environment variable will be overriden by the output path parameter."
},
"OutputVariables": [
{
Expand Down
24 changes: 19 additions & 5 deletions Tasks/AzureIoTEdgeV2/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
"author": "Microsoft Corporation",
"version": {
"Major": 2,
"Minor": 1,
"Patch": 5
"Minor": 2,
"Patch": 0
},
"preview": true,
"preview": false,
"showEnvironmentVariables": true,
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",
"groups": [
{
Expand Down Expand Up @@ -51,7 +52,7 @@
"name": "deploymentFilePath",
"type": "filePath",
"label": "ms-resource:loc.input.label.deploymentFilePath",
"defaultValue": "$(System.DefaultWorkingDirectory)/**/*.json",
"defaultValue": "$(System.DefaultWorkingDirectory)/config/deployment.json",
"required": true,
"visibleRule": "action == Deploy to IoT Edge devices",
"helpMarkDown": "ms-resource:loc.input.help.deploymentFilePath"
Expand Down Expand Up @@ -200,6 +201,15 @@
},
"helpMarkDown": "ms-resource:loc.input.help.fillRegistryCredential"
},
{
"name": "deploymentManifestOutputPath",
"type": "filePath",
"label": "ms-resource:loc.input.label.deploymentManifestOutputPath",
"defaultValue": "$(System.DefaultWorkingDirectory)/config/deployment.json",
"visibleRule": "action == Generate deployment manifest",
"required": true,
"helpMarkDown": "ms-resource:loc.input.help.deploymentManifestOutputPath"
},
{
"name": "bypassModules",
"type": "string",
Expand Down Expand Up @@ -256,7 +266,11 @@
"InvalidRegistryCredentialWarning": "ms-resource:loc.messages.InvalidRegistryCredentialWarning",
"CheckModuleImageExistenceError": "ms-resource:loc.messages.CheckModuleImageExistenceError",
"StartGenerateDeploymentManifest": "ms-resource:loc.messages.StartGenerateDeploymentManifest",
"FinishGenerateDeploymentManifest": "ms-resource:loc.messages.FinishGenerateDeploymentManifest"
"FinishGenerateDeploymentManifest": "ms-resource:loc.messages.FinishGenerateDeploymentManifest",
"LoginRegistrySucess": "ms-resource:loc.messages.LoginRegistrySucess",
"SkipSettingEnvironmentVariable": "ms-resource:loc.messages.SkipSettingEnvironmentVariable",
"SkipSettingEnvironmentVariableForSecret": "ms-resource:loc.messages.SkipSettingEnvironmentVariableForSecret",
"OverrideDeploymentManifestOutputPath": "ms-resource:loc.messages.OverrideDeploymentManifestOutputPath"
},
"OutputVariables": [
{
Expand Down
Loading