AWS Terraform Windows with Node-Red

I'm trying to deploy a Windows Server via Terraform that installs Node-RED,

It gets to the script and seems to stop after the nodejs installation. Can't seems to get PATH variables to stick, but when I log into the remote server after deploy, I can install just fine when I manually enter the the list of commands via cmd.

Any Windows / Terraform gurus out there that can help make this work?

Here is the script section of the Terraform provision using user_data

  @echo off
  echo Deployment Script Started> C:\deploy.log
  netsh advfirewall firewall add rule name="Open Node-red port" protocol=TCP dir=in localport=1880 action=allow >> C:\deploy.log
  echo netsh advfirewall add rule 1880 complete>> C:\deploy.log
  @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command " [System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin;%ALLUSERSPROFILE%\Python3;" >> C:\deploy.log
  echo choco installed>> C:\deploy.log
  choco install python3 -y --override --installarguments "'/quiet  InstallAllUsers=1 TargetDir=%ALLUSERSPROFILE%\Python3'" >> C:\deploy.log
  echo Python 3 install in Python3>> C:\deploy.log
  choco install nodejs-lts -y >> C:\deploy.log
  echo nodejs installed>> C:\deploy.log 
  refreshenv
  npm install -g --unsafe-perm node-red >> C:\deploy.log
  echo node-red global>> C:\deploy.log
  npm install pm2-windows-startup -g >> C:\deploy.log
  echo install pm2 windows-startup>> C:\deploy.log
  pm2-startup install >> C:\deploy.log
  echo pm2-startup installed>> C:\deploy.log
  pm2 save >> C:\deploy.log 
  echo pm2 save>> C:\deploy.log >> C:\deploy.log
  pm2 start C:\Users\Administrator\AppData\Roaming\npm\node_modules\node-red\red.js -- --save >> C:\deploy.log
  echo pm2 start>> C:\deploy.log
  winrm quickconfig -q & winrm set winrm/config @{MaxTimeoutms="1800000"} & winrm set winrm/config/service @{AllowUnencrypted="true"} & winrm set winrm/config/service/auth @{Basic="true"} >> C:\deploy.log
  echo winrm configd>> C:\deploy.log
  npm install --global --production windows-build-tools >> C:\deploy.log
  echo npm install windows-build-tools>> C:\deploy.log
</script>
<powershell>
  Invoke-WebRequest `https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/windows_amd64/AmazonSSMAgentSetup.exe ` -OutFile $env:USERPROFILE\Desktop\SSMAgent_latest.exe
  Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
  Start-Service sshd
  Get-Service sshd
  Set-Service -Name sshd -StartupType 'Automatic'
  New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Program Files\PowerShell\7\pwsh.exe" -PropertyType String -Force
</powershell>
EOF

I think that you need to install windows-build-tools before installing node-red.

But in terms of your issue, not really clear what path issues you are getting? Are there some errors in the logs you can share?

1 Like

Hey Julian,

That kinda makes sense, as I've had build tools install line before the node-red install line.
I wasn't sure this was crucial to NR install, but thought maybe it was needed when installing additional nodes from the Palette Manager. I guess I'm wrong.

The reason I moved windows-build-tools down the to the bottom of the list is because I recall the code was causing an automatic restart on the windows machine, and subsequent things were not installing. I could be wrong on my observations.

So I will move it back up prior to NR install line, and maybe there is a "--NoRestart" kinda option?

I'm curious, windows-build-tools:
Does it even invoke a restart? Or is my script just failing on a different command?

Will report back what happens. Thanks a bunch, Julian.

My biggest thing yesterday was getting the PATH to update with a trailing C:\Python3
Terraform does it's thing, and I think it's doing what it does, but I get into Administrator account, and I type PATH in the cmd and I don't see it. So seems Python won't be located when needed to install these nodes.

When Python was installed I specified a simple C:\Python3 without the directory name containing the latest version number, only a 3, only because I wasn't savvy enough to grab the latest Python version, and update that destination directory, and add to the PATH.

I don't remember it requiring a reboot but then my Windows dev machine is so heavily used that anything could be true! I don't think it would do and I'm not even sure that npm could cause such a thing anyway. The only thing I can think of would be if you have already accessed and locked a file that it wants to replace.

You might be hitting a race condition. I think that when you set a path, you might need to restart the shell or maybe you are setting the path in the wrong shell? Not sure.

Noticed some cases I have to invoke refreshenv after the line to refresh the environment variables.

I then came across another hurdle when installing windows-build-tools via npm, as after it installs this package (I think containing Visual Studio), it will restart the machine automatically. This causes the remaining commands in the script to be discarded. I can't seem to invoke any sort of /NoRestart

I've gutted the whole thing but this script below and can't for the life of me seem to get nodejs installed:

Here is the script now, which successfully installs python3 and adds to the PATH.

npm seems to not install...

<script>
  @echo off
  echo Deployment Script Started > C:\deploy.log
  netsh advfirewall firewall add rule name="Open Node-red port" protocol=TCP dir=in localport=1880 action=allow >> C:\deploy.log
  echo netsh advfirewall add rule 1880 complete>> C:\deploy.log
  @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command " [System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" >> C:\deploy.log
  echo choco installed >> C:\deploy.log
  choco install python --version=3.6.0 -yes >> C:\deploy.log
  refreshenv
  choco install nodejs-lts --version=12.15.0 --yes 
</script>
<powershell>
  Invoke-WebRequest `https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/windows_amd64/AmazonSSMAgentSetup.exe ` -OutFile $env:USERPROFILE\Desktop\SSMAgent_latest.exe
  Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
  Start-Service sshd
  Get-Service sshd
  Set-Service -Name sshd -StartupType 'Automatic'
  New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Program Files\PowerShell\7\pwsh.exe" -PropertyType String -Force
</powershell>
EOF

Not sure what's internally going on in Windows when this deploys,
and when I check the chocolatey logs, I only see as far as a successful python install... nothing about nodejs when it's called to install via the script.

Do you need to install Node.js via choco? Could you deploy it directly? If not, what about Microsoft's new deployment tool - can't remember the name but I see they are pushing something new that is also open source.

There are several methods, and I don't need to use choco. It was the [seemingly] easiest to grasp and utilize once choco was installed. I had a version of nodejs installed and running at one point so I thought that would be viable, but now I notice there are different install packages like choco install nodejs.install. ... nodejs-lts nodejs and can't remember which one and what version I tried to get happy results. Regardless, it's been a looong weekend of trial and error, and can't seem to get a working flow

Are you talking about Powershell? I'm going to try some alternatives today.

One of the reasons I don't like choco. It takes horrible liberties with where and how things are installed. I even created a package for it at one time. Thankfully someone else offered to share the maintenance, I can't even remember how to do it now.

Well, there is a standard executable install for Node.js that you can download from their website, that is how I install normally. But yes, you can control that from PowerShell easily enough. I have a bunch of PowerShell commands around that will recreate most of my working laptop should a disaster happen. Not really a script as such because I generally end up just running bits of it rather than the whole thing. Too much changes between rebuilds.

Example extract

#region == INSTALL WINDOWS APPS ===========================================================
    Write-BoxstarterMessage "Installing required Windows Applications ..."

    $installedApps = Get-ItemProperty $regpath | Select-Object DisplayName, InstallDate, DisplayVersion |Sort DisplayName

    # Location for downloads
    $source = "$ENV:USERPROFILE\Downloads\source"
    # Try to create in case it doesn't exist yet
    If (!(Test-Path -Path $source -PathType Container)) { New-Item -Path $source -ItemType Directory | Out-Null }

    # Chrome
    $Installer = "chrome_installer.exe"; 
    Invoke-WebRequest "http://dl.google.com/chrome/install/375.126/$Installer" -OutFile "$source\$Installer"; 
    Start-Process -FilePath $source\$Installer -Args "/silent /install" -Verb RunAs -Wait; Remove-Item "$source\$Installer"

    # Git for Windows  -  https://github.com/git-for-windows/git/releases/latest
    $Installer = "Git-2.17.1-64-bit.exe";
    Invoke-WebRequest "https://github.com/git-for-windows/git/releases/download/v2.17.1.windows.1/$Installer" -OutFile "$source\$Installer"; 
    Start-Process -FilePath $source\$Installer -Verb RunAs -Wait; Remove-Item "$source\$Installer"

    # Node.JS for Windows  -  https://nodejs.org/en/download/
    $Installer = "node-v8.11.2-x86.msi";
    Invoke-WebRequest "https://nodejs.org/dist/v8.11.2/$Installer" -OutFile "$source\$Installer"; 
    Start-Process -FilePath $source\$Installer -Verb RunAs -Wait; #Remove-Item "$source\$Installer"
    # FROM ADMIN: npm -g install windows-build-tools # (Also installs Python 2.7 & )

As you can see, that is somewhat out of date! :smiley:

1 Like

Nice!

Yeah, this is why I'm working on this very diligently, though frustrating to say the least; To have a "pop-up-tent" of system states.

Terraform to provision the server (AWS or GCP or others), and I'm looking at Anisble as I've used in conjunction in my last project that deploys a client's SaaS "proof of concept" website, business, and function via Node-Red. NR is the diamond in the rough, as many don't know about it, or not know how useful and productive it really is.

Dev team and contributors I see on the forums here are top notch, and respectable.

But I digress... I'm here now working to see how easy it is for Ansible to install the rest on the Windows side. And couple that with Terraform, and (hopefully)... viola.

I'll try and share a version of it when I'm done, if anyone is interested.

2 Likes

I am finally making some progress with this project, however I am at yet another hurdle.

I got Terraform to provision a Windows Server, and Ansible to provision the rest.

I got an issue with getting pm2, pm2-startup (aka pm2-windows-startup) is not running node-red automatically when the system restarts.

When my instance reboots, these don't activate...

However when I log into the Windows Server via MS Remote Desktop, it seems to then load PM2 etc via the Administrator account and node-red will then be up within a few minutes.

Is there a way to get this going without needing to log into the Administrator account?

Here is my Ansible playbook:

---
- name: Installing Node-Red
  hosts: win

  tasks:

    - name: Create installation directory structure
      ansible.windows.win_file:
        path: C:\installers
        state: directory

    # - name: Download the Apache installer
    #   win_get_url:
    #     url: https://archive.apache.org/dist/httpd/binaries/win32/httpd-2.2.25-win32-x86-no_ssl.msi
    #     dest: C:\installers\httpd-2.2.25-win32-x86-no_ssl.msi

    # - name: Install the Apache Installer
    #   win_package:
    #     path: C:\installers\httpd-2.2.25-win32-x86-no_ssl.msi
    #     state: present

    - name: Download Node-Js
      win_get_url:
        url: https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi
        dest: C:\installers\httpd-2.2.25-win32-x86-no_ssl.msi

    - name: Install Node-JS
      win_package:
        path: C:\installers\httpd-2.2.25-win32-x86-no_ssl.msi
        state: present

    - name: Ensure that NodeJs is present on the global system path, and in the specified order
      ansible.windows.win_path:
        elements:
          - 'C:\Program Files\nodejs\'

    - name: Download windows-build-tools
      win_get_url:
        url: https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi
        dest: C:\installers\httpd-2.2.25-win32-x86-no_ssl.msi

    - name: Installing Node-red global package
      ansible.windows.win_shell: npm install -g --unsafe-perm node-red
    
    - name: Setting Firewall Rule - Allow Port 1880 for Node-red
      ansible.windows.win_shell: netsh advfirewall firewall add rule name="Open Port 1880" dir=in action=allow protocol=TCP localport=1880
    
    - name: Ensure NodeJs is in Path
      ansible.windows.win_path:
        elements:
          - 'C:\Program Files\nodejs\'

    - name: Install PM2 to ensure node-red executes each time
      ansible.windows.win_shell: npm install -g pm2

    - name: Install pm2-startup
      ansible.windows.win_shell: npm install -g pm2-windows-startup

    - name: init pm2-statup
      ansible.windows.win_shell: pm2-startup install node-red
    
    - name: pm2 install node-red
      ansible.windows.win_shell: pm2 install node-red

    - name: Install PM2 install of Node-red
      ansible.windows.win_shell: pm2 save

    - name: Install PM2 save
      ansible.windows.win_shell: pm2 start node-red

Will be giving this some review:

You are running PM2 under a user account, it needs to run under SYSTEM prior to user login. You can set that up from the Scheduler.

Alternatively, grab the tool that lets you run node.js as a Windows service and do away with PM2.

1 Like