Skip to content

Feature/vm deploy - #3

Merged
zul-m merged 4 commits into
mainfrom
feature/vm-deploy
Jul 9, 2026
Merged

Feature/vm deploy#3
zul-m merged 4 commits into
mainfrom
feature/vm-deploy

Conversation

@zul-m

@zul-m zul-m commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features
    • Added vm-deploy guided deployment via an interactive/parameterized script with Terraform/Azure preflight checks and safer destroy confirmation.
    • Created a Terraform Azure Windows VM stack with restricted inbound RDP/WinRM, static public IP, scheduled auto-shutdown, WinRM HTTPS bootstrap, and post-provision Ansible setup (incl. SQL Server tooling).
    • Added Terraform outputs and a full terraform.tfvars example template.
  • Documentation
    • Added complete vm-deploy/README.md with prerequisites, configuration, deploy flows, and expected outputs.
  • Bug Fixes
    • Ignored Terraform local state, caches, plans, and secret-bearing files in version control.
  • Chores
    • Pinned Terraform version/provider constraints and added Ansible collection version requirements/lock content.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@zul-m, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7aaa3c6c-008b-46f4-93c5-bc65591e006c

📥 Commits

Reviewing files that changed from the base of the PR and between ae948a6 and 2cf64c8.

📒 Files selected for processing (1)
  • vm-deploy/deploy.ps1
📝 Walkthrough

Walkthrough

Adds a new vm-deploy stack with Terraform, Ansible, and PowerShell to provision an Azure Windows VM, restrict inbound access, bootstrap WinRM HTTPS, run post-provision application setup, and document the deployment flow.

Changes

VM Deploy Terraform + Ansible Stack

Layer / File(s) Summary
Variables, provider versions, example tfvars
vm-deploy/variables.tf, vm-deploy/versions.tf, vm-deploy/terraform.tfvars.example, vm-deploy/.terraform.lock.hcl
Defines the Terraform inputs, provider constraints/configuration, example variable values, and locked provider versions.
Networking, NSG, and VM bootstrap
vm-deploy/main.tf
Builds the Azure network, allowlisted NSG rules, VM, WinRM HTTPS bootstrap, shutdown schedule, and Terraform-triggered Ansible execution.
Ansible application and SQL provisioning
vm-deploy/ansible/playbooks/applications.yml, vm-deploy/ansible/requirements.yml
Installs Windows tooling, SQL Server, SSMS, and Notepad++, creates the SQL admin login, and declares Ansible collection requirements.
Terraform outputs
vm-deploy/outputs.tf
Exports the resource group, VNet, VM IPs, RDP target, and VM name.
PowerShell deployment wrapper
vm-deploy/deploy.ps1
Adds interactive and parameter-driven Terraform execution with Azure login checks, profile selection, and destroy confirmation.
Documentation and ignore rules
vm-deploy/README.md, vm-deploy/.gitignore
Adds deployment documentation and ignore rules for Terraform state, plans, tfvars, overrides, and editor noise.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DeployPS1
  participant Terraform
  participant AzureVM
  participant Ansible
  User->>DeployPS1: run deploy.ps1
  DeployPS1->>Terraform: terraform init and action command
  Terraform->>AzureVM: create VM, NSG, WinRM HTTPS listener
  Terraform->>Ansible: local-exec after dependencies are ready
  Ansible->>AzureVM: connect over WinRM HTTPS
  Ansible->>AzureVM: install applications and SQL Server
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the change, but it's too generic and reads like a branch name rather than a clear summary. Rename it to a concise, specific summary such as "Add Azure Windows VM deployment stack".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/vm-deploy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (3)
vm-deploy/ansible/requirements.yml (1)

1-4: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Pin collection versions for reproducibility.

Unpinned collections can introduce breaking changes on ansible-galaxy collection install. Consider pinning to specific versions.

♻️ Proposed fix
 collections:
-  - name: ansible.windows
-  - name: chocolatey.chocolatey
+  - name: ansible.windows
+    version: "2.0.0"
+  - name: chocolatey.chocolatey
+    version: "1.5.0"

Verify the latest compatible versions for your Ansible runtime before pinning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vm-deploy/ansible/requirements.yml` around lines 1 - 4, The Ansible
collections in requirements.yml are currently unpinned, which can make installs
non-reproducible. Update the collection entries for ansible.windows and
chocolatey.chocolatey to include explicit version constraints that match the
compatible Ansible runtime. Keep the change in requirements.yml so
ansible-galaxy collection install always resolves the same versions.
vm-deploy/main.tf (2)

198-201: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add NSG-subnet association to depends_on

NSG rules are not enforced until the NSG is associated with the subnet. Without this dependency, there's no guarantee the association exists when Ansible attempts to connect. Until the association is created, the subnet has no NSG — meaning the VM is briefly open to all inbound traffic from the internet.

🔒 Proposed fix: add association dependency
   depends_on = [
+    azurerm_subnet_network_security_group_association.vm,
     azurerm_network_security_rule.allow_winrm,
     azurerm_virtual_machine_extension.winrm_https,
   ]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vm-deploy/main.tf` around lines 198 - 201, The WinRM-related resource block
is missing the subnet NSG association in its dependency chain, so `depends_on`
only waits for `azurerm_network_security_rule.allow_winrm` and
`azurerm_virtual_machine_extension.winrm_https`. Update the `depends_on` list to
also include the NSG-to-subnet association resource used in this module so the
association is guaranteed before Ansible connects, and keep the change localized
to this VM deployment resource.

128-130: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

WinRM bootstrap script lacks error handling

The semicolon-separated PowerShell commands continue even if New-SelfSignedCertificate fails. The extension may report success while WinRM HTTPS is broken, causing Ansible to fail with a confusing connection error. Add $ErrorActionPreference='Stop' and a null check to fail fast.

♻️ Proposed fix: add error handling
-    commandToExecute = "powershell -ExecutionPolicy Unrestricted -Command \"$cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\\LocalMachine\\My; New-Item -Path WSMan:\\LocalHost\\Listener -Transport HTTPS -Address * -CertificateThumbPrint $cert.Thumbprint -Force; netsh advfirewall firewall add rule name='WinRM HTTPS' dir=in action=allow protocol=TCP localport=5986 | Out-Null\""
+    commandToExecute = "powershell -ExecutionPolicy Unrestricted -Command \"$ErrorActionPreference='Stop'; $cert = New-SelfSignedCertificate -DnsName $env:COMPUTERNAME -CertStoreLocation Cert:\\LocalMachine\\My; if (-not $cert) { throw 'Failed to create self-signed certificate' }; New-Item -Path WSMan:\\LocalHost\\Listener -Transport HTTPS -Address * -CertificateThumbPrint $cert.Thumbprint -Force; netsh advfirewall firewall add rule name='WinRM HTTPS' dir=in action=allow protocol=TCP localport=5986 | Out-Null\""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vm-deploy/main.tf` around lines 128 - 130, The WinRM bootstrap command in
protected_settings lacks fail-fast error handling, so failures in the
certificate creation path can be masked. Update the commandToExecute PowerShell
sequence to stop on errors by setting $ErrorActionPreference to Stop, then
explicitly verify the result of New-SelfSignedCertificate before using
$cert.Thumbprint; if the certificate is missing or null, abort the script so the
extension fails instead of reporting success. Use the commandToExecute block in
protected_settings to locate the fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@vm-deploy/ansible/playbooks/applications.yml`:
- Line 48: The SQL install task is masking failures by setting failed_when to
false, which prevents sql_install_result.failed checks from ever becoming true.
Update the SQL Server installation flow in the playbook so the follow-up debug
and fail tasks key off the command return code from the sql install result
instead of the failed flag, and remove the error-suppression behavior from the
install step. Keep the logic centered around the SQL install task and the
sql_install_result checks so actual installation failures surface correctly.
- Line 7: The `sql_admin_password` variable is currently allowed to fall back to
an empty string, which can break SQL Server setup and later `sqlcmd`
authentication. In `applications.yml`, add an early validation step before the
install/connect tasks that checks `sql_admin_password` is set and non-empty, and
fail fast with a clear message if it is missing. Use the `sql_admin_password`
variable and the existing SQL Server install/connect tasks as the place to wire
this guard in.
- Around line 88-98: The SQL admin login task leaks the SA password on the
command line and directly embeds an Ansible variable into the PowerShell script.
Update the `Create SQL admin login for SQL Authentication mode` `win_shell`
block so `sql_admin_password` is passed safely via an environment variable or
stdin to `sqlcmd`, and avoid interpolating it directly into the script text.
Also keep the existing escaping around `sql_admin_username` in the
`$safeSqlAdmin` / `$safeSqlAdminLiteral` logic, and use a safely sourced
`$saPassword` value instead of assigning it from `{{ sql_admin_password }}`.

In `@vm-deploy/deploy.ps1`:
- Around line 205-220: The deploy script currently relies on terraform being
available and on Write-Error, which does not stop execution. In deploy.ps1,
before calling terraform in the try block around Ensure-AzLogin, add a preflight
check that verifies terraform is on PATH and fail immediately with a terminating
error if it is missing. Also change the terraform init and terraform `@tfArgs`
failure handling so a nonzero exit code stops the script instead of falling
through to the next command.

In `@vm-deploy/main.tf`:
- Line 170: The current $playbookArgs construction in the deployment flow
exposes ansible_password and sql_admin_password on the command line; update the
ansible-playbook invocation to stop passing sensitive values inline. In the
logic that builds and executes the Linux and WSL paths, write the extra vars to
a temporary file with restricted permissions, switch the command to use
--extra-vars @<temp file>, and ensure the temp file is deleted afterward in both
branches. Keep the fix localized around the $playbookArgs / ansible-playbook
execution code so the credentials never appear in process listings.
- Around line 6-8: The resource naming in the main Terraform locals is using
plantimestamp(), which makes date_suffix change on every new plan and forces
full replacement of Azure resources. Update the local values used by
resource_prefix and resource_group_name to rely on a stable identifier instead
of plantimestamp(), such as a new suffix variable or a random_string-style
persistent value, so the names remain consistent across applies and do not
trigger unnecessary recreation.

In `@vm-deploy/README.md`:
- Around line 53-59: Update the Deploy section in the README to document the
deploy.ps1 wrapper script alongside the existing Terraform commands. Add
examples using the deploy.ps1 entry point (including the interactive menu and a
non-interactive apply invocation with -OsVersion, -Action, and -AutoApprove) and
then keep the manual terraform init/plan/apply commands as a separate “Manual
Terraform commands” option. Make sure the section references deploy.ps1 clearly
so users can discover the OS selection menu, auto-approve flow, and Azure login
preflight.

In `@vm-deploy/variables.tf`:
- Around line 100-105: The `sql_admin_password` variable in `variables.tf`
currently defaults to an empty string even though mixed-mode auth is always
enabled, so add a validation block on `sql_admin_password` to require a
non-empty value. Update the `variable "sql_admin_password"` definition to reject
`""` (and other blank values if applicable) with a clear error message, so
deployments using this input cannot accidentally create a SQL login with an
empty password.

In `@vm-deploy/versions.tf`:
- Around line 5-8: The AzureRM provider constraint in the terraform versions
configuration is still pinned to the 3.x line, which is deprecated; update the
azurerm version constraint in versions.tf to a 4.x-compatible range, and verify
any dependent resources or modules in the vm-deploy stack are adjusted for the
new provider behavior, using the azurerm block as the main locator.

---

Nitpick comments:
In `@vm-deploy/ansible/requirements.yml`:
- Around line 1-4: The Ansible collections in requirements.yml are currently
unpinned, which can make installs non-reproducible. Update the collection
entries for ansible.windows and chocolatey.chocolatey to include explicit
version constraints that match the compatible Ansible runtime. Keep the change
in requirements.yml so ansible-galaxy collection install always resolves the
same versions.

In `@vm-deploy/main.tf`:
- Around line 198-201: The WinRM-related resource block is missing the subnet
NSG association in its dependency chain, so `depends_on` only waits for
`azurerm_network_security_rule.allow_winrm` and
`azurerm_virtual_machine_extension.winrm_https`. Update the `depends_on` list to
also include the NSG-to-subnet association resource used in this module so the
association is guaranteed before Ansible connects, and keep the change localized
to this VM deployment resource.
- Around line 128-130: The WinRM bootstrap command in protected_settings lacks
fail-fast error handling, so failures in the certificate creation path can be
masked. Update the commandToExecute PowerShell sequence to stop on errors by
setting $ErrorActionPreference to Stop, then explicitly verify the result of
New-SelfSignedCertificate before using $cert.Thumbprint; if the certificate is
missing or null, abort the script so the extension fails instead of reporting
success. Use the commandToExecute block in protected_settings to locate the fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f7f52ec8-690a-4339-b10f-294b7964c7b6

📥 Commits

Reviewing files that changed from the base of the PR and between 826420a and b05766b.

📒 Files selected for processing (10)
  • vm-deploy/.gitignore
  • vm-deploy/README.md
  • vm-deploy/ansible/playbooks/applications.yml
  • vm-deploy/ansible/requirements.yml
  • vm-deploy/deploy.ps1
  • vm-deploy/main.tf
  • vm-deploy/outputs.tf
  • vm-deploy/terraform.tfvars.example
  • vm-deploy/variables.tf
  • vm-deploy/versions.tf

Comment thread vm-deploy/ansible/playbooks/applications.yml
Comment thread vm-deploy/ansible/playbooks/applications.yml Outdated
Comment thread vm-deploy/ansible/playbooks/applications.yml Outdated
Comment thread vm-deploy/deploy.ps1
Comment thread vm-deploy/main.tf Outdated
Comment thread vm-deploy/main.tf Outdated
Comment thread vm-deploy/README.md
Comment thread vm-deploy/variables.tf
Comment thread vm-deploy/versions.tf
@zul-m zul-m linked an issue Jul 9, 2026 that may be closed by this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
vm-deploy/deploy.ps1 (1)

78-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use an approved PowerShell verb for this helper.

Ensure-TerraformInstalled triggers PSUseApprovedVerbs; Assert-TerraformInstalled keeps the throwing preflight semantics while satisfying the analyzer.

♻️ Proposed rename
-function Ensure-TerraformInstalled {
+function Assert-TerraformInstalled {
     if (-not (Get-Command terraform -ErrorAction SilentlyContinue)) {
         throw "Terraform is not installed or not on PATH. Install it first: https://developer.hashicorp.com/terraform/downloads"
     }
 }
@@
-    Ensure-TerraformInstalled
+    Assert-TerraformInstalled

Also applies to: 213-213

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vm-deploy/deploy.ps1` around lines 78 - 82, Rename the helper to use an
approved PowerShell verb while keeping the same preflight behavior: change
Ensure-TerraformInstalled to Assert-TerraformInstalled, and update any call
sites in deploy.ps1 that invoke this helper so they match the new name. Keep the
existing throw-on-missing-Terraform logic unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@vm-deploy/deploy.ps1`:
- Around line 78-82: Rename the helper to use an approved PowerShell verb while
keeping the same preflight behavior: change Ensure-TerraformInstalled to
Assert-TerraformInstalled, and update any call sites in deploy.ps1 that invoke
this helper so they match the new name. Keep the existing
throw-on-missing-Terraform logic unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: de98afac-864b-42ba-a116-3d163400b813

📥 Commits

Reviewing files that changed from the base of the PR and between b05766b and ae948a6.

📒 Files selected for processing (8)
  • vm-deploy/.terraform.lock.hcl
  • vm-deploy/README.md
  • vm-deploy/ansible/playbooks/applications.yml
  • vm-deploy/ansible/requirements.yml
  • vm-deploy/deploy.ps1
  • vm-deploy/main.tf
  • vm-deploy/variables.tf
  • vm-deploy/versions.tf
✅ Files skipped from review due to trivial changes (3)
  • vm-deploy/ansible/requirements.yml
  • vm-deploy/.terraform.lock.hcl
  • vm-deploy/README.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • vm-deploy/variables.tf
  • vm-deploy/versions.tf
  • vm-deploy/main.tf
  • vm-deploy/ansible/playbooks/applications.yml

@zul-m zul-m left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Script to provision different environments

1 participant