From 1575e742e7ffa86c96fb678213dddcfe3759c7f7 Mon Sep 17 00:00:00 2001
From: "Xavier Pillons (MSFT)" <xpillons@microsoft.com>
Date: Tue, 2 Jan 2024 17:05:44 +0100
Subject: [PATCH 1/5] remove duplicated file

---
 .../files/bc_vmd/template/xfce.sh             | 44 -------------------
 1 file changed, 44 deletions(-)
 delete mode 100644 playbooks/roles/ood-applications/files/bc_vmd/template/xfce.sh

diff --git a/playbooks/roles/ood-applications/files/bc_vmd/template/xfce.sh b/playbooks/roles/ood-applications/files/bc_vmd/template/xfce.sh
deleted file mode 100644
index 3dec1dd7c..000000000
--- a/playbooks/roles/ood-applications/files/bc_vmd/template/xfce.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-# Remove any preconfigured monitors
-if [[ -f "${HOME}/.config/monitors.xml" ]]; then
-  mv "${HOME}/.config/monitors.xml" "${HOME}/.config/monitors.xml.bak"
-fi
-
-# Copy over default panel if doesn't exist, otherwise it will prompt the user
-PANEL_CONFIG="${HOME}/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml"
-if [[ ! -e "${PANEL_CONFIG}" ]]; then
-  mkdir -p "$(dirname "${PANEL_CONFIG}")"
-  cp "/etc/xdg/xfce4/panel/default.xml" "${PANEL_CONFIG}"
-fi
-
-# Disable startup services
-xfconf-query -c xfce4-session -p /startup/ssh-agent/enabled -n -t bool -s false
-xfconf-query -c xfce4-session -p /startup/gpg-agent/enabled -n -t bool -s false
-
-# Disable useless services on autostart
-AUTOSTART="${HOME}/.config/autostart"
-rm -fr "${AUTOSTART}"    # clean up previous autostarts
-mkdir -p "${AUTOSTART}"
-for service in "pulseaudio" "rhsm-icon" "spice-vdagent" "tracker-extract" "tracker-miner-apps" "tracker-miner-user-guides" "xfce4-power-manager" "xfce-polkit"; do
-  echo -e "[Desktop Entry]\nHidden=true" > "${AUTOSTART}/${service}.desktop"
-done
-
-# Run Xfce4 Terminal as login shell (sets proper TERM)
-TERM_CONFIG="${HOME}/.config/xfce4/terminal/terminalrc"
-if [[ ! -e "${TERM_CONFIG}" ]]; then
-  mkdir -p "$(dirname "${TERM_CONFIG}")"
-  sed 's/^ \{4\}//' > "${TERM_CONFIG}" << EOL
-    [Configuration]
-    CommandLoginShell=TRUE
-EOL
-else
-  sed -i \
-    '/^CommandLoginShell=/{h;s/=.*/=TRUE/};${x;/^$/{s//CommandLoginShell=TRUE/;H};x}' \
-    "${TERM_CONFIG}"
-fi
-
-# launch dbus first through eval becuase it can conflict with a conda environment
-# see https://github.com/OSC/ondemand/issues/700
-eval $(dbus-launch --sh-syntax)
-
-# Start up xfce desktop (block until user logs out of desktop)
-xfce4-session &
\ No newline at end of file

From 02332120baad7fd85925d256db24538c937deb4d Mon Sep 17 00:00:00 2001
From: "Xavier Pillons (MSFT)" <xpillons@microsoft.com>
Date: Thu, 4 Jan 2024 10:27:30 +0100
Subject: [PATCH 2/5] allow dynamic list of remote viz queues

---
 .github/workflows/configs/almalinux.yml       |   7 +
 .github/workflows/configs/centos.yml          |   7 +
 .github/workflows/configs/integration.yml     |   7 +
 config.schema.json                            |  17 +
 config.tpl.yml                                |  14 +-
 docs/deploy/index.md                          | 554 ------------------
 playbooks/nodearray_lookup.yml                |   7 +
 playbooks/ood-overrides-common.yml            |  21 +-
 playbooks/ood-overrides-openpbs.yml           |   6 -
 playbooks/ood-overrides-slurm.yml             |   6 -
 playbooks/ood.yml                             |  17 +
 .../files/bc_ansys_workbench/form.yml.erb     |  18 +-
 .../files/bc_paraview/form.yml.erb            |  20 +-
 .../files/bc_vizer/form.yml.erb               |  18 +-
 .../files/bc_vmd/form.yml.erb                 |  18 +-
 playbooks/templates/viz_nodes.yml.j2          |   3 +
 16 files changed, 91 insertions(+), 649 deletions(-)
 create mode 100644 playbooks/templates/viz_nodes.yml.j2

diff --git a/.github/workflows/configs/almalinux.yml b/.github/workflows/configs/almalinux.yml
index acfb12fa7..068f5ba99 100644
--- a/.github/workflows/configs/almalinux.yml
+++ b/.github/workflows/configs/almalinux.yml
@@ -59,6 +59,8 @@ queues:
 
 # Remote Viz Queues
   - name: viz3d
+    type: remoteviz
+    description: "With GPU - Small GPU node for single session"
     vm_size: Standard_NV12s_v3
     max_count: 4
     image: azhpc:azhop-desktop:almalinux-8_7:latest
@@ -66,6 +68,8 @@ queues:
     EnableAcceleratedNetworking: true
 
   - name: viz
+    type: remoteviz
+    description: "Without GPU - for single session"
     vm_size: Standard_D8s_v5
     max_count: 10
     image: azhpc:azhop-desktop:almalinux-8_7:latest
@@ -75,6 +79,9 @@ queues:
     min_hours: 1 # Minimum session duration - 0 is infinite
 
   - name: largeviz3d
+    type: remoteviz
+    description: "Large With GPU - Intented for shared sessions"
+    shareable: true
     vm_size: Standard_NV48s_v3
     max_count: 4
     image: azhpc:azhop-desktop:almalinux-8_7:latest
diff --git a/.github/workflows/configs/centos.yml b/.github/workflows/configs/centos.yml
index 58ace9a0b..64052d877 100644
--- a/.github/workflows/configs/centos.yml
+++ b/.github/workflows/configs/centos.yml
@@ -65,6 +65,8 @@ queues:
 
 # Remote Viz Queues
   - name: viz3d
+    type: remoteviz
+    description: "With GPU - Small GPU node for single session"
     vm_size: Standard_NV12s_v3
     max_count: 4
     image: azhpc:azhop-desktop:centos-7_9:latest
@@ -73,6 +75,8 @@ queues:
 
   - name: viz
     vm_size: Standard_D8s_v5
+    type: remoteviz
+    description: "Without GPU - for single session"
     max_count: 10
     image: azhpc:azhop-desktop:centos-7_9:latest
     ColocateNodes: false
@@ -82,6 +86,9 @@ queues:
 
   - name: largeviz3d
     vm_size: Standard_NV48s_v3
+    type: remoteviz
+    description: "Large With GPU - Intented for shared sessions"
+    shareable: true
     max_count: 4
     image: azhpc:azhop-desktop:centos-7_9:latest
     ColocateNodes: false
diff --git a/.github/workflows/configs/integration.yml b/.github/workflows/configs/integration.yml
index cd7ae19e6..7178063fe 100644
--- a/.github/workflows/configs/integration.yml
+++ b/.github/workflows/configs/integration.yml
@@ -262,6 +262,8 @@ queues:
 
 # Remote Viz Queues
   - name: viz3d
+    type: remoteviz
+    description: "With GPU - Small GPU node for single session"
     vm_size: Standard_NV12s_v3
     max_count: 4
     image: azhpc:azhop-desktop:centos-7_9:latest
@@ -270,6 +272,8 @@ queues:
     EnableAcceleratedNetworking: true
   - name: viz
     vm_size: Standard_D8s_v5
+    type: remoteviz
+    description: "Without GPU - for single session"
     max_count: 10
     image: azhpc:azhop-desktop:centos-7_9:latest
     ColocateNodes: false
@@ -278,6 +282,9 @@ queues:
     max_hours: 12 # Maximum session duration
     min_hours: 1 # Minimum session duration - 0 is infinite
   - name: largeviz3d
+    type: remoteviz
+    description: "Large With GPU - Intented for shared sessions"
+    shareable: true
     vm_size: Standard_NV48s_v3
     max_count: 2
     image: azhpc:azhop-desktop:centos-7_9:latest
diff --git a/config.schema.json b/config.schema.json
index 67395520d..74ed29eb3 100644
--- a/config.schema.json
+++ b/config.schema.json
@@ -1116,6 +1116,23 @@
                 "min_hours": {
                     "description": "Minimum session duration",
                     "type": "integer"
+                },
+                "type": {
+                    "description": "Type of queue - mandatory for remoteviz nodes",
+                    "enum": [
+                        "remoteviz",
+                        "compute"
+                    ],
+                    "type": "string"
+                },
+                "description": {
+                    "description": "Description of the queue that will appear in the node selection choice of the ood portal",
+                    "type": "string"
+                },
+                "shareable": {
+                    "description": "Whether the remote visualization node can be shared by multiple users. Defaults to false",
+                    "type": "boolean",
+                    "default": false
                 }
             },
             "required": [
diff --git a/config.tpl.yml b/config.tpl.yml
index 7daa0f85d..4ad54c249 100644
--- a/config.tpl.yml
+++ b/config.tpl.yml
@@ -499,8 +499,11 @@ queues:
     max_count: 0
     image: azhpc:azhop-compute:centos-7_9:latest
     EnableAcceleratedNetworking: true
-    # Queue dedicated to GPU remote viz nodes. This name is fixed and can't be changed
+
+# Queues for remote visualization
   - name: viz3d
+    type: remoteviz # mandatory property to specify the queue is for remote viz nodes
+    description: "With GPU - Small GPU node for single session" # optional description that will appear in the node selection choice of the ood portal
     vm_size: Standard_NV12s_v3
     max_count: 4
     # Use the pre-built azhop image from the marketplace
@@ -511,8 +514,11 @@ queues:
     EnableAcceleratedNetworking: true
     max_hours: 12 # Maximum session duration
     min_hours: 1 # Minimum session duration - 0 is infinite
-    # Queue dedicated to share GPU remote viz nodes. This name is fixed and can't be changed
+
   - name: largeviz3d
+    type: remoteviz
+    description: "Large With GPU - Intented for shared sessions"
+    shareable: true # Set to true to allow multiple users to connect to the same node - false by default
     vm_size: Standard_NV48s_v3
     max_count: 2
     image: azhpc:azhop-desktop:centos-7_9:latest
@@ -520,8 +526,10 @@ queues:
     EnableAcceleratedNetworking: true
     max_hours: 12
     min_hours: 1
-    # Queue dedicated to non GPU remote viz nodes. This name is fixed and can't be changed
+
   - name: viz
+    type: remoteviz
+    description: "Without GPU - for single session"
     vm_size: Standard_D8s_v5
     max_count: 10
     image: azhpc:azhop-desktop:centos-7_9:latest
diff --git a/docs/deploy/index.md b/docs/deploy/index.md
index 18600c6bc..9df8e173c 100644
--- a/docs/deploy/index.md
+++ b/docs/deploy/index.md
@@ -370,560 +370,6 @@ Run the `install.sh` script:
 
 # Define the environment
 An **az-hop** environment is defined in the `config.yml` configuration file. Before starting, copy the `config.tpl.yml` template to your own `config.yml` configuration file and update it accordingly to your requirements.
-Here is a template for building such configuration file.
-
-```yml
----
-# yaml-language-server: $schema=config.schema.json
-
-# name of the cluster
-project_name: az-hop
-# azure location name as returned by the command : az account list-locations -o table
-location: westeurope
-# Name of the resource group to create all resources
-resource_group: azhop
-# If using an existing resource group set to true. Default is false
-# When using an existing resource group make sure the location match the one of the existing resource group
-use_existing_rg: false
-# If set to true, will disable telemetry for azhop. See https://azure.github.io/az-hop/deploy/telemetry.html.
-#optout_telemetry: true
-
-# A log analytics workspace can be created for monitoring or alerting 
-# Alternatively, you can use an existing workspace. 
-# To use an existing workspace set create to false and specify the resource group, name and subscription the target workspace lives in
-log_analytics:
-  create: false
-  # An existing log analytics workspace can be used instead. The resource group, name and subscription id of the workspace will need to be specified.
-  # Grant the role "Log Analytics Contributor" on the target Log Analytics Workspace for the identity used to deploy az-hop
-  #resource_group:
-  #name:
-  #subscription_id: # Optional, if not specified the current subscription will be used
-
-# Enable the assignment of a managed identity to compute VMs managed by CycleCloud. 
-# You can create an identity and optionally specify a name for the identity to be created or use an existing identity.
-compute_vm_identity:
-  create: false
-  # An existing user assigned identity can be used instead. 
-  # The name & resource group of the target identity will need to be specified if using an existing identity.
-  # If you opt for creating an identity, you can specify a name for the identity to be created, but do not need to specify the resource group.
-  #name: 
-  #resource_group: 
-
-# Option to install the monitoring agent on static infra VMs. Can be disabled if the agent is installed by policy.  
-monitoring: 
-  azure_monitor_agent: false # Install Azure Monitor Agent on static infra VMs
-  # Optional settings to deploy Grafana and install Telegraf
-  telegraf: true # Install telegraf on static infra VMs and dynamic compute nodes. Default: true
-  grafana: true # Deploy a Grafana instance with pre-defined dashboards. Default: true
-  idle_threshold: '70' # default threshold to highlight idle VMs in grafana cluster stats dashboard
-  mem_threshold: '30' # default threshold to highlight VMs running out of memory in grafana cluster stats dashboard
-  iowait_threshold: '40' # default threshold to highlight VMs waiting on IO in  grafana cluster stats dashboard 
-
-#If set to true, it will create alert rules associated with az-hop. Enablement of alerting will require the specification of an admin email to send alerts to.
-alerting:
-  enabled: false
-  admin_email: admin.mail@contoso.com
-  local_volume_threshold: 80
-# Additional tags to be added on the Resource Group
-tags:
-  env: dev
-  project: azhop
-# Define an Azure Netapp Files (ANF) account, single pool and volume
-# If not present, assume that there is an existing NFS share for the users home directory
-anf:
-  create: true
-  # Size of the ANF pool and unique volume (min: 4TB, max: 100TB)
-  homefs_size_tb: 4
-  # Service level of the ANF volume, can be: Standard, Premium, Ultra
-  homefs_service_level: Standard
-  # dual protocol
-  dual_protocol: false # true to enable SMB support. false by default
-  # If alerting is enabled, this value will be used to determine when to trigger alerts 
-  alert_threshold: 80 # alert when ANF volume reaches this threshold
-
-# For small deployments you can use Azure Files instead of ANF for the home directory
-azurefiles:
-  create: false
-  size_gb: 1024
-
-# These mounts will be listed in the Files menu of the OnDemand portal and automatically mounted on all compute nodes and remote desktop nodes
-mounts:
-  # mount settings for the user home directory
-  home: # This home name can't be changed
-    # type of mount : existing, anf or azurefiles, default to existing. One of the three should be defined in order to mount the home directory
-    # When using existing, the mountpoint, server, export and options should be defined, for other cases leave the values as defined with the curly braces
-    type: anf
-    mountpoint: /anfhome # /sharedhome for example
-    server: '{{anf_home_ip}}' # Specify an existing NFS server name or IP, when using the ANF built in use '{{anf_home_ip}}'
-    export: '{{anf_home_path}}' # Specify an existing NFS export directory, when using the ANF built in use '{{anf_home_path}}'
-    options: '{{anf_home_opts}}' # Specify the mount options. Default to rw,hard,rsize=262144,wsize=262144,vers=3,tcp,_netdev
-#  mount1:
-#    mountpoint: /mount1 
-#    server: a.b.c.d # Specify an existing NFS server name or IP
-#    export: myexport1 # Specify an existing NFS export name
-#    options: my_options # Specify the mount options.
-
-# name of the admin account
-admin_user: hpcadmin
-# List of identities (object ids) to grant read access to az-hop key vault (optional)
-# key_vault_readers:
-# Network
-network:
-  # Create Network and Application Security Rules, true by default, false when using an existing VNET if not specified
-  create_nsg: true
-  vnet:
-    name: hpcvnet # Optional - default to hpcvnet
-    #id: # If a vnet id is set then no network will be created and the provided vnet will be used
-    address_space: "10.0.0.0/23" 
-    # Special VNET Tags
-    # tags:
-    #   key1: value1
-    # When using an existing VNET, only the subnet names will be used and not the adress_prefixes
-    subnets: # all subnets are optionals
-    # name values can be used to rename the default to specific names, address_prefixes to change the IP ranges to be used
-    # All values below are the default values
-      frontend:
-        name: frontend
-        address_prefixes: "10.0.0.0/29"
-        create: true # create the subnet if true. default to true when not specified, default to false if using an existing VNET when not specified
-      admin:
-        name: admin
-        address_prefixes: "10.0.0.16/28"
-        create: true
-      netapp:
-        name: netapp
-        address_prefixes: "10.0.0.32/28"
-        create: true
-      # the outbounddns is optional and only when deploying an Azure Private DNS Resolver
-      # outbounddns:
-      #   name: outbounddns
-      #   address_prefixes: "10.0.0.48/28"
-      #   create: true
-      ad:
-        name: ad
-        address_prefixes: "10.0.0.8/29"
-        create: true
-      # Bastion and Gateway subnets are optional and can be added if a Bastion or a VPN need to be created in the environment
-      # bastion: # Bastion subnet name is always fixed to AzureBastionSubnet
-      #   address_prefixes: "10.0.0.64/26" # CIDR minimal range must be /26
-      #   create: true
-      # lustre: # Lustre subnet when deploying a lustre filesystem
-      #   address_prefixes: "10.0.0.128/26"
-      #   create: true
-      # gateway: # Gateway subnet name is always fixed to GatewaySubnet
-      #   address_prefixes: "10.0.0.192/27" # Recommendation is to use /27 or /26 network
-      #   create: true
-      compute:
-        name: compute
-        address_prefixes: "10.0.1.0/24"
-        create: true
-  # Specify the Application Security Groups mapping if already existing
-# asg:
-#   resource_group: # name of the resource group containing the ASG. Default to the resource group containing azhop resources
-#   names: # list of ASG names mapping to the one defined in az-hop
-#     asg-ssh: asg-ssh
-#     asg-rdp: asg-rdp
-#     asg-jumpbox: asg-jumpbox
-#     asg-ad: asg-ad
-#     asg-ad-client: asg-ad-client
-#     asg-lustre: asg-lustre
-#     asg-lustre-client: asg-lustre-client
-#     asg-pbs: asg-pbs
-#     asg-pbs-client: asg-pbs-client
-#     asg-cyclecloud: asg-cyclecloud
-#     asg-cyclecloud-client: asg-cyclecloud-client
-#     asg-nfs-client: asg-nfs-client
-#     asg-telegraf: asg-telegraf
-#     asg-grafana: asg-grafana
-#     asg-robinhood: asg-robinhood
-#     asg-ondemand: asg-ondemand
-#     asg-deployer: asg-deployer
-#     asg-mariadb-client: asg-mariadb-client
-    
-#  peering: # This list is optional, and can be used to create VNet Peerings in the same subscription.
-#    - vnet_name: #"VNET Name to Peer to"
-#      vnet_resource_group: #"Resource Group of the VNET to peer to"
-#      vnet_allow_gateway: false # optional: allow gateway transit (default: true)
-
-# Specify DNS forwarders available in the network
-# dns:
-#   forwarders:
-#     - { name: foo.com, ips: "10.2.0.4, 10.2.0.5" }
-
-# When working in a locked down network, uncomment and fill out this section
-locked_down_network:
-  enforce: false
-#   grant_access_from: [a.b.c.d] # Array of CIDR to grant access from, see https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security?tabs=azure-portal#grant-access-from-an-internet-ip-range
-  public_ip: true # Enable public IP creation for Jumpbox, OnDemand and create images. Default to true
-
-# NAT Gateway is used for outbound internet connectivity
-nat_gateway:
-  create: true
-  #name: foo # name to be used instead of the default one created for you
-
-# Base image configuration. Can be either an image reference or an image_id from the image registry or a custom managed image
-# For AlmaLinux 8.7 use almalinux:almalinux-x86_64:8_7-gen2:latest
-# For CentOS 7.9 use OpenLogic:CentOS:7_9-gen2:latest
-linux_base_image: "OpenLogic:CentOS:7_9-gen2:latest" # publisher:offer:sku:version or image_id
-# linux image plan if required, format is publisher:product:name
-#linux_base_plan:
-windows_base_image: "MicrosoftWindowsServer:WindowsServer:2019-Datacenter-smalldisk:latest" # publisher:offer:sku:version or image_id
-
-domain:
-  name: "hpc.azure"
-  #domain_join_ou: "OU=azhop" # OU to set the machine in. Make sure the OU exists in the domain as it won't be created for you
-  use_existing_dc: false # Set to true if you want to join a domain with existing DC
-  domain_join_user:
-    username: hpcadmin
-    password_key_vault_name: name_for_the_key_vault_with_the_domain_join_password
-    password_key_vault_resource_group_name: resource_group_name_for_the_key_vault_with_the_domain_join_password
-    password_key_vault_secret_name: key_vault_secret_name_for_the_domain_join_password
-  # additional settings when using an existinf DC
-  existing_dc_details: 
-    domain_controller_names: ["dc1", "dc2"]
-    domain_controller_ip_addresses: ["192.168.1.100", "192.168.1.101"]
-    private_dns_servers: ["192.168.1.53", "192.168.2.53"]
-
-# Optional: name of the key vault resource to be created. If not provided, a name will be generated
-# azure_key_vault:
-#   name: custom_key_vault_name
-
-# Optional: name of the storage account to be created.
-# azure_storage_account:
-#   name: custom_storage_account_name
-
-# Jumpbox VM configuration, only needed when deploying thru a public IP and without a configured deployer VM
-jumpbox:
-  name: jumpbox
-  vm_size: Standard_B2ms
-  # SSH port under which the jumpbox SSH server listens on the public IP. Default to 22
-  # Change this to, e.g., 2222, if security policies (like "zero trust") in your tenant automatically block access to port 22 from the internet
-  #ssh_port: 2222
-# Active directory VM configuration
-ad:
-  name: ad
-  vm_size: Standard_B2ms
-  hybrid_benefit: false # Enable hybrid benefit for AD, default to false
-  high_availability: false # Build AD in High Availability mode (2 Domain Controlers) - default to false
-  ha_name: ad2 # name of the HA AD machine when high_availability=true
-
-# On demand VM configuration
-ondemand:
-  name: ondemand # When provided, it will be used as the name of the VM. Default to ondemand
-  vm_size: Standard_D4s_v5
-  #fqdn: azhop.foo.com # When provided it will be used for the certificate server name
-  generate_certificate: true # Generate an SSL certificate for the OnDemand portal. Default to true
-  #whitelist_path: "{{mounts.home.mountpoint}}:/tmp" # Optional: colon-separated list of paths allowed in the file browser
-  #file_upload_max: 2048 # Maximum file upload size in bytes. Optional, default: 10GB
-  #file_upload_allowed_extensions: [".txt", ".log"] # List of allowed file extensions. Default: all files are allowed
-# Grafana VM configuration
-grafana:
-  name: grafana
-  vm_size: Standard_B2ms
-# Scheduler VM configuration
-scheduler:
-  name: scheduler # When provided, it will be used as the name of the scheduler VM. Default to scheduler
-  vm_size: Standard_B2ms
-# CycleCloud VM configuration
-cyclecloud:
-  name: ccportal # When provided, it will be used as the name of the CycleCloud VM. Default to ccportal
-  vm_size: Standard_B2ms
-  # version: # to specify a specific version, see https://packages.microsoft.com/yumrepos/cyclecloud/
-  # Optional: use Ubuntu for the CycleCloud VM (default: linux_base_image)
-  # image: "canonical:0001-com-ubuntu-server-focal:20_04-lts-gen2:latest"
-  # plan: publisher:product:name
-
-# Lustre cluster is optional and can be used to create a Lustre cluster in the environment.
-lustre:
-  create: false # true or false to create a lustre cluster
-  # Options: AMLFS-Durable-Premium-40, AMLFS-Durable-Premium-125, AMLFS-Durable-Premium-250, AMLFS-Durable-Premium-500
-  # See documentation for more details: https://learn.microsoft.com/en-us/azure/azure-managed-lustre/create-file-system-resource-manager
-  sku: AMLFS-Durable-Premium-250
-  # The step sizes are dependent on the SKU.
-  # - AMLFS-Durable-Premium-40: 48TB
-  # - AMLFS-Durable-Premium-125: 16TB
-  # - AMLFS-Durable-Premium-250: 8TB
-  # - AMLFS-Durable-Premium-500: 4TB
-  capacity: 8
-
-  # optional to use existing storage for the archive
-  # if not included it will use the azhop storage account that is created
-  # hsm:
-  #   storage_account: #existing_storage_account_name
-  #   storage_container: #only_used_with_existing_storage_account
-# List of users to be created on this environment
-users:
-  # name: username - must be less than 20 characters
-  # uid: uniqueid
-  # shell: /bin/bash # default to /bin/bash
-  # home: /anfhome/<user_name> # default to /homedir_mountpoint/user_name
-  # groups: list of groups the user belongs to
-  - { name: clusteradmin, uid: 10001, groups: [5001, 5002] }
-  - { name: hpcuser, uid: 10002 }
-  # - { name: user1, uid: 10003, groups: [6000] }
-  # - { name: user2, uid: 10004, groups: [6001] }
-
-usergroups:
-# These group names could be changed but not the gids as names will be mapped by gids
-  - name: azhop-users # All users will be added to this group by default
-    gid: 5000
-  - name: azhop-admins
-    gid: 5001
-    description: "For users with azhop admin privileges"
-  - name: azhop-localadmins
-    gid: 5002
-    description: "For users with sudo right or local admin right on nodes"
-# For custom groups use gid >= 6000
-  # - name: project1 # For project1 users
-  #   gid: 6000
-  # - name: project2 # For project2 users
-  #   gid: 6001
-
-# Enable cvmfs-eessi - disabled by default
-cvmfs_eessi:
-  enabled: false
-
-# scheduler to be installed and configured (openpbs, slurm)
-queue_manager: openpbs
-
-# Specific SLURM configuration
-slurm:
-  # Enable SLURM accounting, this will create a SLURM accounting database in a managed MariaDB server instance
-  accounting_enabled: false
-  # SLURM version to install. Currently supported: only [20.11.9 | 22.05.3] with cyclecloud_slurm_version==2.7.x and [22.05.9 | 23.02.5] with cyclecloud_slurm_version==3.0.x.
-  slurm_version: 22.05.9
-  # CycleCloud for SLURM project version as defined in https://github.com/Azure/cyclecloud-slurm/releases. Currently supported: 2.7.0-2.7.2, 3.0.4.
-  cyclecloud_slurm_version: 3.0.4
-  # Name of the SLURM cluster for accounting (optional, default to 'slurm')
-  # WARNING: changing this value on a running cluster will cause slurmctld to fail to start. This is a
-  # safety check to prevent accounting errors. To override, remove /var/spool/slurmd/clustername
-  cluster_name: slurm_azhop
-
-enroot:
-  enroot_version: 3.4.1
-
-#database:
-  # Resource name of the MariaDB instance to be created
-  #name: custom_mariadb_name
-
-  # If using an existing Managed MariaDB instance for SLURM accounting, specify these values
-  # Admin user of the database for which the password will be retrieved from the azhop keyvault
-  #user: sqladmin
-  # FQDN of the existing managed instance
-  #fqdn:
-  # IP of the managed private endpoint if the FQDN is not registered in a private DNS
-  #ip:
-
-# Create a Bastion in the bastion subnet when defined
-bastion:
-  create: false
-
-# Create a VPN Gateway in the gateway subnet when specified
-vpn_gateway:
-  create: false
-
-# Authentication configuration for accessing the az-hop portal
-# Default is basic authentication. For oidc authentication you have to specify the following values
-# The OIDCClient secret need to be stored as a secret named <oidc-client-id>-password in the keyvault used by az-hop
-authentication:
-  user_auth: ad # local or ad - default to ad. Local will create local users and users groups on all infrastructure VMs and dynamically on dynamic nodes
-  httpd_auth: basic # oidc or basic
-  # User mapping https://osc.github.io/ood-documentation/latest/reference/files/ood-portal-yml.html#ood-portal-generator-user-map-match
-  # You can specify either a map_match or a user_map_cmd
-  # Domain users are mapped to az-hop users with the same name and without the domain name
-  # user_map_match: '^([^@]+)@mydomain.foo$'
-  # If using a custom mapping script, update it from the ./playbooks/files directory before running the playbook
-  # user_map_cmd: /opt/ood/ood_auth_map/bin/custom_mapping.sh
-  # ood_auth_openidc:
-  #   OIDCProviderMetadataURL: # for AAD use 'https://sts.windows.net/{{tenant_id}}/.well-known/openid-configuration'
-  #   OIDCClientID: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
-  #   OIDCRemoteUserClaim: # for AAD use 'upn'
-  #   OIDCScope: # for AAD use 'openid profile email groups'
-  #   OIDCPassIDTokenAs: # for AAD use 'serialized'
-  #   OIDCPassRefreshToken: # for AAD use 'On'
-  #   OIDCPassClaimsAs: # for AAD use 'environment'
-  #   OIDCStateMaxNumberOfCookies: # in case of too many connections error for the same user set this to [10, true]
-
-image_gallery:
-  create: false # Create the shared image gallery to store custom images
-
-# List of images to be defined
-images:
-  # - name: image_definition_name # Should match the packer configuration file name, one per packer file
-  #   publisher: azhop
-  #   offer: CentOS
-  #   sku: 7_9-gen2
-  #   hyper_v: V2 # V1 or V2 (V1 is the default)
-  #   os_type: Linux # Linux or Windows
-  #   version: 7.9 # Version of the image to create the image definition in SIG. Pattern is major.minor where minor is mandatory
-# Pre-defined images
-  - name: azhop-compute-almalinux-8_7
-    publisher: azhop
-    offer: almalinux
-    sku: 8_7-hpc-gen2
-    hyper_v: V2
-    os_type: Linux
-    version: 8.7
-  - name: azhop-centos79-v2-rdma-gpgpu
-    publisher: azhop
-    offer: CentOS
-    sku: 7.9-gen2
-    hyper_v: V2
-    os_type: Linux
-    version: 7.9
-  # Image definition when using a custom image to build compute nodes images
-  - name: azhop-centos79-v2-rdma-ci
-    publisher: azhop
-    offer: CentOS
-    sku: 7.9-gen2-ci
-    hyper_v: V2
-    os_type: Linux
-    version: 7.9
-  # Image definition when using a custom image to build remote viz nodes images
-  - name: azhop-centos79-desktop3d-ci
-    publisher: azhop
-    offer: CentOS
-    sku: 7.9-gen2-desktop3d-ci
-    hyper_v: V2
-    os_type: Linux
-    version: 7.9
-  - name: azhop-centos79-desktop3d
-    publisher: azhop
-    offer: CentOS
-    sku: 7.9-gen2-desktop3d
-    hyper_v: V2
-    os_type: Linux
-    version: 7.9
-  - name: azhop-compute-centos-7_9
-    publisher: azhpc
-    offer: azhop-compute
-    sku: centos-7_9
-    hyper_v: V2
-    os_type: Linux
-    version: 7.9
-  - name: azhop-desktop-centos-7_9
-    publisher: azhpc
-    offer: azhop-desktop
-    sku: centos-7_9
-    hyper_v: V2
-    os_type: Linux
-    version: 7.9
-  - name: azhop-desktop-ubuntu-20_04
-    publisher: azhpc
-    offer: azhop-desktop
-    sku: ubuntu-2004
-    hyper_v: V2
-    os_type: Linux
-    version: 20.04
-  - name: azhop-win10
-    publisher: azhop
-    offer: Windows-10
-    sku: 21h1-pron
-    hyper_v: V1
-    os_type: Windows
-    version: 10.19043
-  # Base image when building your own HPC image and not using the HPC marketplace images
-  - name: base-centos79-v2-rdma
-    publisher: azhop
-    offer: CentOS
-    sku: 7.9-gen2-rdma-nogpu
-    hyper_v: V2
-    os_type: Linux
-    version: 7.9
-
-# Autoscale default settings for all queues, can be overriden on each queue depending on the VM type if needed
-autoscale:
-  idle_timeout: 1800 # Idle time in seconds before shutting down VMs - default to 1800 like in CycleCloud
-
-# List of queues (node arrays in Cycle) to be defined
-# don't use queue names longer than 8 characters in order to leave space for node suffix, as hostnames are limited to 15 chars due to domain join and NETBIOS constraints.
-queues:
-  - name: htc # name of the Cycle Cloud node array
-    # Azure VM Instance type
-    vm_size: Standard_F2s_v2
-    # maximum number of cores that can be instanciated
-    max_core_count: 1024
-      # maximum number of nodes that can be instanciated. The lower of the two will be used
-    max_count: 128
-    # Use the pre-built azhop image from the marketplace
-    image: azhpc:azhop-compute:centos-7_9:latest
-    # Use this image ID when building your own custom images
-    #image: /subscriptions/{{subscription_id}}/resourceGroups/{{resource_group}}/providers/Microsoft.Compute/galleries/{{sig_name}}/images/azhop-centos79-v2-rdma-gpgpu/latest
-    # Image plan specification (when needed for the image). Terms must be accepted prior to deployment
-    # plan: publisher:product:name
-    # Set to true if AccelNet need to be enabled. false is the default value
-    EnableAcceleratedNetworking: false
-    # spot instance support. Default is false
-    spot: false
-    # Set to false to disable creation of placement groups (for SLURM only). Default is true
-    ColocateNodes: false
-    # Specific idle time in seconds before shutting down VMs, make sure it's lower than autoscale.idle_timeout
-    idle_timeout: 300
-    # Set the max number of vm's in a VMSS; requires additional limit raise through support ticket for >100; 
-    # 100 is default value; lower numbers will improve scaling for single node jobs or jobs with small number of nodes
-    MaxScaleSetSize: 100
-    # Use ephemeral boot disk for VM, check here for supported family https://learn.microsoft.com/en-us/azure/virtual-machines/ephemeral-os-disks
-    EphemeralOSDisk: false
-  - name: hpc
-    vm_size: Standard_HB120rs_v3
-    max_count: 10
-    image: azhpc:azhop-compute:centos-7_9:latest
-    EnableAcceleratedNetworking: true
-  - name: gpu
-    vm_size: Standard_NC24ads_A100_v4
-    max_count: 0
-    image: azhpc:azhop-compute:centos-7_9:latest
-    EnableAcceleratedNetworking: true
-    # Queue dedicated to GPU remote viz nodes. This name is fixed and can't be changed
-  - name: viz3d
-    vm_size: Standard_NV12s_v3
-    max_count: 4
-    # Use the pre-built azhop image from the marketplace
-    image: azhpc:azhop-desktop:centos-7_9:latest
-    # Use this image ID when building your own custom images
-    #image: /subscriptions/{{subscription_id}}/resourceGroups/{{resource_group}}/providers/Microsoft.Compute/galleries/{{sig_name}}/images/azhop-centos79-desktop3d/latest
-    ColocateNodes: false
-    EnableAcceleratedNetworking: true
-    max_hours: 12 # Maximum session duration
-    min_hours: 1 # Minimum session duration - 0 is infinite
-    # Queue dedicated to share GPU remote viz nodes. This name is fixed and can't be changed
-  - name: largeviz3d
-    vm_size: Standard_NV48s_v3
-    max_count: 2
-    image: azhpc:azhop-desktop:centos-7_9:latest
-    ColocateNodes: false
-    EnableAcceleratedNetworking: true
-    max_hours: 12
-    min_hours: 1
-    # Queue dedicated to non GPU remote viz nodes. This name is fixed and can't be changed
-  - name: viz
-    vm_size: Standard_D8s_v5
-    max_count: 10
-    image: azhpc:azhop-desktop:centos-7_9:latest
-    ColocateNodes: false
-    EnableAcceleratedNetworking: true
-    max_hours: 12
-    min_hours: 1
-
-# Application settings
-applications:
-  bc_codeserver:
-    enabled: true
-  bc_jupyter:
-    enabled: true
-  bc_amlsdk:
-    enabled: false
-  bc_rstudio:
-    enabled: false
-  bc_ansys_workbench:
-    enabled: false
-  bc_vmd:
-    enabled: false
-  bc_paraview:
-    enabled: false
-  bc_vizer:
-    enabled: false
-```
 
 # Deploy your environment
 
diff --git a/playbooks/nodearray_lookup.yml b/playbooks/nodearray_lookup.yml
index a6785690b..eecb3e672 100644
--- a/playbooks/nodearray_lookup.yml
+++ b/playbooks/nodearray_lookup.yml
@@ -41,6 +41,13 @@
       delegate_to: ondemand
       become: true
 
+    - name: Copy the viz node configuration file
+      template:
+        src: 'viz_nodes.yml.j2'
+        dest: '/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml'
+      delegate_to: ondemand
+      become: true
+
     # - name: create config directory
     #   file:
     #     path: /etc/ood/config/apps/bc_desktop/config
diff --git a/playbooks/ood-overrides-common.yml b/playbooks/ood-overrides-common.yml
index b133fbec4..6d493d1bb 100755
--- a/playbooks/ood-overrides-common.yml
+++ b/playbooks/ood-overrides-common.yml
@@ -39,7 +39,7 @@ ood_apps:
     form:
       - desktop
       - target
-      - num_hours
+      - bc_num_hours
       - bucket
     attributes:
       desktop: xfce
@@ -48,23 +48,8 @@ ood_apps:
         label: "Session target"
         help: |
           Select the resource target for the remote desktop session <br>
-          - **With GPU** <br>
-            These are standard small GPU nodes for visualization for a single user session.<br>
-          - **Large With GPU** <br>
-            These are standard large GPU nodes for visualization, usually for multiple users sessions sharing the same node.<br>
-          - **Without GPU** <br>
-            Same as for **With GPU** but without a GPU accelerator.
-        options:
-         - ["With GPU - Small GPU node for single session", "viz3d", data-hide-bucket: true, data-set-bucket: 1, 
-              data-max-num-hours: "{{ (queues | selectattr('name', 'equalto', 'viz3d') | map(attribute='max_hours', default=8)) }}", 
-              data-min-num-hours: "{{ (queues | selectattr('name', 'equalto', 'viz3d') | map(attribute='min_hours', default=1)) }}"]
-         - ["Large With GPU - Intented for shared sessions", "largeviz3d", 
-              data-max-num-hours: "{{ (queues | selectattr('name', 'equalto', 'largeviz3d') | map(attribute='max_hours', default=8)) }}", 
-              data-min-num-hours: "{{ (queues | selectattr('name', 'equalto', 'largeviz3d') | map(attribute='min_hours', default=1)) }}"]
-         - ["Without GPU - for single session", "viz", data-hide-bucket: true, data-set-bucket: 1, 
-              data-max-num-hours: "{{ (queues | selectattr('name', 'equalto', 'viz') | map(attribute='max_hours', default=8)) }}", 
-              data-min-num-hours: "{{ (queues | selectattr('name', 'equalto', 'viz') | map(attribute='min_hours', default=1)) }}"]
-      num_hours:
+        options: #__TARGET_OPTIONS__
+      bc_num_hours:
         widget: "number_field"
         label: "Maximum duration in hours of your remote session"
         value: 1
diff --git a/playbooks/ood-overrides-openpbs.yml b/playbooks/ood-overrides-openpbs.yml
index 6cbc0d78c..462050488 100755
--- a/playbooks/ood-overrides-openpbs.yml
+++ b/playbooks/ood-overrides-openpbs.yml
@@ -14,12 +14,6 @@ ood_apps:
 
         scheduler_args = ["-q", "vizq"]
 
-        # If the user has specified a number of hours, set the job walltime
-        hours = num_hours.to_i
-        if hours > 0
-          scheduler_args += ["-l", "walltime=%02d:00:00" % hours]
-        end
-
         # If the user has specified a node ratio greather than 1, set the job ppn
         node_ratio = bucket.to_i
         node_arrays = YAML.load_file("/etc/ood/config/apps/bc_desktop/config/node_arrays.yml")
diff --git a/playbooks/ood-overrides-slurm.yml b/playbooks/ood-overrides-slurm.yml
index cbe301b11..d8e5d94ff 100755
--- a/playbooks/ood-overrides-slurm.yml
+++ b/playbooks/ood-overrides-slurm.yml
@@ -12,12 +12,6 @@ ood_apps:
         require "yaml"
         scheduler_args = ["-p", target]
 
-        # If the user has specified a number of hours, set the job walltime
-        hours = num_hours.to_i
-        if hours > 0
-          scheduler_args += ["-t", "%02d:00:00" % hours]
-        end
-
         # If the user has specified a node ratio greather than 1, set the job ppn
         node_ratio = bucket.to_i
         node_arrays = YAML.load_file("/etc/ood/config/apps/bc_desktop/config/node_arrays.yml")
diff --git a/playbooks/ood.yml b/playbooks/ood.yml
index 315ae374e..81887216d 100644
--- a/playbooks/ood.yml
+++ b/playbooks/ood.yml
@@ -21,6 +21,23 @@
   - name: Gather facts for first time
     setup:
 
+  - name: copy bc_desktop file
+    copy:
+      remote_src: true
+      src: /etc/ood/config/apps/bc_desktop/ondemand.yml
+      dest: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
+
+  - name: configure bc_desktop to dynamically load viz targets
+    blockinfile:
+      path: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
+      insertafter : "__TARGET_OPTIONS__"
+      backup: no
+      block: |
+        # Dynamically load viz targets - keep indentation as is
+                <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
+                    <%= line.to_s %>
+                <%- end %>      
+
   - name: set httpd_auth values when using basic auth
     block:
       - name: set httpd_auth values when using basic auth on Alma 8
diff --git a/playbooks/roles/ood-applications/files/bc_ansys_workbench/form.yml.erb b/playbooks/roles/ood-applications/files/bc_ansys_workbench/form.yml.erb
index 59c91d0e5..2685a6896 100644
--- a/playbooks/roles/ood-applications/files/bc_ansys_workbench/form.yml.erb
+++ b/playbooks/roles/ood-applications/files/bc_ansys_workbench/form.yml.erb
@@ -25,22 +25,10 @@ attributes:
     label: "Session target"
     help: |
       Select the resource target for the remote desktop session <br>
-      - **With GPU** <br>
-        These are standard small GPU nodes for visualization for a single user session.<br>
-      - **Large With GPU** <br>
-        These are standard large GPU nodes for visualization, usually for multiple users sessions sharing the same node.<br>
-      - **Without GPU** <br>
-        Same as for **With GPU** but without a GPU accelerator.
     options:
-      - ["With GPU - Small GPU node for single session", "viz3d", data-hide-bucket: true, data-set-bucket: 1, 
-          data-max-bc-num-hours: "8", 
-          data-min-bc-num-hours: "1"]
-      - ["Large With GPU - Intented for shared sessions", "largeviz3d", 
-          data-max-bc-num-hours: "8", 
-          data-min-bc-num-hours: "1"]
-      - ["Without GPU - for single session", "viz", data-hide-bucket: true, data-set-bucket: 1, 
-          data-max-bc-num-hours: "8", 
-          data-min-bc-num-hours: "1"]
+    <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
+      <%= line.to_s %>
+    <%- end %>
   bucket:
       widget: "select"
       label: "Node bucket"
diff --git a/playbooks/roles/ood-applications/files/bc_paraview/form.yml.erb b/playbooks/roles/ood-applications/files/bc_paraview/form.yml.erb
index 901c0cbfb..39466f9b4 100644
--- a/playbooks/roles/ood-applications/files/bc_paraview/form.yml.erb
+++ b/playbooks/roles/ood-applications/files/bc_paraview/form.yml.erb
@@ -12,8 +12,6 @@ attributes:
         widget: "number_field"
         label: "Maximum duration in hours of your session"
         value: 1
-        min: 1
-        max: 8
         help: |
             This is the maximum duration in hours of your session once started.
         step: 1
@@ -22,22 +20,10 @@ attributes:
         label: "Node type"
         help: |
             Select the resource target for the remote desktop session <br>
-            - **With GPU** <br>
-                These are standard small GPU nodes for visualization for a single user session.<br>
-            - **Large With GPU** <br>
-                These are standard large GPU nodes for visualization, usually for multiple users sessions sharing the same node.<br>
-            - **Without GPU** <br>
-                Same as for **With GPU** but without a GPU accelerator.
         options:
-            - ["With GPU - Small GPU node for single session", "viz3d", data-hide-bucket: true, data-set-bucket: 1,
-                data-max-bc-num-hours: "8",
-                data-min-bc-num-hours: "1"]
-            - ["Large With GPU - Intented for shared sessions", "largeviz3d",
-                data-max-bc-num-hours: "8",
-                data-min-bc-num-hours: "1"]
-            - ["Without GPU - for single session", "viz", data-hide-bucket: true, data-set-bucket: 1,
-                data-max-bc-num-hours: "8",
-                data-min-bc-num-hours: "1"]
+        <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
+            <%= line.to_s %>
+        <%- end %>
     bucket:
         widget: "select"
         label: "Node bucket"
diff --git a/playbooks/roles/ood-applications/files/bc_vizer/form.yml.erb b/playbooks/roles/ood-applications/files/bc_vizer/form.yml.erb
index 9e0561552..ced1155bf 100644
--- a/playbooks/roles/ood-applications/files/bc_vizer/form.yml.erb
+++ b/playbooks/roles/ood-applications/files/bc_vizer/form.yml.erb
@@ -22,22 +22,10 @@ attributes:
         label: "Node type"
         help: |
             Select the resource target for the remote desktop session <br>
-            - **With GPU** <br>
-                These are standard small GPU nodes for visualization for a single user session.<br>
-            - **Large With GPU** <br>
-                These are standard large GPU nodes for visualization, usually for multiple users sessions sharing the same node.<br>
-            - **Without GPU** <br>
-                Same as for **With GPU** but without a GPU accelerator.
         options:
-            - ["With GPU - Small GPU node for single session", "viz3d", data-hide-bucket: true, data-set-bucket: 1,
-                data-max-bc-num-hours: "8",
-                data-min-bc-num-hours: "1"]
-            - ["Large With GPU - Intented for shared sessions", "largeviz3d",
-                data-max-bc-num-hours: "8",
-                data-min-bc-num-hours: "1"]
-            - ["Without GPU - for single session", "viz", data-hide-bucket: true, data-set-bucket: 1,
-                data-max-bc-num-hours: "8",
-                data-min-bc-num-hours: "1"]
+        <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
+            <%= line.to_s %>
+        <%- end %>
     bucket:
         widget: "select"
         label: "Node bucket"
diff --git a/playbooks/roles/ood-applications/files/bc_vmd/form.yml.erb b/playbooks/roles/ood-applications/files/bc_vmd/form.yml.erb
index e09a60939..ab34ba986 100644
--- a/playbooks/roles/ood-applications/files/bc_vmd/form.yml.erb
+++ b/playbooks/roles/ood-applications/files/bc_vmd/form.yml.erb
@@ -24,22 +24,10 @@ attributes:
     label: "Session target"
     help: |
       Select the resource target for the remote desktop session <br>
-      - **With GPU** <br>
-        These are standard small GPU nodes for visualization for a single user session.<br>
-      - **Large With GPU** <br>
-        These are standard large GPU nodes for visualization, usually for multiple users sessions sharing the same node.<br>
-      - **Without GPU** <br>
-        Same as for **With GPU** but without a GPU accelerator.
     options:
-      - ["With GPU - Small GPU node for single session", "viz3d", data-hide-bucket: true, data-set-bucket: 1, 
-          data-max-bc-num-hours: "8", 
-          data-min-bc-num-hours: "1"]
-      - ["Large With GPU - Intented for shared sessions", "largeviz3d", 
-          data-max-bc-num-hours: "8", 
-          data-min-bc-num-hours: "1"]
-      - ["Without GPU - for single session", "viz", data-hide-bucket: true, data-set-bucket: 1, 
-          data-max-bc-num-hours: "8", 
-          data-min-bc-num-hours: "1"]
+        <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
+            <%= line.to_s %>
+        <%- end %>
   bucket:
       widget: "select"
       label: "Node bucket"
diff --git a/playbooks/templates/viz_nodes.yml.j2 b/playbooks/templates/viz_nodes.yml.j2
new file mode 100644
index 000000000..2d8e49bb6
--- /dev/null
+++ b/playbooks/templates/viz_nodes.yml.j2
@@ -0,0 +1,3 @@
+{% for queue in ( queues | rejectattr('type', 'undefined') | selectattr('type', 'match', 'remoteviz'))%}
+- ["{{ queue.description | default(queue.name) }}", "{{ queue.name }}", data-max-bc-num-hours: {{ queue.max_hours | default(8) }}, data-min-bc-num-hours: {{ queue.min_hours | default(1) }}{% if (queue.shareable is not defined) or (queue.shareable is defined and not queue.shareable) %}, data-hide-bucket: true, data-set-bucket: 1 {% endif %}]
+{% endfor %}

From a06812636afcc121e920dc95d1c8a49d3d54b06b Mon Sep 17 00:00:00 2001
From: "Xavier Pillons (MSFT)" <xpillons@microsoft.com>
Date: Thu, 4 Jan 2024 11:30:43 +0100
Subject: [PATCH 3/5] move bc_desktop configuration at the end

---
 playbooks/ood.yml | 39 ++++++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/playbooks/ood.yml b/playbooks/ood.yml
index 81887216d..7e783a397 100644
--- a/playbooks/ood.yml
+++ b/playbooks/ood.yml
@@ -21,24 +21,7 @@
   - name: Gather facts for first time
     setup:
 
-  - name: copy bc_desktop file
-    copy:
-      remote_src: true
-      src: /etc/ood/config/apps/bc_desktop/ondemand.yml
-      dest: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
-
-  - name: configure bc_desktop to dynamically load viz targets
-    blockinfile:
-      path: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
-      insertafter : "__TARGET_OPTIONS__"
-      backup: no
-      block: |
-        # Dynamically load viz targets - keep indentation as is
-                <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
-                    <%= line.to_s %>
-                <%- end %>      
-
-  - name: set httpd_auth values when using basic auth
+   - name: set httpd_auth values when using basic auth
     block:
       - name: set httpd_auth values when using basic auth on Alma 8
         set_fact:
@@ -555,13 +538,31 @@
         shell: cvmfs_config setup 
     when:  ( cvmfs_eessi.enabled | default(false) )
 
-  # Generate the node array core lookup file for ondemand - will be only run if the marker file for ondemand exists
   - name: "yq: Download and install (CentOS)"
     get_url:
       url: "https://github.com/mikefarah/yq/releases/download/{{ yq_version }}/{{ yq_binary }}"
       dest: /usr/bin/yq
       mode: 0755
 
+# Configure bc_desktop for dynamic remote viz targets
+  - name: copy bc_desktop file
+    copy:
+      remote_src: true
+      src: /etc/ood/config/apps/bc_desktop/ondemand.yml
+      dest: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
+
+  - name: configure bc_desktop to dynamically load viz targets
+    blockinfile:
+      path: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
+      insertafter : "__TARGET_OPTIONS__"
+      backup: no
+      block: |
+        # Dynamically load viz targets - keep indentation as is
+                <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
+                    <%= line.to_s %>
+                <%- end %>
+
+  # Generate the node array core lookup file for ondemand - will be only run if the marker file for ccluster exists
   - import_tasks: nodearray_lookup.yml
     vars:
       marker_file: cccluster.ok

From a521164e19dc6e922a01557c2a622d1dd32edcab Mon Sep 17 00:00:00 2001
From: "Xavier Pillons (MSFT)" <xpillons@microsoft.com>
Date: Thu, 4 Jan 2024 11:57:57 +0100
Subject: [PATCH 4/5] fix yml typo

---
 playbooks/ood.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/playbooks/ood.yml b/playbooks/ood.yml
index 7e783a397..7cefbe17c 100644
--- a/playbooks/ood.yml
+++ b/playbooks/ood.yml
@@ -21,7 +21,7 @@
   - name: Gather facts for first time
     setup:
 
-   - name: set httpd_auth values when using basic auth
+  - name: set httpd_auth values when using basic auth
     block:
       - name: set httpd_auth values when using basic auth on Alma 8
         set_fact:

From 0d4d076dace9122c7640cefcf4fce738982110f9 Mon Sep 17 00:00:00 2001
From: "Xavier Pillons (MSFT)" <xpillons@microsoft.com>
Date: Thu, 4 Jan 2024 15:47:04 +0100
Subject: [PATCH 5/5] fix ruby code injection for dynamic list

---
 playbooks/ood-overrides-common.yml | 2 +-
 playbooks/ood.yml                  | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/playbooks/ood-overrides-common.yml b/playbooks/ood-overrides-common.yml
index 6d493d1bb..7251ea5ed 100755
--- a/playbooks/ood-overrides-common.yml
+++ b/playbooks/ood-overrides-common.yml
@@ -48,7 +48,7 @@ ood_apps:
         label: "Session target"
         help: |
           Select the resource target for the remote desktop session <br>
-        options: #__TARGET_OPTIONS__
+        options:
       bc_num_hours:
         widget: "number_field"
         label: "Maximum duration in hours of your remote session"
diff --git a/playbooks/ood.yml b/playbooks/ood.yml
index 7cefbe17c..7b41697db 100644
--- a/playbooks/ood.yml
+++ b/playbooks/ood.yml
@@ -554,13 +554,18 @@
   - name: configure bc_desktop to dynamically load viz targets
     blockinfile:
       path: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
-      insertafter : "__TARGET_OPTIONS__"
+      insertafter : "options: null"
       backup: no
       block: |
         # Dynamically load viz targets - keep indentation as is
                 <%- File.readlines("/etc/ood/config/apps/bc_desktop/config/viz_nodes.yml").each do |line|  %>
                     <%= line.to_s %>
                 <%- end %>
+  - name: remove the null value of the options
+    replace:
+      path: /etc/ood/config/apps/bc_desktop/ondemand.yml.erb
+      regexp: 'options: null'
+      replace: 'options:' 
 
   # Generate the node array core lookup file for ondemand - will be only run if the marker file for ccluster exists
   - import_tasks: nodearray_lookup.yml