Error installing Chocolatey via Ansible on Windows

11.1k views Asked by At

I have a problem installing Chocolatey and Chocolatey packages using Ansible on Windows Server 2008 R2. Everything worked fine on Windows Server 2012 R2 (it has built-in PowerShell v3.0).

I had a problem running the PowerShell scripts in the Ansible documentation, but I ran Set-ExecutionPolicy RemoteSigned, which helped. I installed Windows PowerShell 3.0 so Ansible could run. Now, when I run the playbook, I have this error:

failed: [192.168.1.1] => {"failed": true, "parsed": false}

Mode                LastWriteTime     Length Name                              
----                -------------     ------ ----                              
d----         6/16/2015   6:16 AM            chocInstall                       
Downloading https://chocolatey.org/api/v2/package/chocolatey/ to C:\Users\ADMINI~1\AppData\Local\Temp\chocolatey\chocInstall\chocolatey.zip
Download 7Zip commandline tool
Downloading https://chocolatey.org/7za.exe to C:\Users\ADMINI~1\AppData\Local\Temp\chocolatey\chocInstall\7za.exe
Extracting C:\Users\ADMINI~1\AppData\Local\Temp\chocolatey\chocInstall\chocolatey.zip to C:\Users\ADMINI~1\AppData\Local\Temp\chocolatey\chocInstall...
Installing chocolatey on this machine
{
    "changed":  false,
    "msg":  "The term \u0027C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\chocolatey\\chocInstall\\tools\>\chocolateyInstall.ps1\u0027 is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.",
    "failed":  true
}

7-Zip (A) 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18

Processing archive: C:\Users\ADMINI~1\AppData\Local\Temp\chocolatey\chocInstall\chocolatey.zip

Extracting  _rels\.rels
Extracting  chocolatey.nuspec
Extracting  tools\chocolateyInstall.ps1
Extracting  tools\chocolateysetup.psm1
Extracting  tools\init.ps1
Extracting  tools\chocolateyInstall\choco.exe
Extracting  tools\chocolateyInstall\choco.exe.ignore
Extracting  package\services\metadata\core-properties\61804721eec44e8592a61904d0a62022.psmdcp
Extracting  [Content_Types].xml

Everything is Ok

Files: 9
Size:       3738621
Compressed: 1259522


FATAL: all hosts have already failed -- aborting

After second run, I have a different error:

failed: [192.168.1.1] => {"changed": false, "failed": true}
msg: The specified module 'C:\Users\Administrator\AppData\Local\Temp\chocolatey\chocInstall\tools\chocolateyInstall\helpers\chocolateyInstaller.psm1' was not loaded because no valid module file was found in any module directory.

FATAL: all hosts have already failed -- aborting

I noticed that Ansible has a problem unpacking Chocolatey from %TEMP% to %PROGRAMDATA%. So, after running chocolateyInstall.ps1 from %TEMP%\chocolatey\helpers (I think it's good path) I have this error:

failed: [192.168.1.1] => {"changed": false, "choco_error_cmd": "choco.exe list --local-only chocolatey", "choco_error_log": "",
"failed": true} msg: Error checking installation status for chocolatey

FATAL: all hosts have already failed -- aborting

I need to automate the installation and configuration tools such as: jdk, tomcat, firefox, etc. Here is an example of my playbook:

---
- hosts: windows
  vars:
    java:
      JAVA_HOME: "C:\\Program Files\\Java\\jdk1.7.0_76"
  tasks:
#   INSTALL FIREFOX
    - name: install_firefox
      win_chocolatey:
        name: firefox -y
        state: present
#   INSTALL AND SET JAVA_HOME
    - name: install_and_set_java_home
      win_chocolatey:
        name: jdk7 -y
        version: 7.0.76
        environment: java
        state: present
6

There are 6 answers

0
Christopher Chrzanowski On BEST ANSWER

I have modified my playbook, now I run it only once but I have the error (same as earlier) about choco installation. If it helps for someone here is the solution for ignoring failure in playbook:

---
- hosts: windows
  tasks:
#   INSTALL CHOCO
    - name: install_chocolatey
      win_chocolatey:
        name: chocolatey -y
        state: present
      ignore_errors: yes
#   INSTALL FIREFOX
    - name: install_firefox
      win_chocolatey:
        name: firefox -y
        state: present
.
.
.

I hope it will help ;)

0
Anthony Mastrean On

You might have some bad encoding in your command.

Installing chocolatey on this machine
{
    "changed":  false,
    "msg":  "The term \u0027C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\chocolatey\\chocInstall\\tools\>\chocolateyInstall.ps1\u0027 is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.",
    "failed":  true
}

The apostrophes are being printed as Unicode literals

"The term \u0027...chocolateyInstall.ps1\u0027 is not recognized..."

Is that just something that Ansible is doing? Can you show us the Chocolatey install playbook section/command?

Like, where do you get this from

#   INSTALL FIREFOX
    - name: install_firefox
      win_chocolatey:
1
Christopher Chrzanowski On

It's stupid to admit but so simple solution as changing order of instalation helps the second run error.

I think there was a problem with JAVA_HOME system variable (I installed first jdk 7 and setted for it variable), chocolatey installation of tomcat 7 requires installation of java 8 (strange) and sets system variable to jdk8.

My playbook installs now tomcat, jdk7, sets system variable to jdk7 (I'm trying to do this with powershell) and then installs other things. I still have the first error (while installing chocolatey)

---
- hosts: windows
  vars:
    java:
      JAVA_HOME: "C:\\Program Files\\Java\\jdk1.7.0_76"
  tasks:
#   INSTALL FIREFOX
    - name: install_firefox
      win_chocolatey:
        name: firefox -y
        state: present
#   TOMCAT INSTALL
    - name: install_tomcat
      win_chocolatey:
        name: tomcat -y
        version: 7.0.59
        state: present
#   INSTALL AND SET JAVA_HOME
    - name: install_and_set_java_home
      win_chocolatey:
        name: jdk7 -y
        version: 7.0.76
        environment: java
        state: present
#   STOP TOMCAT SERVICE
    - name: tomcat_service_auto_stop
      win_service:
        name: Apache Tomcat 7.0 Tomcat7
        start_mode: auto
        state: stopped
...
...
...
#   DOWNLOAD SERVER.XML FOR TOMCAT
    - name: download_server_xml
      win_get_url: 
        url: http://192.168.1.107:8000/server.xml
        dest: C:\Program Files\Apache Software Foundation\tomcat\apache-tomcat-7.0.59\conf\server.xml
#   DOWNLOAD SQL DRIVER
    - name: download_sql_driver
      win_get_url: 
        url: http://192.168.1.107:8000/sqljdbc4.jar
        dest: C:\Program Files\Apache Software Foundation\tomcat\apache-tomcat-7.0.59\lib\sqljdbc4.jar
#   OPEN PORT 80 FOR TOMCAT
    - name: Open_Port_80_for_Tomcat
      script: ../scripts/portsWin2008.ps1
#   START TOMCAT SERVICE
    - name: tomcat_service_start
      win_service:
        name: Apache Tomcat 7.0 Tomcat7
        state: started
0
Christopher Chrzanowski On

There is no chocolatey install that I run.

Powershell script win_chocolatey.ps1 should install packages (package manager).

Before the install it should search for chocolatey installation on windows machine. Below the code from win_chocolatey.ps1 script:

#!powershell
# This file is part of Ansible
#
# Copyright 2014, Trond Hindenes <[email protected]>
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

$ErrorActionPreference = "Stop"

# WANT_JSON
# POWERSHELL_COMMON

$params = Parse-Args $args;
$result = New-Object PSObject;
Set-Attr $result "changed" $false;

If ($params.name)
{
    $package = $params.name
}
Else
{
    Fail-Json $result "missing required argument: name"
}

If ($params.force)
{
    $force = $params.force | ConvertTo-Bool
}
Else
{
    $force = $false
}

If ($params.upgrade)
{
    $upgrade = $params.upgrade | ConvertTo-Bool
}
Else
{
    $upgrade = $false
}

If ($params.version)
{
    $version = $params.version
}
Else
{
    $version = $null
}

If ($params.source)
{
    $source = $params.source.ToString().ToLower()
}
Else
{
    $source = $null
}

If ($params.showlog)
{
    $showlog = $params.showlog | ConvertTo-Bool
}
Else
{
    $showlog = $null
}

If ($params.state)
{
    $state = $params.state.ToString().ToLower()
    If (($state -ne "present") -and ($state -ne "absent"))
    {
        Fail-Json $result "state is $state; must be present or absent"
    }
}
Else
{
    $state = "present"
}

Function Chocolatey-Install-Upgrade
{
    [CmdletBinding()]

    param()

    $ChocoAlreadyInstalled = get-command choco -ErrorAction 0
    if ($ChocoAlreadyInstalled -eq $null)
    {
        #We need to install chocolatey
        iex ((new-object net.webclient).DownloadString("https://chocolatey.org/install.ps1"))
        $result.changed = $true
        $script:executable = "C:\ProgramData\chocolatey\bin\choco.exe"
    }
    else
    {
        $script:executable = "choco.exe"

        if ((choco --version) -lt '0.9.9')
        {
            Choco-Upgrade chocolatey 
        }
    }
}


Function Choco-IsInstalled
{
    [CmdletBinding()]

    param(
        [Parameter(Mandatory=$true, Position=1)]
        [string]$package
    )

    $cmd = "$executable list --local-only $package"
    $results = invoke-expression $cmd

    if ($LastExitCode -ne 0)
    {
        Set-Attr $result "choco_error_cmd" $cmd
        Set-Attr $result "choco_error_log" "$LastExitCode"

        Throw "Error checking installation status for $package" 
    }     

    If ("$results" -match " $package .* (\d+) packages installed.")
    {
        return $matches[1] -gt 0
    }

    $false
}

Function Choco-Upgrade 
{
    [CmdletBinding()]

    param(
        [Parameter(Mandatory=$true, Position=1)]
        [string]$package,
        [Parameter(Mandatory=$false, Position=2)]
        [string]$version,
        [Parameter(Mandatory=$false, Position=3)]
        [string]$source,
        [Parameter(Mandatory=$false, Position=4)]
        [bool]$force
    )

    if (-not (Choco-IsInstalled $package))
    {
        throw "$package is not installed, you cannot upgrade"
    }

    $cmd = "$executable upgrade -dv -y $package"

    if ($version)
    {
        $cmd += " -version $version"
    }

    if ($source)
    {
        $cmd += " -source $source"
    }

    if ($force)
    {
        $cmd += " -force"
    }

    $results = invoke-expression $cmd

    if ($LastExitCode -ne 0)
    {
        Set-Attr $result "choco_error_cmd" $cmd
        Set-Attr $result "choco_error_log" "$results"
        Throw "Error installing $package" 
    }

    if ("$results" -match ' upgraded (\d+)/\d+ package\(s\)\. ')
    {
        if ($matches[1] -gt 0)
        {
            $result.changed = $true
        }
    }
}

Function Choco-Install 
{
    [CmdletBinding()]

    param(
        [Parameter(Mandatory=$true, Position=1)]
        [string]$package,
        [Parameter(Mandatory=$false, Position=2)]
        [string]$version,
        [Parameter(Mandatory=$false, Position=3)]
        [string]$source,
        [Parameter(Mandatory=$false, Position=4)]
        [bool]$force,
        [Parameter(Mandatory=$false, Position=5)]
        [bool]$upgrade
    )

    if (Choco-IsInstalled $package)
    {
        if ($upgrade)
        {
            Choco-Upgrade -package $package -version $version -source $source -force $force
        }

        return
    }

    $cmd = "$executable install -dv -y $package"

    if ($version)
    {
        $cmd += " -version $version"
    }

    if ($source)
    {
        $cmd += " -source $source"
    }

    if ($force)
    {
        $cmd += " -force"
    }

    $results = invoke-expression $cmd

    if ($LastExitCode -ne 0)
    {
        Set-Attr $result "choco_error_cmd" $cmd
        Set-Attr $result "choco_error_log" "$results"
        Throw "Error installing $package" 
    }

     $result.changed = $true
}

Function Choco-Uninstall 
{
    [CmdletBinding()]

    param(
        [Parameter(Mandatory=$true, Position=1)]
        [string]$package,
        [Parameter(Mandatory=$false, Position=2)]
        [string]$version,
        [Parameter(Mandatory=$false, Position=3)]
        [bool]$force
    )

    if (-not (Choco-IsInstalled $package))
    {
        return
    }

    $cmd = "$executable uninstall -dv -y $package"

    if ($version)
    {
        $cmd += " -version $version"
    }

    if ($force)
    {
        $cmd += " -force"
    }

    $results = invoke-expression $cmd

    if ($LastExitCode -ne 0)
    {
        Set-Attr $result "choco_error_cmd" $cmd
        Set-Attr $result "choco_error_log" "$results"
        Throw "Error uninstalling $package" 
    }

     $result.changed = $true
}
Try
{
    Chocolatey-Install-Upgrade

    if ($state -eq "present")
    {
        Choco-Install -package $package -version $version -source $source `
            -force $force -upgrade $upgrade
    }
    else
    {
        Choco-Uninstall -package $package -version $version -force $force
    }

    Exit-Json $result;
}
Catch
{
     Fail-Json $result $_.Exception.Message
}

As you see it install chocolatey if it is not found on machine.

Powershell script to install chocolatey is downloaded from https://chocolatey.org/install.ps1

One more thing... in chocolatey install logs there is an exception

2015-06-17 01:13:40,156 [ERROR] - Error deserializing response of type chocolatey.infrastructure.app.configuration.ConfigFileSettings: Exception of type 'System.OutOfMemoryException' was thrown.

2015-06-17 01:13:40,187 [ERROR] - Exception of type System.OutOfMemoryException' was thrown.

I found somewhere that I should use:

winrm set winrm/config/winrs @{MaxMemoryPerShellMB="MemoryInMB"}

but it don't help the installation

0
Gavin Bunney On

The issue is that the target machine doesn't allow enough memory per PowerShell process.

You can check the current allocation by running:

get-item wsman:localhost\Shell\MaxMemoryPerShellMB

This is 300MB by default. I generally set it to 2GB for Ansible managed machines, which clears errors around the System.OutOfMemoryException right up.

This can be done on the host directly, or with Ansible:

- name: set PowerShell memory allowance to 2GB
  win_shell: set-item wsman:localhost\Shell\MaxMemoryPerShellMB 2048
1
Mr.Pramod Anarase On

I think i found the solution.. the reported issue is with encoding Ansible uses by default encoding and language as ansible.cfg

...
module_lang    = C
...

but you can override this to host specific variable as

ansible_module_lang=cp1252
ansible_ssh_port=5986
ansible_connection=winrm

This will solve your problem