Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows support! #69

Merged
merged 4 commits into from
May 22, 2017
Merged

Windows support! #69

merged 4 commits into from
May 22, 2017

Conversation

judy-zz
Copy link
Contributor

@judy-zz judy-zz commented May 17, 2017

I wrote full Windows support for this role. I tried to match the programming style and Ansible best practices as closely as possible. I'm still new to Ansible, and would happily accept any feedback.

There are a LOT of additions, and more than a handful of changes, mostly ansible_os_system checks. I'll comment in the code diff where there might be points of confusion between how Linux does things and how Windows does them.

This role supports Consul 0.8.3 but still installs 0.8.2 by accident.
This has been remedied.
@@ -86,37 +85,44 @@ the variables are named and described below:
### `consul_bin_path`

- Binary installation path
- Default value: `/usr/local/bin`
- Default linux value: `/usr/local/bin`
- Default windows value: `C:\ProgramData\consul\bin`
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've used C:\ProgramData\consul for all necessary program data, including the consul.exe binary. Most Windows programs use the magical %APPDATA% path, but those are tied to specific users. My understanding is that C:\ProgramData is what Chocolatey and NSSM use, and it's a good place for system-level services.


### `consul_user`

- OS user
- Default value: *consul*
- Default linux value: *consul*
- Default linux value: *LocalSystem*
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Windows convention is to have the LocalSystem user run services. It has the right mix of permissions for those kinds of services.

@@ -5,20 +5,26 @@
consul_debug: no

### Package
consul_version: "{{ lookup('env','CONSUL_VERSION') | default('0.8.2', true) }}"
consul_version: "{{ lookup('env','CONSUL_VERSION') | default('0.8.3', true) }}"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The last commit on the upstream repo updates the project to support Consul 0.8.3, but the default installation still downloads 0.8.2. This is an unrelated bug fix, but will probably just disappear if fixed upstream, correct?

consul_architecture_map:
# this first entry seems... redundant
#(but it's required for reasons)
amd64: amd64
x86_64: amd64
armv7l: arm
aarch64: arm64
32-bit: "386"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know if there are even Windows Server versions that run in 32-bit, but there are personal versions of Windows that do, and this entry ensures the right package is grabbed from Hashicorp.

{% if ansible_os_family == "Windows" %}\
{{ 'windows' }}\
{% else %}\
{{ ansible_system | lower }}\
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ansible_system in these cases returns Win32NT. This changes between Windows Server versions and is unfortunately brittle.

@@ -27,6 +33,7 @@ consul_install_remotely: false
consul_bin_path: "/usr/local/bin"
consul_config_path: "/etc/consul"
consul_configd_path: "/etc/consul.d"
consul_bootstrap_state: "/etc/consul/.consul_bootstrapped"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bootstrap state is another path I needed to change for Windows, and consolidating it with the other paths seemed to be the smart choice.

consul_iface: "{{ lookup('env','CONSUL_IFACE') | default(ansible_default_ipv4.interface, true) }}"
consul_iface: "\
{% if ansible_os_family == "Windows" %}\
{{ lookup('env','CONSUL_IFACE') | default(ansible_interfaces[0].interface_name, true) }}\
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Network interfaces in Windows are handled very differently in Ansible, with very little overlap. I'm not sure why. But this works.

service:
name: consul
state: restarted
include: restart_consul.yml
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Having OS-contextual handlers is awkward. I attempted to do this with ansible blocks but they're unsupported. This is clunkier than ideal, but is the best option I could find that works.

path: /tmp/consul
state: directory

- name: Verify TLS1.2 is used
Copy link
Contributor Author

@judy-zz judy-zz May 17, 2017

Choose a reason for hiding this comment

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

Windows attempts to use TLS1.0 by default when downloading files, falling back to SSL3, and never trying TLS1.2. This is fixed in later versions of Windows.

This task sets a typical value in the registry just in case it isn't there, ensuring that TLS1.2 is tried first, then TLS1.0, then SSL3. Otherwise, downloading the package and checksum files outright fails because you haven't changed the registry variable. ¯_(ツ)_/¯

when: not consul_checksum.stat.exists | bool

- name: Read Consul package checksum
win_shell: "findstr {{ consul_pkg }} /tmp/consul/consul_{{ consul_version }}_SHA256SUMS"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

findstr is to Windows as grep is to Linux.

dest: "/tmp/consul/{{ consul_pkg }}"
tags: installation

- name: Calculate checksum
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These next two tasks are done different from the usual path, because win_get_url doesn't allow checksums like get_url does. Minor inconsistency we have to handle by hand here.

include: config_windows.yml
when: ansible_os_family == 'Windows'

- name: Ensure neither ACL nor TLS are requested for windows hosts
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Small safety check. I haven't updated the ACL or TLS code, so in the meanwhile their support is turned off for Windows hosts. This can be added later.

@@ -157,10 +200,12 @@
group: root
mode: 0755
when:
- ansible_service_mgr is defined
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ansible_service_mgr is undefined on Windows.

state: latest

- name: Start Consul on Windows
win_nssm:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

NSSM is used to wrap consul.exe into a Windows-friendly service. Without it we can't use the regular win_service module because services don't let you set configuration variables.


- name: Check Consul HTTP API
wait_for:
delay: 15
port: 8500
when: ansible_os_family != "Windows"

- name: Check Consul HTTP API
Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's no win_wait_for module yet. This is a hack to use wait_for locally and watch the port in the same way. It works on my machine perfectly, but I can see cases where this could potentially fail depending on network setup. It may need more work in the future.

# File: Windows.yml - Windows OS variables for Consul

# paths
consul_windows_path: /ProgramData/consul
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fun fact: forward slashes now work almost as well as backslashes do in Windows! Folder structure is still different though.

@brianshumate
Copy link
Contributor

Thanks very much for this contribution!

@brianshumate brianshumate merged commit 7b83474 into ansible-collections:master May 22, 2017
- name: Install NSSM
win_chocolatey:
name: nssm
state: latest

Choose a reason for hiding this comment

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

@judy @brianshumate Shouldn't there be a when clause here checking for os_family == "Windows"?
(Didn't test)

@gmarkey
Copy link

gmarkey commented May 23, 2017

Heads up; the "when" clauses are breaking anything that registers objects in the output (e.g. stat) as the condition failure is being stored in register and forcibly casting as a dict.

Might just be an ordering problem; it's likely best to encapsulate the Windows & non-Windows stuff inside a block.

@brianshumate
Copy link
Contributor

Yeah... missed that stuff, sorry!

I have committed a quick change that puts all non-Windows and Windows main tasks in separate top-level blocks. Not the ideal solution, but it unbreaks the role for the moment. This is released in v1.20.1 also.

@judy-zz
Copy link
Contributor Author

judy-zz commented May 23, 2017

I was trying this earlier but wasn't formatting my blocks correctly. I see how you did it now. This is much cleaner!

@brianshumate
Copy link
Contributor

👍

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.

4 participants