Install - .NET Dynamic Agent deployed via Ansible for .NET Framework Command Line Apps



Overview

During the vFunction Dynamic Agent installation via Ansible, the Agent is added to the Target Host as a ZIP file and configurable parameters are added to the Host in an installation.yaml. On the Host’s filessystem, the ZIP is unpacked and the installation.yaml is added to this location. An installation script is run to set the Agent configuration files. A separate script is used to start the Application with the Agent hooked into the running Application via COR_PROFILER process-level Environment Variables.


Prerequisites

Ansible Installation ZIP

The Ansible vFunction .NET Agent ZIP can be downloaded from here. The details below outline specific portions of this ZIP.


Layout

The Ansible vFunction .NET Agent should be configured in the following manner:

ansible-vfunction-dotnet-agent/
├── playbook.yml
├── requirements.yml
├── inventory.ini
├── group_vars/
│   └── windows.yml              # all configurable values (edit this)
├── templates/
│   ├── installation.yaml.j2     # renders installation.yaml
│   └── start-thick-client.ps1.j2 # renders the COR_PROFILER launch script
└── files/
    └── PLACE_ZIP_HERE.txt       # drop the vFunction ZIP here

ansible-vfunction-dotnet-agent/playbook.yml
# Steps:
#   1. Move the Installation ZIP to the Windows host
#   2. Extract the vFunction Installation Package
#   3. Populate installation.yaml with the required configuration settings
#   4. Unblock files and run install.ps1 for the instance
#   5. Create a separate script that sets COR_PROFILER env vars and starts
#      the thick client application
#   6. Run that script to launch the instrumented thick client
# ===========================================================================
- name: Install vFunction Dynamic Agent (.NET Framework, command-line workflow)
  hosts: windows
  gather_facts: false

  vars:
    vf_installation_yaml_dir: "{{ vf_base_dir }}\\vfunction\\config\\installation\\instances\\{{ vf_instance_name }}"
    vf_controller_install_dir: "{{ vf_base_dir }}\\controller-installation"
    vf_thick_client_script_path: "{{ vf_base_dir }}\\start-thick-client.ps1"

  tasks:

    # -----------------------------------------------------------------
    # 1. Prep: create the base directory where vFunction will run
    # -----------------------------------------------------------------
    - name: Ensure vFunction base directory exists
      ansible.windows.win_file:
        path: "{{ vf_base_dir }}"
        state: directory

    # -----------------------------------------------------------------
    # 2. Move the Installation ZIP to the Windows host
    # -----------------------------------------------------------------
    - name: Copy vFunction Controller Installation ZIP to the host
      ansible.windows.win_copy:
        src: "{{ vf_zip_local_path }}"
        dest: "{{ vf_zip_remote_path }}"

    # -----------------------------------------------------------------
    # 3. Extract the vFunction Installation Package
    # -----------------------------------------------------------------
    - name: Extract the vFunction Installation Package
      community.windows.win_unzip:
        src: "{{ vf_zip_remote_path }}"
        dest: "{{ vf_base_dir }}"
        remote_src: true

    # Unblock extracted files:
    - name: Unblock extracted vFunction files
      ansible.windows.win_shell: |
                Get-ChildItem -Path '{{ vf_base_dir }}' -Recurse | Unblock-File

    # -----------------------------------------------------------------
    # 4. Populate installation.yaml with the required configuration
    #    settings
    # -----------------------------------------------------------------
    - name: Ensure installation.yaml target directory exists
      ansible.windows.win_file:
        path: "{{ vf_installation_yaml_dir }}"
        state: directory

    - name: Deploy installation.yaml with vFunction configuration
      ansible.windows.win_template:
        src: templates/installation.yaml.j2
        dest: "{{ vf_installation_yaml_dir }}\\installation.yaml"
      no_log: true   # contains client_secret

    # -----------------------------------------------------------------
    # 5. Run install.ps1 for the instance
    # -----------------------------------------------------------------
    - name: Run vFunction install.ps1 for instance {{ vf_instance_name }}
      ansible.windows.win_shell: |
                & '{{ vf_controller_install_dir }}\install.ps1' -instance {{ vf_instance_name }}
      args:
        chdir: "{{ vf_controller_install_dir }}"
      register: vf_install_result

    - name: Show install.ps1 output
      ansible.builtin.debug:
        var: vf_install_result.stdout_lines

    # -----------------------------------------------------------------
    # 6. Create a separate script that sets the COR_PROFILER variables
    #    and starts the thick client application
    # -----------------------------------------------------------------
    - name: Deploy thick-client launch script with COR_PROFILER variables
      ansible.windows.win_template:
        src: templates/start-thick-client.ps1.j2
        dest: "{{ vf_thick_client_script_path }}"

    # -----------------------------------------------------------------
    # 7. Run the script to start the instrumented thick client
    # -----------------------------------------------------------------
    - name: Launch the instrumented thick client
      ansible.windows.win_shell: |
        Start-Process -FilePath 'powershell.exe' `
          -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','{{ vf_thick_client_script_path }}' `
          -WindowStyle Normal        
      when: vf_start_thick_client | bool
      async: 5
      poll: 0

    - name: Confirm thick client launch was triggered
      ansible.builtin.debug:
        msg: >
          Thick client launch script '{{ vf_thick_client_script_path }}' has been triggered.
          Confirm on the host that the application comes up and functions as expected.
          If issues arise, see:
          https://kb.vfunction.com/installations/known-issues/mono-dynamic-agent/dotnet
          and
          https://kb.vfunction.com/installations/general-troubleshooting/mono-dynamic-agent/dotnet/host/          
      when: vf_start_thick_client | bool

ansible-vfunction-dotnet-agent/group_vars/windows.yml
# ---------------------------------------------------------------------------
# vFunction installation package
# ---------------------------------------------------------------------------
# Local path (on the Ansible control node) to the vFunction Windows Controller
# Installation ZIP downloaded from:
# https://portal.vfunction.com/files/shares/installation-files/controller
vf_zip_local_path: "files/vfunction-controller-installation.zip"

# Location on the Windows target where vFunction should run/be extracted
vf_base_dir: "C:\\vFunction"
vf_zip_remote_path: "{{ vf_base_dir }}\\vfunction-controller-installation.zip"

vf_instance_name: "default-dotnet"

# ---------------------------------------------------------------------------
# installation.yaml - controller settings
# (see https://kb.vfunction.com/installations/configurable-settings/mono-dynamic-agent/dotnet/windows/#required)
# ---------------------------------------------------------------------------
vf_controller_name: "CHANGE_ME"        # UI identifier for the Agent, e.g. QA-Win1-BillPay
vf_controller_host: "CHANGE_ME"        # e.g. https://vfunction.organization.com
vf_org_id: "CHANGE_ME"                 # UUID from VF Server UI Install Instructions dialog
vf_app_id: "CHANGE_ME"                 # UUID from VF Server UI Install Instructions dialog
vf_client_id: "CHANGE_ME"              # UUID from VF Server UI Install Instructions dialog
# Store this in an Ansible Vault-encrypted file/variable, never in plaintext:
vf_client_secret: "CHANGE_ME"          # ansible-vault encrypt_string this value
vf_tags:
  - "CHANGE_ME"       # e.g. "prod" or "BillPay"

# instrconf_additions (optional inclusions/exclusions)
vf_instrconf_inclusions: []
vf_instrconf_exclusions: []

# agent block - fixed values required for the Framework / command-line workflow
vf_agent_version: "framework"
vf_agent_environment: "command"

# ---------------------------------------------------------------------------
# Thick client application to instrument
# ---------------------------------------------------------------------------
# Full path to the executable that starts the thick client application
vf_run_app_path: "C:\\Program Files\\MyThickClient\\MyThickClient.exe"
# Optional arguments passed to the thick client executable
vf_run_app_args: ""

# Whether to fire off the thick client launch script at the end of the play
# (set to false if you'd rather start it manually / via logon script)
vf_start_thick_client: true