I'm using Azure DevOps on a vs2017-win2016 build agent to provision some infrastructure using Terraform.
What I want to know is it possible to pass the Terraform Output of a hosts dynamically assigned IP address to a
2nd Job running a different build agent.
I'm able to pass these to build variables in the first Job
BASTION_PRIV_IP=x.x.x.x
BASTION_PUB_IP=1.1.1.1
But un-able to get these variables to appear to be consumed with the second build agent running ubuntu-16.04
I am able to pass any static defined parameters like Azure Resource Group name that I define before the job start, its just the
dynamically assigned ones.
This is pretty easily done when you are using the YAML based builds.
It's important to know that variables are only available within the scope of current job by default.
However you can set a variable as an output variable for your job.
This output variable can then be mapped to a variable within second job (do note that you need to set the first job as a dependency for the second job).
Please see the following link for an example of how to get this to work
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#set-a-multi-job-output-variable
It may also be doable in the visual designer type of build, but i couldn't get that to work in the quick test i did, maybe you can get something to work inspired on the linked example.
Related
My Azure pipeline is timing out on terraform plan/apply when I add variable groups.
The variables
Variable group
I tried to do some research but to no avail.
yml
When running Terraform in a pipeline you need to pass the parameter -input-false. This will cause Terraform to immediately output the error and I suspect it's saying something like the input variable vnet_name is not set because you have not explained how you are joining the variable group to Terraform. It is not enough to simply add the pipeline variables, you must also pass them into Terraform.
There are a number of ways of passing values into Terraform as described in this page here: https://www.terraform.io/language/values/variables#assigning-values-to-root-module-variables
The most common method I have seen used is to create an environment.tfvars file. This is a simple key:pair value of variables which you can hard-code variables into which you then pass into Terraform like terraform apply -var-file="environment.tfvars"
If you have values in Azure Pipelines that you want to place there, you can use the Azure Replace Tokens tasks. (https://marketplace.visualstudio.com/items?itemName=qetza.replacetokens)
In which case your environment.tfvars will look like this:
vnet_name = #{vnet_name}#
The Replace Token Task will replace the Azure Pipeline variable vnet_name with the value described in your variable group.
We are looking for a solution how to move the non-secret variables from the Variable groups into the code repositories.
We would like to have the possibilities:
to track the changes of all the settings in the code repository
version value of the variable together with the source code, pipeline code version
Problem:
We have over 100 variable groups defined which are referenced by over 100 YAML pipelines.
They are injected at different pipeline/stage/job levels depends on the environment/component/stage they are operating on.
Example problems:
some variable can change their name, some variable can be removed and in the pipeline which targets the PROD environment it is still referenced, and on the pipeline which deploys on DEV it is not there
particular pipeline run used the version of the variables at some date in the past, it is good to know with what set of settings it had been deployed in the past
Possible solutions:
It should be possible to use the simple yaml template variables file to mimic the variable groups and just include the yaml templates with variable groups into the main yamls using this approach: Variable reuse.
# File: variable-group-component.yml
variables:
myComponentVariable: 'SomeVal'
# File: variable-group-environment.yml
variables:
myEnvVariable: 'DEV'
# File: azure-pipelines.yml
variables:
- template: variable-group-component.yml # Template reference
- template: variable-group-environment.yml # Template reference
#some stages/jobs/steps:
In theory, it should be easy to transform the variable groups to the YAML template files and reference them from YAML instead of using a reference to the variable group.
# Current reference we use
variables:
- group: "Current classical variable group"
However, even without implementing this approach, we hit the following limit in our pipelines: "No more than 100 separate YAML files may be included (directly or indirectly)"
YAML templates limits
Taking into consideration the requirement that we would like to have the variable groups logically granulated and separated and not stored in one big yml file (in order to not hit another limit with the number of variables in a job agent) we cannot go this way.
The second approach would be to add a simple script (PowerShell?) which will consume some key/value metadata file with variables (variableName/variableValue) records and just execute job step with a command to
##vso[task.setvariable variable=one]secondValue.
But it could be only done at the initial job level, as a first step, and it looks like the re-engineering variable groups mechanism provided natively in Azure DevOps.
We are not sure that this approach will work everywhere in the YAML pipelines when the variables are currently used. Somewhere they are passed as arguments to the tasks. Etc.
Move all the variables into the key vault secrets? We abandoned this option at the beginning as the key vault is a place to store sensitive data and not the settings which could be visible by anyone. Moreover storing it in secrets cause the pipeline logs to put * instead of real configuration setting and obfuscate the pipeline run log information.
Questions:
Q1. Do you have any other propositions/alternatives on how the variables versioning/changes tracking could be achieved in Azure DevOps YAML pipelines?
Q2. Do you see any problems in the 2. possible solution, or have better ideas?
You can consider this as alternative:
Store your non-secrets variable in json file in a repository
Create a pipeline to push variables to App Configuration (instead a Vault)
Then if you need this settings in your app make sure that you reference to app configuration from the app instead running replacement task in Azure Devops. Or if you need this settings directly by pipelines Pull them from App Configuration
Drawbacks:
the same as one mentioned by you in Powershell case. You need to do it job level
What you get:
track in repo
track in App Configuration and all benefits of App Configuration
We have setup a agentpool with 3 agents tagged to it for running tests in parallel. We would like to use various input values for .runsettings file to override test run parameters (overrideTestrunParameters) & distribute our test runs on various agents. e.g.,
Lets assume that the agentpool P1 have associated agents A1, A2, A3.
We need agent A1 to configure a test run parameter executeTests = Functionality1, agent A2 to configure a test run parameter executeTests = Functionality2 etc.,
Please let us know if it is possible to use executionPlan with options Multiagent or Multi Configuration to achieve it.
So if I did not misunderstand, what you want is run the tests with multiple-configuration into multi-agents?
If yes, I'd better suggest you could apply with matrix in pipeline to achieve what you want.
*Note: Matrix is the new feature that only support YAML pipeline. If you want to make use matrix in your side, you had to use YAML to configure your pipeline.*
For how to apply matrix in this scenario, you could refer to below simple sample:
strategy:
matrix:
execTest1:
agentname: "Agent-V1"
executeTests: "Functionality1"
execTest2:
agentname: "Agent-V2"
executeTests: "Functionality2"
execTest3:
agentname: "Agent-V3"
executeTests: "Functionality3"
maxParallel: 3
pool:
name: '{pool name}'
demand:
- agent-name -equals $(agentname)
...
...
With such YAML definition, it can run the job at same time and with different configuration. Also, different configuration run onto the specified agent.
Note: Please ensure your project support parallel consuming.
For more details, see this.
I was able to find a solution for my case here by doing below
Add a variable group in the pipeline named executeTests & assigning names, values for the respective variable group as Functionality1, Functionality2 etc.,
Added multiple agent jobs in the same pipeline & assigned the Override test run parameters with -(test.runsetting variable) $(Functionality1) etc across agents A1, A2, A3
The above does run tests parallelly based on the settings available at each agent job
Using different runsettings or even override settings is not supported. The test task expects it to be consistent across all the agents. It will use whichever is configured for the first to start the test task. For example, if you were to pass an override variable $(Agent.Name), it would use the first agent name regardless of which agent picked it up.
The only way we found to manage this was to handle it in our test framework code. Instead of loading from runsettings, we set environment variables on the agent in a step prior to the test task. Then our test framework will load from the environment variable.
I have a pipeline defined of two steps:
one building a combined helm chart from two separate artifacts
two deploying this chart to a cluster
Both stages first load a secret and then run a bash script to do the work, as shown in the following image.
My challenge now is, to submit the helm chart name and its version from the Build stage to the Deploy one. So that the 2 step can fetch the right chart.
How can I achieve this?
Trial 1: Using ##vso[task.setvariable - Did not work from the script
echo "##vso[task.setvariable variable=HELM_CHART_NAME]$HELM_CHART_NAME"
echo "##vso[task.setvariable variable=HELM_CHART_VERSION]$HELM_CHART_VERSION"
Using ##vso[task.setvariable - Did not work from the script
This caused by different stages using different agents, and the dynamic variable which set by ##vso[task.setvariable is just a agent-scoped one. Its life cycle equal with agent, so it will disappear once one agent job finished.
For the solution which can help you achieve pass variable from Build stage to Deploy stage, you'd better store these variables in one storage. Such as store it in Azure Key vault with the task Azure Key Vault actions or Write Secrets to Key Vault.
Another way is use rest api to add it as the release variable with powershell script:
PUT https://vsrm.dev.azure.com/{organization}/{project}/_apis/release/releases/{releaseId}?api-version=5.0
Then, in next stage, it can access and get variable from Release Variables.
We would like to try building a release pipeline for our product in VSTS - however, our product requires a separate instance of the application per customer (there are some legacy in the picture here :)). What we THINK we want, is a process like this:
For each customer:
Update DB schema
Configure a container, with customer-specific configuration etc.
Publish the container into Azure Container Registry
Deploy the container in Azure Container Service (OR on-prem if the customer runs on-prem)
The configuration can be multiple things: Extensions of the API in the application (new DLLs basically), connection strings, ...
I figure we can do this fairly easily using a custom PowerShell script, but I would like to not write anything custom (at least for the "looping" issue) if I don't have to. We could also create separate environments in VSTS for each customer, but that seems quite unmaintainable with well over 100 customers.
Some additional details:
- There's a separate DB per customer
- There's two separate web applications per customer
So what's the best practice here? Any advice? Thanks! :-)
You could think of doing it in two ways.
1 - By creating one environment for each customer. So you could have the exact same tasks for each environment, or have the flexibility to change steps in a particular environment.
This approach would give you also the ability to use a flow pipeline, because your build will be released only after is passes your internal QA and other processes.
To do it easily, you could also create task groups to reuse then in each environment.
2 - The other way is to create create separate releases for each customer or group of customers. This will also give you the same flexibility, you can use your builds, but you have to add some extra steps to make sure you are using the right build, since you can choose any build when you create a release, which you can do mannualy.
Updated
A third option could be to create on environment for all customers and then have the one deployment agent installed for every customer, using all of them on the same deployment group. Then have one file with all your variables per customer, with the file named with the agent name, and a powershell script that uses the agent name variable to find what file to run. This powershell script would then run all your individual configurations.
In that case, I suspect that you would end up doing almost all your deployment in powershell, which could be more time consuming for you to maintain. You also have to keep in mind that in this particular scenario you would update all your customers the same time, because all agents would be on the same deployment group.