In lab management workflow, there is an option to take a snapshot of the environment after the application is deployed. This option is exposed in the workflow UI and is very useful in scenarios in which you want to revert to the environment state in which only the environment has only the new build deployed onto it and nothing else.

For example: – If as part of the workflow if you are additionally running automated tests as well, and you plan to manually scout the build once the workflow is complete, so in that case you may want to go back to a state where the environment had just the new build and is not “dirty” with the execution of the test cases.

You can enable taking of this snapshot in the workflow UI as mentioned below. To enable this option, you should enable the green box and specify a prefix for the snapshot name.

takeSnapshot

Once you have enabled this option saving the build definition, the code in default lab template ensures that the snapshot is taken after the deployment is complete.  Now let us go to that template file and see how does it look like. To look at the template file, typically I click on the version control path (red box in the below picture) which takes me to the right file in source control browser.

processTemplatePath

 

LabTemplatePath

I opened the lab template file in notepad and here is the relevant portion which is responsible for taking post deployment snapshot.

<If Condition="[LabWorkflowParameters.DeploymentDetails.TakePostDeploymentSnapshot = True]" DisplayName="Post Deployment Snapshot">
      <If.Then>

<Sequence DisplayName="Take Post deployment Snapshot ">
        <Sequence.Variables>

                 <Variable x:TypeArguments="x:Int64" Name="PostDeploymentSnapshotChainId" />
                              <Variable x:TypeArguments="x:String" Default="[String.Format(&quot;{0}_{1}&quot;, BuildDetail.BuildDefinition.Name, BuildDetail.BuildNumber)]"  Name="PostDeploymentSnapshotName" />
                      </Sequence.Variables>

                      <If Condition="[String.IsNullOrEmpty(LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName) = False]" DisplayName="Check snapshot name">
                              <If.Then>
                                         <Assign>
                                                <Assign.To>
                                                       <OutArgument x:TypeArguments="x:String">[PostDeploymentSnapshotName]</OutArgument>
                                                </Assign.To>
                                                <Assign.Value>
                                                        <InArgument x:TypeArguments="x:String">[If(LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True,
String.Format("{0}_{1}_2}",LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildNumber,BuildDetail.BuildNumber),String.Format("{0}_{1}",LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildDetail.BuildNumber))]</InArgument>
                                              </Assign.Value>
                                    </Assign>
                          </If.Then>
                    </If>

                    <mtlwa:SnapshotLabEnvironment DisplayName="Taking Post Deployment snapshot" LabEnvironmentUri="[LabEnvironmentUri]" SnapshotChainId="[PostDeploymentSnapshotChainId]" SnapshotName="[PostDeploymentSnapshotName]" />

                     <mtlwa:WriteDeploymentInformation Url="{x:Null}" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.Deploy]" DisplayName="Taking Snapshot succeeded" Message="[String.Format(&quot;The following snapshot was taken after the deployment was finished: {0}&quot;, PostDeploymentSnapshotName)]" />                   

                   <mtlwa:WriteDeploymentInformation Url="[PostDeploymentSnapshotChainId.ToString()]" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.ConnectToSnapshot]" DisplayName="Added connection link to the Snapshot" Message="[PostDeploymentSnapshotName]" />
             </Sequence>
         </If.Then>

</If>

Now let us now go through the code snippet little deeply and understand what’s going on.

-   This is a conditional check which is evaluating the condition that whether the option to take post deployment snapshot is on or off. (Green box in the above image)

<If Condition="[LabWorkflowParameters.DeploymentDetails.TakePostDeploymentSnapshot = True]" DisplayName="Post Deployment Snapshot">
      <If.Then>

-   Define a couple of temporary variables. One for the output of the snapshot operation (SnapshotChainId) which is used to generate the hyperlink in the build summary and other for the default name for new snapshot.

<Sequence.Variables>

     <Variable x:TypeArguments="x:Int64" Name="PostDeploymentSnapshotChainId" />
     <Variable x:TypeArguments="x:String" Default="[String.Format(&quot;{0}_{1}&quot;, BuildDetail.BuildDefinition.Name, BuildDetail.BuildNumber)]"  Name="PostDeploymentSnapshotName" />
</Sequence.Variables>

-   If the prefix for the snapshot name is specified, then use that prefix in the snapshot name.

<If Condition="[String.IsNullOrEmpty(LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName) = False]" DisplayName="Check snapshot name">
    <If.Then>
        <Assign>
            <Assign.To>
                   <OutArgument x:TypeArguments="x:String">[PostDeploymentSnapshotName]</OutArgument>
             </Assign.To>
             <Assign.Value>
                   <InArgument x:TypeArguments="x:String">[If(LabWorkflowParameters.BuildDetails.IsTeamSystemBuild = True,
String.Format("{0}_{1}_2}",LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildNumber,BuildDetail.BuildNumber),String.Format("{0}_{1}",LabWorkflowParameters.DeploymentDetails.PostDeploymentSnapshotName, BuildDetail.BuildNumber))]

                     </InArgument>
            </Assign.Value>
       </Assign>
   </If.Then>
</If>

 

- Take the snapshot using built-in SnapshotLabEnvironment activity. Since snapshot is a long running operation, this activity internally waits for the operation to complete.


<mtlwa:SnapshotLabEnvironment DisplayName="Taking Post Deployment snapshot" LabEnvironmentUri="[LabEnvironmentUri]" SnapshotChainId="[PostDeploymentSnapshotChainId]" SnapshotName="[PostDeploymentSnapshotName]" />

 

- Log the details of the snapshot operation so that it appears in the workflow summary.


<mtlwa:WriteDeploymentInformation Url="{x:Null}" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.Deploy]" DisplayName="Taking Snapshot succeeded" Message="[String.Format(&quot;The following snapshot was taken after the deployment was finished: {0}&quot;, PostDeploymentSnapshotName)]" />                   

<mtlwa:WriteDeploymentInformation Url="[PostDeploymentSnapshotChainId.ToString()]" DeploymentInformationType="[Microsoft.TeamFoundation.Build.Common.DeploymentInformationTypes.ConnectToSnapshot]" DisplayName="Added connection link to the Snapshot" Message="[PostDeploymentSnapshotName]" />

Hopefully now you would have learnt how the xaml is coded to take a snapshot after the deployment is complete. You can use the similar approach to take snapshots for the custom scenarios like taking snapshot if one or more automated tests fails etc.