ansible / molecule

Molecule aids in the development and testing of Ansible content: collections, playbooks and roles
https://ansible.readthedocs.io/projects/molecule/
MIT License
3.88k stars 662 forks source link

Running molecule against Windows boxes #607

Closed mikef-nl closed 7 years ago

mikef-nl commented 7 years ago

Awesome work with molecule guys, have it working with Gitlab-CI for role testing. I haven't been able to get it working with Windows boxes however. It seems the Ansible component is hard-coded to use SSH for connections. I have tried using an alternative inventory file to specify winrm but haven't been able to get it working. Is there a preferred way to make it work with Windows boxes? To be specific I'm using mwrock/windows2012r2 for testing of Ansible roles on Windows. I am using Virtualbox on Centos 7 with Vagrant 1.8.6 and use Vagrant as the driver.

retr0h commented 7 years ago

Hi @mikef-nl. Molecule was built out of necessity for our particular needs. We are not a windows shop, so we have never attempted to make it work. This isn't something we are going to have the cycles to implement, b/c it really isn't a use case for us.

If this something you require, unfortunately you or someone else would need to implement it. Hope you understand.

mikef-nl commented 7 years ago

Ok I'm happy to take a look at adding the Windows support. I can see under vagrantdriver.py where it specifies the ansible_connection_params and have added in winrm if specified, otherwise defaulting to ssh. I also see def inventory_entry defines the entry within the inventory and then returns a template. Where does the template then get passed to, the login_args ?

retr0h commented 7 years ago

@mikef-nl I honestly don't think windows is really something we will ever care to support. We would have difficulty testing it, and maintaining the code around it. Without sounding to insensitive, I just don't think we care to support windows.

m4rkw commented 7 years ago

Windows support works fine for me with the current molecule.

try merging these into your molecule.yml

vagrant: platforms:

  • name: win2012r2 box: opentable/win-2012r2-standard-amd64-nocm raw_config_args:
  • "ssh.port = 5985" ansible: sudo: False connection: winrm

also create group_vars/group1.yml containing:

ansible_user: vagrant ansible_password: vagrant ansible_port: 5985 ansible_connection: winrm

The following is necessary for Python 2.7.9+ (or any older Python that has backported SSLContext, eg, Python 2.7.5 on RHEL7) when using default WinRM self-signed certificates:

ansible_winrm_server_cert_validation: ignore

hth, Mark

m4rkw commented 7 years ago

Sorry not sure how to format quotes in comments but check:

https://a.rkw.io/molecule.yml https://a.rkw.io/group1.yml

SiM22 commented 7 years ago

This seems to have been closed and come to a halt.

I can not get it to connect via 5985, it keeps defaulting to ssh

m4rkw commented 7 years ago

@SiM22 did you configure the group as described above?

SiM22 commented 7 years ago

This is what i have

---
dependency:
  name: galaxy
driver:
  name: vagrant
vagrant:
  platforms:
    - name: name
      box: windows_server-2012r2-standard-amd64-nocm
      box_url: https://atlas.hashicorp.com/devopsgroup-io/boxes/windows_server-2012r2-standard-amd64-nocm/versions/1.6.0/providers/virtualbox.box
  providers:
    - name: virtualbox
      type: virtualbox
      options:
        memory: 2048
        cpus: 2
  instances:
    - name: name
      ansible_groups:
        - group1
  raw_config_args:
    - "ssh.port = 5985"
verifier:
  name: serverspec

ansible:
  sudo: False
  connection: winrm
  group_vars:
    group1:
      ansible_user: vagrant
      ansible_password: vagrant
      ansible_port: 5985
      ansible_connection: winrm
m4rkw commented 7 years ago

it worked the last time i tried it, it's been a while since i've used it though. if you can't get it to work i'd suggest fixing the reason why you need to use windows for anything in the first place ;)

SiM22 commented 7 years ago

ha, if only that was possible.

SiM22 commented 7 years ago

Anyone else know why this is not working?

m4rkw commented 7 years ago

the code isn't that complicated, stick some debug in there and see what it's doing. see where it invokes ansible and what args it passes, then debug that in isolation

SiM22 commented 7 years ago

managed to get a working config for whoever stumbles across this

---
dependency:
  name: galaxy
driver:
  name: vagrant
vagrant:
#Config options not supported by Molecule but can still be injected
  raw_config_args:
    - "vm.communicator = 'winrm'"
    - "vm.guest = :windows"
    - "winrm.username = 'vagrant'"
    - "winrm.password = 'vagrant'"
    - "vbguest.auto_update = false"
    - "winrm.timeout = 120"
    - "winrm.retry_limit = 5"
  platforms:
    - name: name
      box: boxName
  providers:
    - name: virtualbox
      type: virtualbox
      options:
        memory: 2048
        cpus: 2
  instances:
    - name: name
      ansible_groups:
        - group1

verifier:
  name: serverspec

ansible:
  sudo: False
  connection: winrm
  group_vars:
    group1:
      ansible_user: vagrant
      ansible_password: vagrant
      ansible_ssh_port: 55986
      ansible_connection: winrm
      ansible_winrm_server_cert_validation: ignore
mkinney commented 6 years ago

Note: The windows image below 'windows-2016' was built locally using packer. Hope this helps.

This worked for me:


driver:
  name: vagrant
  provider:
    name: vmware_desktop
lint:
  name: yamllint
platforms:
  - name: instance
    box: windows-2016
provisioner:
  name: ansible
  connection_options:
    sudo: False
    ansible_user: vagrant
    ansible_password: vagrant
    ansible_port: 55985
    ansible_connection: winrm
    ansible_winrm_scheme: http
    ansible_winrm_server_cert_validation: ignore
  lint:
    name: ansible-lint
scenario:
  name: default
verifier:
  name: testinfra
  lint:
    name: flake8
retr0h commented 6 years ago

@mkinney You want to submit a PR to add this to the molecule examples?

mkinney commented 6 years ago

Sure.

I'm not sure really how to find out the port. I "cheated" and found the info here: cat ~/.vagrant.d/data/vmware/vmware-nat.json

mkinney commented 6 years ago

To find the ports, you can also run this command: vagrant port

But, you have to be in the molecule/default/.molecule directory.

jugatsu commented 6 years ago

example role with windows support https://github.com/jugatsu/ansible-role-molecule-linux-windows

jimbo8098 commented 3 years ago

FYI this is no longer possible. I went down a similar route myself and was only able to connect via WinRM using something like the following:

driver:
  name: vagrant
platforms:
  - name: windows-generic-server
    box: trueability/windows-server-2019
    memory: 4096
    groups:
      - windows
    interfaces:
      - network_name: public_network
      - network_name: private_network
        ip: "10.0.1.17"
    provider_options:
      gui: false
      linked_clone: true
provisioner:
  name: ansible
  playbooks:
    prepare: ./prepare.yml
  connection_options:
    ansible_connection: winrm
    ansible_host: 10.0.1.17
    ansible_port: 5985
  inventory:
    group_vars:
      windows:
        ansible_winrm_transport: basic
        ansible_password: vagrant

Some things to note:

  1. You could technically use the port forwarding done automatically through Vagrant but this of course would use a random port each time. While you could hard-set that through the platform section for the molecule-vagrant driver, I wouldn't recommend it unless you use only one Windows machine at a time otherwise there would be a high likelihood of using a port already in use. I believe this is because molecule-vagrant is using vagrant ssh to connect.
  2. gui must be false, otherwise the VM fails to boot. No idea why. Whilst I do use virtualbox as my vagrant provider, I run that headless. Bootstrapping Linux boxes is perfectly fine without this specification.
  3. The connection_options section is important because this sets to connection type and (in my case importantly) the host and port. This appears to have been possible to override previously within group_vars which, in my opinion, is better since it allows more flexibility but nowadays if you do the same it just gets overwritten by molecule.
  4. Due to the ability to only use one list of connection_options per scenario, it is not possible to start more than one Windows VM within the molecule environment. This causes issues for me because I am trying to do things that involve more than one machine.
  5. The prepare.yml only outputs a debug message. The default prepare.yml (which I found at ./.local/lib/python3.8/site-packages/molecule_vagrant/playbooks/prepare.yml, does not work on Windows since it uses Linux utilities. This would also need to be expanded on to support Windows. I would have liked to have included a blank prepare.yml file (to bypass that step) but this results in an ansible error. I'm not sure at this time if setting the prepare playbook to null would allow this.

I am interested in adding a PR to support Windows but I will need to ask the maintainers of the molecule_vagrant repo if they are interested in that. I think they will be since the their general outlook on it is if it doesn't break anything go for it.

ProfessorManhattan commented 3 years ago

I experimented with @jimbo8098 's recommendations even though I'm testing against Windows 10 (and did not need gui: false). I originally wanted to use SSH so I can test both Windows and Linux environments using the same scenario (because as far as I know a molecule test can only have one set of connection options). However, I was getting the following error:

fatal: [Windows-10]: FAILED! => {
    "ansible_facts": {},
    "changed": false,
    "failed_modules": {
        "ansible.legacy.setup": {
            "failed": true,
            "module_stderr": "/bin/sh: -c: line 0: syntax error near unexpected token `;'\n/bin/sh: -c: line 0: `chcp.com 65001 >  ; PowerShell -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand UABvAHcAZQByAFMAaABlAGwAbAAgAC0ATgBvAFAAcgBvAGYAaQBsAGUAIAAtAE4AbwBuAEkAbgB0AGUAcgBhAGMAdABpAHYAZQAgAC0ARQB4AGUAYwB1AHQAaQBvAG4AU'\n",
            "module_stdout": "",
            "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
            "rc": 0
        }
    },
    "msg": "The following modules failed to execute: ansible.legacy.setup\n"
}

So I experimented with @jimbo8098 's settings and came up with the following working configuration. All three of these files should be placed in the molecule/windows-desktop/ folder in the root of a role.

molecule.yml

---
dependency:
  name: galaxy
  options:
    role-file: requirements.yml
    requirements-file: requirements.yml
driver:
  name: vagrant
  provider:
    name: virtualbox
lint: |
  yamllint .
  ansible-lint
  flake8
platforms:
  - name: Windows-10
    box: Megabyte/Windows-Desktop
    memory: 4096
    cpus: 2
    groups:
      - windows
    provider_options:
      linked_clone: true
    provider_raw_config_args:
      - "customize [ 'modifyvm', :id, '--natdnshostresolver1', 'on' ]"
      - "customize [ 'modifyvm', :id, '--natpf1', 'winrm,tcp,127.0.0.1,55985,,5985' ]"
provisioner:
  name: ansible
  connection_options:
    ansible_connection: winrm
    ansible_host: 127.0.0.1
    ansible_port: 55985
  inventory:
    group_vars:
      all:
        virtualbox_molecule_test: true
      windows:
        ansible_become_method: runas
        ansible_become_user: vagrant
        ansible_connection: winrm
        ansible_password: vagrant
        ansible_user: vagrant
        ansible_winrm_scheme: http
        ansible_winrm_transport: basic
  options:
    vvv: true
  playbooks:
    converge: converge.yml
    prepare: prepare.yml
verifier:
  name: ansible
scenario:
  create_sequence:
    - dependency
    - create
    - prepare
  check_sequence:
    - dependency
    - cleanup
    - destroy
    - create
    - prepare
    - converge
    - check
    - destroy
  converge_sequence:
    - dependency
    - create
    - prepare
    - converge
  destroy_sequence:
    - dependency
    - cleanup
    - destroy
  test_sequence:
    - lint
    - dependency
    - cleanup
    - destroy
    - syntax
    - create
    - prepare
    - converge
    - idempotence
    - side_effect
    - verify
    - cleanup
    - destroy

prepare.yml

---
- name: Prepare
  hosts: all
  gather_facts: false
  tasks:
    - name: Bypass prepare stage
      debug:
        msg: Bypassing the prepare stage since the client is a Windows box
      changed_when: false

converge.yml

---
- name: Converge
  hosts: all
  vars:
    ansible_user: vagrant
  roles:
    - role: "YOUR_ROLE_NAME_HERE"

You can then run molecule test -s windows-desktop to test your role. If Ansible complains that it cannot find the role then you might have to add an ansible.cfg file that looks something like this in your role's root:

ansible.cfg

[defaults]
roles_path=../

You can find a full example here: https://github.com/ProfessorManhattan/ansible-androidstudio (note, this currently links to an incomplete project but should be complete by the time people start reading this).

It might be important to note that the Vagrant box I am using has WinRM, SSH, Python 3, and Chocolatey pre-installed.

Thanks @jimbo8098

EDIT I figured out how to make Windows-10 work alongside Linux hosts -- since this post is already very long, just check the default scenario in the link above if you'd like it. Basically, I just had to remove the --dnshostresolver1 setting and move the connection options to the host_vars instead of the group_vars for the Windows-10 client.

jimbo8098 commented 3 years ago

You're welcome! However note that this method means you can only provision one host at a time because you have to manually set the IP each time.

The connection options under the group/host vars is finniky. Since Molecule expects to use the connection details from vagrant, it doesn't expect them to be overrode in the scenario other than in the connection_options which can only be set once per scenario. I didn't have any success with it in multi-machine builds though to be fair I didn't check a Windows and Linux multi-machine scenario

jmjava commented 3 years ago

@ProfessorManhattan - Do you think this would be able to be ported to Vagrant - HyperV provider? I am using WSL2 on laptop and I have seen various posts about getting molecule working with VirtualBox on windows from WSL2 but i am getting critical error when trying to create a box with WindowsServer2019 because it seems to need HyperV. I know this is not exactly what you are doing - just looking for some pointers if possible. Thanks.

ProfessorManhattan commented 3 years ago

@jimbo8098 -- the method I posted can be modified to work with multiple Windows hosts.. you just have to set up a manual port forward for each Windows machine and then the Linux machines work automatically. I think for some reason you have to specify the connection options in the molecule connection options or the host_vars. I did not have any luck using group_vars. Since the connection options are global, you should use the host_vars to specify connection details for each Windows host if you have more than 1 or are including Linux tests alongside Windows tests.

@jmjava I have not experimented with running the test from a WSL2 environment. I imagine, if your box is a Hyper-V box that you would have to run Ansible from the environment that has Hyper-V installed which would be regular Windows and not the WSL2 environment.

jmjava commented 3 years ago

@ProfessorManhattan - this seems to be a tricky problem. I found this but so far it's not working https://github.com/karandash8/virtualbox_WSL2