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.89k stars 664 forks source link

Implementing delegated driver #1292

Closed freeseacher closed 6 years ago

freeseacher commented 6 years ago

Issue Type

My molecule.yml

---
dependency:
  name: galaxy
driver:
  name: delegated
  hostname: 192.168.XX.10
  esxi_hostname: 192.168.XX.12
  username: XXX
  password: XXXX
  datacenter: lab
  validate_certs: "no"
  resource_pool: Tests
  folder: "/testy"
  ssh_identity_file: "XXXX"
  options:
    ansible_connection_options:
      connection: ssh
lint:
  name: yamllint
platforms:
  - name: node1
    template: packer-centos7
    memory: 3072
    cpu: 2

provisioner:
  name: ansible
  playbooks:
    converge: playbook.yml
  lint:
    name: ansible-lint
scenario:
  name: default
verifier:
  name: goss
  lint:
    name: flake8
    enabled: false

Create.yml

- name: Create
  hosts: localhost
  connection: local
  gather_facts: false
  no_log: "{{ not lookup('env', 'MOLECULE_DEBUG') | bool }}"
  tasks:
    - name: Create molecule instance(s)
      vmware_guest:
        hostname: "{{ molecule_yml.driver.hostname }}"
        esxi_hostname: "{{ molecule_yml.driver.esxi_hostname }}"
        username: "{{ molecule_yml.driver.username }}"
        password: "{{ molecule_yml.driver.password }}"
        datacenter: "{{ molecule_yml.driver.datacenter }}"
        validate_certs: "{{ molecule_yml.driver.validate_certs }}"
        resource_pool: "{{ molecule_yml.driver.resource_pool }}"
        folder: "{{ molecule_yml.driver.folder }}"
        name: "{{ item.name }}"
        template: "{{ item.template }}"
        hardware:
          memory_mb: "{{ item.memory | default(omit) }}"
          num_cpus: "{{ item.cpu | default(omit) }}"
        wait_for_ip_address: "yes"
        state: poweredon
      register: server
      with_items: "{{ molecule_yml.platforms }}"

    - name: Populate instance config dict
      set_fact:
        instance_conf_dict: {
          'instance': "{{ item.instance.hw_name }}",
          'address': "{{ item.instance.ipv4 }}",
          'user': "vagrant",
          'port': "22",
          'identity_file': 'identity_file': "{{ molecule_yml.driver.ssh_identity_file }}"
        }
      with_items: "{{ server.results }}"
      register: instance_config_dict
      when: server is changed

    - name: Convert instance config dict to a list
      set_fact:
        instance_conf: "{{ instance_config_dict.results | map(attribute='ansible_facts.instance_conf_dict') | list }}"
      when: server is changed

    - name: Dump instance config
      copy:
        # NOTE(retr0h): Workaround for Ansible 2.2.
        #               https://github.com/ansible/ansible/issues/20885
        content: "{{ instance_conf | to_json | from_json | molecule_to_yaml | molecule_header }}"
        dest: "{{ molecule_instance_config }}"
      when: server is changed

Instance created successfuly. i have file instance_config.yml

# Molecule managed

---
- address: 10.10.10.34
  identity_file:XXX
  instance: node1
  port: '22'
  user: vagrant

looks good. but ansible_inventory.yml pretty useless because of node1 config sections.

# Molecule managed

---
all:
  hosts:
    node1: &id001
      connection: ssh
  vars:
    molecule_ephemeral_directory: '{{ lookup(''env'', ''MOLECULE_EPHEMERAL_DIRECTORY'')
      }}'
    molecule_file: '{{ lookup(''env'', ''MOLECULE_FILE'') }}'
    molecule_instance_config: '{{ lookup(''env'', ''MOLECULE_INSTANCE_CONFIG'') }}'
    molecule_scenario_directory: '{{ lookup(''env'', ''MOLECULE_SCENARIO_DIRECTORY'')
      }}'
    molecule_yml: '{{ lookup(''file'', molecule_file) | molecule_from_yaml }}'
ungrouped:
  hosts:
    node1: *id001
  vars: {}

so after converge stage i got

    fatal: [node1]: UNREACHABLE! => {
        "changed": false, 
        "unreachable": true
    }

    MSG:

    Failed to connect to the host via ssh: ssh: Could not resolve hostname node1: Name or service not known

Docs says that i have to It is the developers responsibility to configure the ssh config file. Am i catching idea right that i have to add template for ssh_config file and put all connection logic to it? something like

Host {{instance}}
  HostName {{address}}
  Port {{port}}
  IdentityFile {{identity_file}}
  PreferredAuthentications publickey
  User {{user}}

If yes what for instance_config.yml is used ? If no what should i do to implement delegated driver in a correct way ?

freeseacher commented 6 years ago

ok. trying to implement

    - name: render ssh_config for instances
      template:
        src: ssh_config.j2
        dest: "{{molecule_ephemeral_directory}}/ssh_config"
      when: server is changed
{% for host in instance_conf %}
Host {{host.instance}}
  HostName {{host.address}}
  Port {{host.port}}
  IdentityFile {{host.identity_file}}
  PreferredAuthentications publickey
  User {{host.user}}
{%endfor%}

molecule.yml

driver:
  name: delegated
....
  options:
    ansible_connection_options:
      connection: ssh
      ansible_ssh_common_args: -F $MOLECULE_EPHEMERAL_DIRECTORY/ssh-config

no interpolation done.

% cat ansible_inventory.yml
# Molecule managed

---
all:
  hosts:
    node1: &id001
      ansible_ssh_common_args: -F /ssh-config
      connection: ssh

but according to http://molecule.readthedocs.io/en/latest/testing.html You also must include the MOLECULE_EPHEMERAL_DIRECTORY variable in the molecule.yml configuration file.

retr0h commented 6 years ago

Molecule.yml does not know anything about MOLECULE_* env vars. That is a chicken and egg problem, that is not easy to correct. Those variables are exported for many of the other components used by Molecule. However, I am trying to think of a way to correct this particular issue. It's just not easy.

It is the developers responsibility to create a ssh-config. It can be done manually or via automation, and can be placed wherever you wish. It does not need to live in the $MOLECULE_EPHEMERAL_DIRECTORY path. I suggest making your own convention for now.

retr0h commented 6 years ago

If yes what for instance_config.yml is used ? If no what should i do to implement delegated driver in a correct way ?

Delegated driver is for people who wish to connect to systems that may or may not be managed by Molecule. Molecule does not make any assumptions here. So it is a pretty bare driver. You supply your create/destroy playbooks, and your own ssh config file. Molecule simply ssh'es into the systems.

The instance config is not necessary, b/c the instance config is specific to the Molecule driver code. It is a crappy attempt to get data generated from Ansible back into Molecule, and Molecule expects the dict to have certain keys. This is why I opted to just use an ssh config file for delegated.

I hope that makes sense why things were done this way. Also, very few people use this. You're probably the first one, so we can obviously improve this ;)

freeseacher commented 6 years ago

I suggest making your own convention for now.

ok. not a problem. just want to follow main line.

You're probably the first one, so we can obviously improve this

i will be great if we can make ansible_host var available to playbook inventroy. i heave rely on in and on fact that it is an ip address. for example to make hosts file https://github.com/nocproject/ansible_deploy/blob/microservices/noc_roles/pre/tasks/main.yml#L54

freeseacher commented 6 years ago

for my use case it is just adding code from vagrant.py to delegated.py works well i am talking about ansible_connection_options and _get_instance_config functions. of cause this breaks all the things for documented behavior but works ok.

freeseacher commented 6 years ago

any ideas how to make it work in upstream ?

retr0h commented 6 years ago

any ideas how to make it work in upstream ?

Make what work upstream @freeseacher ?

freeseacher commented 6 years ago

Currently to make delegated driver works as expected i have to return code for ansible_connection_options and _get_instance_config functions. Otherwise there are no possibility to make ansible_host variable propagated well.

Currently i made docker file with molecule and patched delegated.py. That looks like quick and dirty solution but i don't want make it work like this.

So it will be good if we can add option/another driver ? that will work like delegeted but with most of the features of molecule will work. Currently with delegated driver molecule login is not working, inventory pretty unusable.

Of cause i understand that using molecule not as intended to do. Not on localhost, not for role testing but pretty in devops way :)

retr0h commented 6 years ago

The delegated driver works if you supply the ssh-config. The delegated driver simply requires that you to supply the ssh-config.

retr0h commented 6 years ago

So it will be good if we can add option/another driver ? that will work like delegeted but with most of the features of molecule will work. Currently with delegated driver molecule login is not working, inventory pretty unusable.

Did you use the delegated driver and set managed to true? Molecule should write you out a host inventory file.

all:
  hosts:
    instance: &id001
      ansible_host: 127.0.0.1
  vars:
    molecule_ephemeral_directory: '{{ lookup(''env'', ''MOLECULE_EPHEMERAL_DIRECTORY'')
      }}'
    molecule_file: '{{ lookup(''env'', ''MOLECULE_FILE'') }}'
    molecule_instance_config: '{{ lookup(''env'', ''MOLECULE_INSTANCE_CONFIG'') }}'
    molecule_scenario_directory: '{{ lookup(''env'', ''MOLECULE_SCENARIO_DIRECTORY'')
      }}'
    molecule_yml: '{{ lookup(''file'', molecule_file) | molecule_from_yaml }}'
ungrouped:
  hosts:
    instance: *id001
  vars: {}

Configuring your driver as follows, you should be able to login.

driver:
  name: delegated
  options:
    managed: False
    login_cmd_template: 'ssh {instance} -F /tmp/ssh-config'
    ansible_connection_options:
      connection: ssh
      ansible_ssh_common_args -F /path/to/ssh-config

Is that not the case? I believe Molecule should act pretty much the same with delegated it just expects you to configure ssh. Molecule should have added the ansible_ssh_common_args to host inventory, so it all just works.

freeseacher commented 6 years ago

ok. adding

  options:
    managed: True
    login_cmd_template: 'ssh {instance} -F /tmp/molecule/molecule_delegated/default/ssh_config'
    ansible_connection_options:
      connection: ssh
      ansible_ssh_common_args: -F /tmp/molecule/molecule_delegated/default/ssh_config

to driver and

    - name: render ssh_config for instances
      template:
        src: ssh_config.j2
        dest: "{{molecule_ephemeral_directory}}/ssh_config"
      when: server is changed

to prepare really makes molecule login works.

but inventory is build without ansible_host info and as far as i know i can't get it other way.

% cat /tmp/molecule/molecule_delegated/default/ansible_inventory.yml
# Molecule managed

---
all:
  hosts:
    sova_dev_rhel7: &id001
      ansible_ssh_common_args: -F /tmp/molecule/molecule_delegated/default/ssh_config
      connection: ssh
  vars:
    molecule_ephemeral_directory: '{{ lookup(''env'', ''MOLECULE_EPHEMERAL_DIRECTORY'')
      }}'
    molecule_file: '{{ lookup(''env'', ''MOLECULE_FILE'') }}'
    molecule_instance_config: '{{ lookup(''env'', ''MOLECULE_INSTANCE_CONFIG'') }}'
    molecule_scenario_directory: '{{ lookup(''env'', ''MOLECULE_SCENARIO_DIRECTORY'')
      }}'
    molecule_yml: '{{ lookup(''file'', molecule_file) | molecule_from_yaml }}'
ungrouped:
  hosts:
    sova_dev_rhel7: *id001
  vars: {}

as mentioned early i heavily rely on it

retr0h commented 6 years ago

Molecule.yml does not know anything about MOLECULE_* env vars. That is a chicken and egg problem, that is not easy to correct. Those variables are exported for many of the other components used by Molecule. However, I am trying to think of a way to correct this particular issue. It's just not easy.

FYI - #1296

retr0h commented 6 years ago

as mentioned early i heavily rely on it

Okay, so we will do this.

Sound good?

freeseacher commented 6 years ago

Yep. sounds good.

retr0h commented 6 years ago

@freeseacher Please try molecule on master. This should do what you expect.

barhoz10 commented 7 months ago

Hello, there is a production version of this driver ?