diff options
39 files changed, 1757 insertions, 918 deletions
diff --git a/README_AWS.md b/README_AWS.md index 1c76916cb..c511741b9 100644 --- a/README_AWS.md +++ b/README_AWS.md @@ -22,6 +22,27 @@ Note: You must source this file before running any Ansible commands.  Alternatively, you could configure credentials in either ~/.boto or ~/.aws/credentials, see the [boto docs](http://docs.pythonboto.org/en/latest/boto_config_tut.html) for the format. +Subscribe to CentOS +------------------- + +1. [CentOS on AWS](https://aws.amazon.com/marketplace/pp/B00O7WM7QW) + + +Set up Security Group +--------------------- +By default, a cluster is launched into the `public` security group. Make sure you allow hosts to talk to each other on port `4789` for SDN. +You may also want to allow access from the outside world on the following ports: + +``` +• 22    - ssh +• 80    - Web Apps +• 443   - Web Apps (https) +• 4789  - SDN / VXLAN +• 8443  - Openshift Console +• 10250 - kubelet  +``` + +  (Optional) Setup your $HOME/.ssh/config file  -------------------------------------------  In case of a cluster creation, or any other case where you don't know the machine hostname in advance, you can use `.ssh/config` @@ -130,3 +151,21 @@ The --deployment-type flag can be passed to bin/cluster to specify the deploymen    bin/cluster create aws --deployment-type=online <cluster-id>  ```  Note: If no deployment type is specified, then the default is origin. + + +## Post-ansible steps +Create the default router +------------------------- +On the master host: +```sh +oadm router --create=true \ +  --credentials=/etc/openshift/master/openshift-router.kubeconfig +``` + +Create the default docker-registry +---------------------------------- +On the master host: +```sh +oadm registry --create=true \ +  --credentials=/etc/openshift/master/openshift-registry.kubeconfig +```
\ No newline at end of file diff --git a/bin/cluster b/bin/cluster index 7eb4a4448..c80fe0cab 100755 --- a/bin/cluster +++ b/bin/cluster @@ -23,6 +23,16 @@ class Cluster(object):                  '-o ControlMaster=auto '                  '-o ControlPersist=600s '              ) +            # Because of `UserKnownHostsFile=/dev/null` +            # our `.ssh/known_hosts` file most probably misses the ssh host public keys +            # of our servers. +            # In that case, ansible serializes the execution of ansible modules +            # because we might be interactively prompted to accept the ssh host public keys. +            # Because of `StrictHostKeyChecking=no` we know that we won't be prompted +            # So, we don't want our modules execution to be serialized. +            os.environ['ANSIBLE_HOST_KEY_CHECKING'] = 'False' +            # TODO: A more secure way to proceed would consist in dynamically +            # retrieving the ssh host public keys from the IaaS interface      def get_deployment_type(self, args):          """ diff --git a/bin/openshift_ansible/aws b/bin/openshift_ansible/aws new file mode 120000 index 000000000..eb0575b4d --- /dev/null +++ b/bin/openshift_ansible/aws @@ -0,0 +1 @@ +../../inventory/aws/
\ No newline at end of file diff --git a/bin/ossh_bash_completion b/bin/ossh_bash_completion index 1467de858..5072161f0 100755 --- a/bin/ossh_bash_completion +++ b/bin/ossh_bash_completion @@ -1,6 +1,12 @@  __ossh_known_hosts(){ -    if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then -        /usr/bin/python -c 'import json,os; z = json.loads(open("%s"%os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache")).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])' +    if python -c 'import openshift_ansible' &>/dev/null; then +      /usr/bin/python -c 'from openshift_ansible import multi_ec2; m=multi_ec2.MultiEc2(); m.run(); z=m.result; print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])' + +    elif [[ -f /dev/shm/.ansible/tmp/multi_ec2_inventory.cache ]]; then +      /usr/bin/python -c 'import json; loc="/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"; z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])' + +    elif [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then +      /usr/bin/python -c 'import json,os; loc="%s" % os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache"); z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])'      fi  } @@ -19,8 +25,15 @@ _ossh()  complete -F _ossh ossh oscp  __opssh_known_hosts(){ -    if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then -                /usr/bin/python -c 'import json,os; z = json.loads(open("%s"%os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache")).read()); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in z["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' +    if python -c 'import openshift_ansible' &>/dev/null; then +      /usr/bin/python -c 'from openshift_ansible.multi_ec2 import MultiEc2; m=MultiEc2(); m.run(); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in m.result["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' + +    elif [[ -f /dev/shm/.ansible/tmp/multi_ec2_inventory.cache ]]; then +      /usr/bin/python -c 'import json; loc="/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"; z=json.loads(open(loc).read()); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in z["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' + +    elif [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then +      /usr/bin/python -c 'import json,os; loc="%s" % os.path.expanduser("/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"); z=json.loads(open(loc).read()); print "\n".join(["%s" % (host["ec2_tag_host-type"]) for dns, host in z["_meta"]["hostvars"].items() if "ec2_tag_host-type" in host])' +      fi  } diff --git a/bin/ossh_zsh_completion b/bin/ossh_zsh_completion index 6ab930dc4..44500c618 100644 --- a/bin/ossh_zsh_completion +++ b/bin/ossh_zsh_completion @@ -1,9 +1,16 @@  #compdef ossh oscp  _ossh_known_hosts(){ -  if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then -    print $(/usr/bin/python -c 'import json,os; z = json.loads(open("%s"%os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache")).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items()])') -  fi +    if python -c 'import openshift_ansible' &>/dev/null; then +      print $(/usr/bin/python -c 'from openshift_ansible import multi_ec2; m=multi_ec2.MultiEc2(); m.run(); z=m.result; print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])') + +    elif [[ -f /dev/shm/.ansible/tmp/multi_ec2_inventory.cache ]]; then +      print $(/usr/bin/python -c 'import json; loc="/dev/shm/.ansible/tmp/multi_ec2_inventory.cache"; z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])') + +    elif [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then +      print $(/usr/bin/python -c 'import json,os; loc="%s" % os.path.expanduser("~/.ansible/tmp/multi_ec2_inventory.cache"); z=json.loads(open(loc).read()); print "\n".join(["%s.%s" % (host["ec2_tag_Name"],host["ec2_tag_environment"]) for dns, host in z["_meta"]["hostvars"].items() if all(k in host for k in ("ec2_tag_Name", "ec2_tag_environment"))])') + +    fi  }  _ossh(){ diff --git a/git/.pylintrc b/git/.pylintrc index af8f1656f..fe6eef6de 100644 --- a/git/.pylintrc +++ b/git/.pylintrc @@ -71,7 +71,7 @@ confidence=  # no Warning level messages displayed, use"--disable=all --enable=classes  # --disable=W"  # w0511 - fixme - disabled because TODOs are acceptable -disable=E1608,W1627,E1601,E1603,E1602,E1605,E1604,E1607,E1606,W1621,W1620,W1623,W1622,W1625,W1624,W1609,W1608,W1607,W1606,W1605,W1604,W1603,W1602,W1601,W1639,W1640,I0021,W1638,I0020,W1618,W1619,W1630,W1626,W1637,W1634,W1635,W1610,W1611,W1612,W1613,W1614,W1615,W1616,W1617,W1632,W1633,W0704,W1628,W1629,W1636,W0511 +disable=E1608,W1627,E1601,E1603,E1602,E1605,E1604,E1607,E1606,W1621,W1620,W1623,W1622,W1625,W1624,W1609,W1608,W1607,W1606,W1605,W1604,W1603,W1602,W1601,W1639,W1640,I0021,W1638,I0020,W1618,W1619,W1630,W1626,W1637,W1634,W1635,W1610,W1611,W1612,W1613,W1614,W1615,W1616,W1617,W1632,W1633,W0704,W1628,W1629,W1636,W0511,R0801  [REPORTS] @@ -205,7 +205,7 @@ docstring-min-length=-1  [SIMILARITIES]  # Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=0  # Ignore comments when computing similarities.  ignore-comments=yes @@ -214,7 +214,7 @@ ignore-comments=yes  ignore-docstrings=yes  # Ignore imports when computing similarities. -ignore-imports=no +ignore-imports=yes  [VARIABLES] diff --git a/inventory/multi_ec2.py b/inventory/multi_ec2.py index b7ce9e5dc..2cbf33473 100755 --- a/inventory/multi_ec2.py +++ b/inventory/multi_ec2.py @@ -78,7 +78,7 @@ class MultiEc2(object):                  },              ] -            self.config['cache_max_age'] = 0 +            self.config['cache_max_age'] = 300          else:              raise RuntimeError("Could not find valid ec2 credentials in the environment.") diff --git a/playbooks/adhoc/create_pv/create_pv.yaml b/playbooks/adhoc/create_pv/create_pv.yaml new file mode 100644 index 000000000..684a0ca72 --- /dev/null +++ b/playbooks/adhoc/create_pv/create_pv.yaml @@ -0,0 +1,142 @@ +--- +#example run:  +# ansible-playbook -e "cli_volume_size=1" \ +#                  -e "cli_device_name=/dev/xvdf" \ +#                  -e "cli_hosttype=master" \ +#                  -e "cli_environment=ops" \ +#                  create_pv.yaml +# FIXME: we need to change "environment" to "clusterid" as that's what it really is now. +# +- name: Create a volume and attach it to master +  hosts: localhost +  gather_facts: no +  vars: +    cli_volume_type: gp2 +    cli_volume_iops: '' +    oo_name: "{{ groups['tag_host-type_' ~ cli_hosttype] | +                 intersect(groups['tag_environment_' ~ cli_environment]) | +                 first }}" +  pre_tasks: +  - fail: +      msg: "This playbook requires {{item}} to be set." +    when: "{{ item }} is not defined or {{ item }} == ''" +    with_items: +    - cli_volume_size +    - cli_device_name +    - cli_hosttype +    - cli_environment + +  - name: set oo_name fact +    set_fact: +      oo_name: "{{ oo_name }}" + + +  - name: Select a single master to run this on +    add_host: +      hostname: "{{ oo_name }}" +      ansible_ssh_host: "{{ hostvars[oo_name].ec2_public_dns_name }}" +      groups: oo_master + +  - name: Create a volume and attach it +    ec2_vol: +      state: present +      instance: "{{ hostvars[oo_name]['ec2_id'] }}" +      region: "{{ hostvars[oo_name]['ec2_region'] }}" +      volume_size: "{{ cli_volume_size }}" +      volume_type: "{{ cli_volume_type }}" +      device_name: "{{ cli_device_name }}" +      iops: "{{ cli_volume_iops }}" +    register: vol + +  - debug: var=vol + +- name: Configure the drive +  gather_facts: no +  hosts: oo_master +  user: root +  connection: ssh +  vars: +    pv_tmpdir: /tmp/persistentvolumes + +  post_tasks: +  - name: Setting facts for template +    set_fact: +      pv_name: "pv-{{cli_volume_size}}-{{ hostvars[hostvars.localhost.oo_name]['ec2_tag_Name'] }}-{{hostvars.localhost.vol.volume_id }}" +      vol_az: "{{ hostvars[hostvars.localhost.oo_name]['ec2_placement'] }}" +      vol_id: "{{ hostvars.localhost.vol.volume_id }}" +      vol_size: "{{ cli_volume_size }}" +      pv_mntdir: "{{ pv_tmpdir }}/mnt-{{ 1000 | random }}" + +  - set_fact: +      pv_template: "{{ pv_tmpdir }}/{{ pv_name }}.yaml" + +  - name: "Mkdir {{ pv_tmpdir }}" +    file: +      state: directory +      path: "{{ pv_tmpdir }}" +      mode: '0750' + +  - name: "Mkdir {{ pv_mntdir }}" +    file: +      state: directory +      path: "{{ pv_mntdir }}" +      mode: '0750' + +  - name: Create pv file from template +    template: +      src: ./pv-template.j2 +      dest: "{{ pv_template }}" +      owner: root +      mode: '0640' + +  - name: mkfs +    filesystem: +      dev: "{{ cli_device_name }}" +      fstype: ext4 +     +  - name: Mount the dev +    mount: +      name: "{{ pv_mntdir }}" +      src: "{{ cli_device_name }}" +      fstype: ext4 +      state: mounted + +  - name: chgrp g+rwXs +    file:  +      path: "{{ pv_mntdir }}" +      mode: 'g+rwXs' +      recurse: yes +      seuser: system_u +      serole: object_r +      setype: svirt_sandbox_file_t +      selevel: s0 + +  - name: umount +    mount: +      name: "{{ pv_mntdir }}" +      src: "{{ cli_device_name }}" +      state: unmounted +      fstype: ext4 + +  - name: detach drive +    delegate_to: localhost +    ec2_vol: +      region: "{{ hostvars[hostvars.localhost.oo_name].ec2_region }}" +      id: "{{ hostvars.localhost.vol.volume_id }}" +      instance: None + +  - name: "Remove {{ pv_mntdir }}" +    file: +      state: absent +      path: "{{ pv_mntdir }}" + +  # We have to use the shell module because we can't set env vars with the command module. +  - name: "Place PV into oc" +    shell: "KUBECONFIG=/etc/openshift/master/admin.kubeconfig oc create -f {{ pv_template | quote }}" +    register: oc_output + +  - debug: var=oc_output + +  - fail:  +      msg: "Failed to add {{ pv_template }} to master." +    when: oc_output.rc != 0 diff --git a/playbooks/adhoc/create_pv/pv-template.j2 b/playbooks/adhoc/create_pv/pv-template.j2 new file mode 100644 index 000000000..5654ef6c4 --- /dev/null +++ b/playbooks/adhoc/create_pv/pv-template.j2 @@ -0,0 +1,16 @@ +--- +apiVersion: v1 +kind: PersistentVolume +metadata: +  name: {{ pv_name }} +  labels: +    type: ebs +spec: +  capacity: +    storage: {{ vol_size }}Gi +  accessModes: +    - ReadWriteOnce +  persistentVolumeReclaimPolicy: Recycle +  awsElasticBlockStore: +    volumeID: aws://{{ vol_az }}/{{ vol_id }} +    fsType: ext4 diff --git a/playbooks/adhoc/deploy_monitoring_containers/deploy.yml b/playbooks/adhoc/deploy_monitoring_containers/deploy.yml deleted file mode 100644 index 44df693d5..000000000 --- a/playbooks/adhoc/deploy_monitoring_containers/deploy.yml +++ /dev/null @@ -1,58 +0,0 @@ ---- -- name: Setup hosts -  hosts: localhost -  gather_facts: no -  user: root -  tasks: -  - name: build inven -    add_host: "name={{ hostvars[item]['ec2_public_dns_name'] }} groups=oo_hosts" -    with_items: groups['tag_env-host-type_kwoodsontest2-openshift-node'] - -  - debug: msg=oo_hosts - -- name: Deploy host-monitoring -  hosts: oo_hosts -  user: root -  tasks: -  - name: Deploy docker oso-f22-host-monitoring -    command: docker pull docker-registry.ops.rhcloud.com/ops/oso-f22-host-monitoring - -  - name: Deploy oso-rhel7-zagg-client -    command: docker pull docker-registry.ops.rhcloud.com/ops/oso-rhel7-zagg-client - -  - name: Copy oso-f22-host-monitoring systemd file -    copy: -        src: oso-f22-host-monitoring.service -        dest: /etc/systemd/system/oso-f22-host-monitoring.service -        owner: root -        group: root -        mode: 0644 -    register: pcp_systemd - -  - name: Copy zagg-client systemd file -    copy: -        src: oso-rhel7-zagg-client.service -        dest: /etc/systemd/system/oso-rhel7-zagg-client.service -        owner: root -        group: root -        mode: 0644 -    register: zagg_systemd - -  - name: reload systemd -    command: /usr/bin/systemctl --system daemon-reload -    when: pcp_systemd.changed or zagg_systemd.changed - -  - name: pasue for a few seconds -    pause: seconds=5 - -  - name: Start the oso-f22-host-monitoring service -    service: -      name: oso-f22-host-monitoring -      state: started -      enabled: yes - -  - name: Start the oso-rhel7-zagg-client service -    service: -      name: oso-rhel7-zagg-client -      state: started -      enabled: yes diff --git a/playbooks/adhoc/deploy_monitoring_containers/oso-f22-host-monitoring.service b/playbooks/adhoc/deploy_monitoring_containers/oso-f22-host-monitoring.service deleted file mode 100644 index 852be09b6..000000000 --- a/playbooks/adhoc/deploy_monitoring_containers/oso-f22-host-monitoring.service +++ /dev/null @@ -1,36 +0,0 @@ -# This is a systemd file to run this docker container under systemd. -# To make this work: -#  * pull the image (probably from ops docker registry) -#  * place this file in /etc/systemd/system without the .systemd extension -#  * run the commands: -#  systemctl daemon-reload -#  systemctl enable pcp-docker -#  systemctl start pcp-docker -# -# -[Unit] -Description=PCP Collector Contatainer -Requires=docker.service -After=docker.service - - -[Service] -Type=simple -TimeoutStartSec=5m -#Slice=container-small.slice - -ExecStartPre=-/usr/bin/docker rm "oso-f22-host-monitoring" - -ExecStart=/usr/bin/docker run --rm  --name=oso-f22-host-monitoring            \ -          --privileged --net=host --pid=host --ipc=host                       \ -          -v /sys:/sys:ro  -v /etc/localtime:/etc/localtime:ro                \ -          -v /var/lib/docker:/var/lib/docker:ro -v /run:/run                  \ -          -v /var/log:/var/log                                                \ -          docker-registry.ops.rhcloud.com/ops/oso-f22-host-monitoring - -ExecReload=-/usr/bin/docker stop "oso-f22-host-monitoring" -ExecReload=-/usr/bin/docker rm "oso-f22-host-monitoring" -ExecStop=-/usr/bin/docker stop "oso-f22-host-monitoring" - -[Install] -WantedBy=default.target diff --git a/playbooks/adhoc/deploy_monitoring_containers/oso-rhel7-zagg-client.service b/playbooks/adhoc/deploy_monitoring_containers/oso-rhel7-zagg-client.service deleted file mode 100644 index 381c7b487..000000000 --- a/playbooks/adhoc/deploy_monitoring_containers/oso-rhel7-zagg-client.service +++ /dev/null @@ -1,39 +0,0 @@ -# This is a systemd file to run this docker container under systemd. -# To make this work: -#  * pull the image (probably from ops docker registry) -#  * place this file in /etc/systemd/system without the .systemd extension -#  * run the commands: -#  systemctl daemon-reload -#  systemctl enable zagg-client-docker -#  systemctl start zagg-client-docker -# -# -[Unit] -Description=Zagg Client Contatainer -Requires=docker.service -After=docker.service - - -[Service] -Type=simple -TimeoutStartSec=5m -#Slice=container-small.slice - -ExecStartPre=-/usr/bin/docker rm "oso-rhel7-zagg-client" - - -ExecStart=/usr/bin/docker run --name oso-rhel7-zagg-client                               \ -           -e ZAGG_SERVER=SERVERNAME                                                     \ -           -e ZAGG_USER=USERNAME                                                         \ -           -e ZAGG_PASSWORD=PASSWORD                                                     \ -           -v /etc/localtime:/etc/localtime                                              \ -           -v /run/pcp:/run/pcp                                                          \ -           docker-registry.ops.rhcloud.com/ops/oso-rhel7-zagg-client - - -ExecReload=-/usr/bin/docker stop "oso-rhel7-zagg-client" -ExecReload=-/usr/bin/docker rm "oso-rhel7-zagg-client" -ExecStop=-/usr/bin/docker stop "oso-rhel7-zagg-client" - -[Install] -WantedBy=default.target diff --git a/playbooks/adhoc/zabbix_setup/clean_zabbix.yml b/playbooks/adhoc/zabbix_setup/clean_zabbix.yml index 610d18b28..a31cbef65 100644 --- a/playbooks/adhoc/zabbix_setup/clean_zabbix.yml +++ b/playbooks/adhoc/zabbix_setup/clean_zabbix.yml @@ -2,67 +2,50 @@  - hosts: localhost    gather_facts: no    vars: -    # Use this for local ZAIO      g_zserver: http://localhost/zabbix/api_jsonrpc.php -      g_zuser: Admin      g_zpassword: zabbix    roles: -  - ../roles/os_zabbix +  - ../../../roles/os_zabbix    post_tasks: -  - zbxapi: +  - zbx_template:        server: "{{ g_zserver }}"        user: "{{ g_zuser }}"        password: "{{ g_zpassword }}" -      zbx_class: Template        state: list -      params: -        output: extend -        search: -          host: 'Template Heartbeat' +      name: 'Template Heartbeat'      register: templ_heartbeat -  - zbxapi: +  - zbx_template:        server: "{{ g_zserver }}"        user: "{{ g_zuser }}"        password: "{{ g_zpassword }}" -      zbx_class: Template        state: list -      params: -        output: extend -        search: -          host: 'Template App Zabbix Server' +      name: 'Template App Zabbix Server'      register: templ_zabbix_server -  - zbxapi: +  - zbx_template:        server: "{{ g_zserver }}"        user: "{{ g_zuser }}"        password: "{{ g_zpassword }}" -      zbx_class: Template        state: list -      params: -        output: extend -        search: -          host: 'Template App Zabbix Agent' +      name: 'Template App Zabbix Agent'      register: templ_zabbix_agent -  - zbxapi: +  - zbx_template:        server: "{{ g_zserver }}"        user: "{{ g_zuser }}"        password: "{{ g_zpassword }}" -      zbx_class: Template        state: list      register: templates    - debug: var=templ_heartbeat.results -  - zbxapi: +  - zbx_template:        server: "{{ g_zserver }}"        user: "{{ g_zuser }}"        password: "{{ g_zpassword }}" -      zbx_class: Template        state: absent -      params: "{{templates.results | difference(templ_zabbix_agent.results) | difference(templ_zabbix_server.results) | oo_collect('templateid') }}" -    register: template_results +    with_items: "{{ templates.results | difference(templ_zabbix_agent.results) | difference(templ_zabbix_server.results) | oo_collect('host') }}"      when:  templ_heartbeat.results | length == 0 diff --git a/playbooks/adhoc/zabbix_setup/create_app.yml b/playbooks/adhoc/zabbix_setup/create_app.yml deleted file mode 100644 index 3a08b2301..000000000 --- a/playbooks/adhoc/zabbix_setup/create_app.yml +++ /dev/null @@ -1,34 +0,0 @@ ---- -- hosts: localhost -  gather_facts: no -  vars_files: -  - vars/template_heartbeat.yml -  - vars/template_os_linux.yml -  vars: -    g_zserver: http://oso-rhel7-zabbix-web.kwoodsontest2.opstest.online.openshift.com/zabbix/api_jsonrpc.php -    g_zuser: Admin -    g_zpassword: zabbix -  roles: -  - ../roles/os_zabbix -  post_tasks: -  - zbxapi: -      server: "{{ g_zserver }}" -      user: "{{ g_zuser }}" -      password: "{{ g_zpassword }}" -      zbx_class: Template -      state: list -      params: -        output: extend -    register: templates - -  - debug: var=templates - -  - name: Create app -    include: create_application.yml -    vars: -      ctp_template: "{{ g_template_heartbeat }}" -      ctp_zserver: "{{ g_zserver }}" -      ctp_zuser: "{{ g_zuser }}" -      ctp_zpassword: "{{ g_zpassword }}" - - diff --git a/playbooks/adhoc/zabbix_setup/create_application.yml b/playbooks/adhoc/zabbix_setup/create_application.yml deleted file mode 100644 index aa6c40ed8..000000000 --- a/playbooks/adhoc/zabbix_setup/create_application.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- -- debug: var=ctp_template - -- name: Create Application -  zbxapi: -    server: "{{ ctp_zserver }}" -    user: "{{ ctp_zuser }}" -    password: "{{ ctp_zpassword }}" -    zbx_class: Application -    state: present -    params: -      name: "{{ ctp_template.application['name'] }}" -      hostid: 10085 -      search: -        name: "{{ ctp_template.application['name'] }}" -  register: ctp_created_application - -- debug: var=ctp_created_application diff --git a/playbooks/adhoc/zabbix_setup/create_template.yml b/playbooks/adhoc/zabbix_setup/create_template.yml index b055e78eb..50fff53b2 100644 --- a/playbooks/adhoc/zabbix_setup/create_template.yml +++ b/playbooks/adhoc/zabbix_setup/create_template.yml @@ -2,16 +2,14 @@  - debug: var=ctp_template  - name: Create Template -  zbxapi: +  zbx_template:      server: "{{ ctp_zserver }}"      user: "{{ ctp_zuser }}"      password: "{{ ctp_zpassword }}" -    zbx_class: Template -    state: present -    params: "{{ ctp_template.params }}" -  register: ctp_created_templates +    name: "{{ ctp_template.name }}" +  register: ctp_created_template -- debug: var=ctp_created_templates +- debug: var=ctp_created_template  #- name: Create Application  #  zbxapi: @@ -22,7 +20,7 @@  #    state: present  #    params:  #      name: "{{ ctp_template.application.name}}" -#      hostid: "{{ ctp_created_templates.results[0].templateid }}" +#      hostid: "{{ ctp_created_template.results[0].templateid }}"  #      search:  #        name: "{{ ctp_template.application.name}}"  #  register: ctp_created_application @@ -30,28 +28,28 @@  #- debug: var=ctp_created_application  - name: Create Items -  zbxapi: +  zbx_item:      server: "{{ ctp_zserver }}"      user: "{{ ctp_zuser }}"      password: "{{ ctp_zpassword }}" -    zbx_class: Item -    state: present -    params: "{{ item | oo_set_zbx_item_hostid(ctp_created_templates.results) }}" +    key: "{{ item.key }}" +    name: "{{ item.name | default(item.key, true) }}" +    value_type: "{{ item.value_type | default('int') }}" +    template_name: "{{ ctp_template.name }}"    with_items: ctp_template.zitems    register: ctp_created_items  #- debug: var=ctp_created_items  - name: Create Triggers -  zbxapi: +  zbx_trigger:      server: "{{ ctp_zserver }}"      user: "{{ ctp_zuser }}"      password: "{{ ctp_zpassword }}" -    zbx_class: Trigger -    state: present -    params: "{{ item }}" +    description: "{{ item.description }}" +    expression: "{{ item.expression }}" +    priority: "{{ item.priority }}"    with_items: ctp_template.ztriggers -  register: ctp_created_triggers    when: ctp_template.ztriggers is defined  #- debug: var=ctp_created_triggers diff --git a/playbooks/adhoc/zabbix_setup/setup_zabbix.yml b/playbooks/adhoc/zabbix_setup/setup_zabbix.yml index 8b44f2adf..1729194b5 100644 --- a/playbooks/adhoc/zabbix_setup/setup_zabbix.yml +++ b/playbooks/adhoc/zabbix_setup/setup_zabbix.yml @@ -5,22 +5,17 @@    - vars/template_heartbeat.yml    - vars/template_os_linux.yml    vars: -    # Use this for local ZAIO      g_zserver: http://localhost/zabbix/api_jsonrpc.php -      g_zuser: Admin      g_zpassword: zabbix    roles: -  - ../roles/os_zabbix +  - ../../../roles/os_zabbix    post_tasks: -  - zbxapi: +  - zbx_template:        server: "{{ g_zserver }}"        user: "{{ g_zuser }}"        password: "{{ g_zpassword }}" -      zbx_class: Template        state: list -      params: -        output: extend      register: templates    - debug: var=templates diff --git a/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml b/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml index 9d6145ec4..22cc75554 100644 --- a/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml +++ b/playbooks/adhoc/zabbix_setup/vars/template_heartbeat.yml @@ -1,33 +1,11 @@  ---  g_template_heartbeat: -  application: -    name: Heartbeat -#output: extend -    search: -      name: Heartbeat -  params: -    name: Template Heartbeat -    host: Template Heartbeat -    groups: -    - groupid: 1 # FIXME (not real) -    output: extend -    search: -      name: Template Heartbeat +  name: Template Heartbeat    zitems:    - name: Heartbeat Ping      hostid: -    key_: heartbeat.ping -    type: 2 -    value_type: 1 -    output: extend -    search: -      key_: heartbeat.ping -    selectApplications: extend +    key: heartbeat.ping    ztriggers:    - description: 'Heartbeat.ping has failed on {HOST.NAME}'      expression: '{Template Heartbeat:heartbeat.ping.last()}<>0' -    priority: 3 -    searchWildcardsEnabled: True -    search: -      description: 'Heartbeat.ping has failed on*' -    expandExpression: True +    priority: avg diff --git a/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml b/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml index b89711632..9cc038ffa 100644 --- a/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml +++ b/playbooks/adhoc/zabbix_setup/vars/template_os_linux.yml @@ -1,248 +1,90 @@  ---  g_template_os_linux: -  application: -    name: OS Linux -    output: extend -    search: -      name: OS Linux -  params: -    name: Template OS Linux -    host: Template OS Linux -    groups: -    - groupid: 1 # FIXME (not real) -    output: extend -    search: -      name: Template OS Linux +  name: Template OS Linux    zitems: -  - hostid: null -    key_: kernel.uname.sysname -    name: kernel.uname.sysname -    search: -      key_: kernel.uname.sysname -    type: 2 -    value_type: 4 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.wait.total -    name: kernel.all.cpu.wait.total -    search: -      key_: kernel.all.cpu.wait.total -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.irq.hard -    name: kernel.all.cpu.irq.hard -    search: -      key_: kernel.all.cpu.irq.hard -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.idle -    name: kernel.all.cpu.idle -    search: -      key_: kernel.all.cpu.idle -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.uname.distro -    name: kernel.uname.distro -    search: -      key_: kernel.uname.distro -    type: 2 -    value_type: 4 -    selectApplications: extend -  - hostid: null -    key_: kernel.uname.nodename -    name: kernel.uname.nodename -    search: -      key_: kernel.uname.nodename -    type: 2 -    value_type: 4 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.irq.soft -    name: kernel.all.cpu.irq.soft -    search: -      key_: kernel.all.cpu.irq.soft -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.load.15_minute -    name: kernel.all.load.15_minute -    search: -      key_: kernel.all.load.15_minute -    type: 2 -    value_type: 0 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.sys -    name: kernel.all.cpu.sys -    search: -      key_: kernel.all.cpu.sys -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.load.5_minute -    name: kernel.all.load.5_minute -    search: -      key_: kernel.all.load.5_minute -    type: 2 -    value_type: 0 -    selectApplications: extend -  - hostid: null -    key_: mem.freemem -    name: mem.freemem -    search: -      key_: mem.freemem -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.nice -    name: kernel.all.cpu.nice -    search: -      key_: kernel.all.cpu.nice -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: mem.util.bufmem -    name: mem.util.bufmem -    search: -      key_: mem.util.bufmem -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: swap.used -    name: swap.used -    search: -      key_: swap.used -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.load.1_minute -    name: kernel.all.load.1_minute -    search: -      key_: kernel.all.load.1_minute -    type: 2 -    value_type: 0 -    selectApplications: extend -  - hostid: null -    key_: kernel.uname.version -    name: kernel.uname.version -    search: -      key_: kernel.uname.version -    type: 2 -    value_type: 4 -    selectApplications: extend -  - hostid: null -    key_: swap.length -    name: swap.length -    search: -      key_: swap.length -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: mem.physmem -    name: mem.physmem -    search: -      key_: mem.physmem -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.uptime -    name: kernel.all.uptime -    search: -      key_: kernel.all.uptime -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: swap.free -    name: swap.free -    search: -      key_: swap.free -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: mem.util.used -    name: mem.util.used -    search: -      key_: mem.util.used -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.user -    name: kernel.all.cpu.user -    search: -      key_: kernel.all.cpu.user -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.uname.machine -    name: kernel.uname.machine -    search: -      key_: kernel.uname.machine -    type: 2 -    value_type: 4 -    selectApplications: extend -  - hostid: null -    key_: hinv.ncpu -    name: hinv.ncpu -    search: -      key_: hinv.ncpu -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: mem.util.cached -    name: mem.util.cached -    search: -      key_: mem.util.cached -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.cpu.steal -    name: kernel.all.cpu.steal -    search: -      key_: kernel.all.cpu.steal -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.all.pswitch -    name: kernel.all.pswitch -    search: -      key_: kernel.all.pswitch -    type: 2 -    value_type: 3 -    selectApplications: extend -  - hostid: null -    key_: kernel.uname.release -    name: kernel.uname.release -    search: -      key_: kernel.uname.release -    type: 2 -    value_type: 4 -    selectApplications: extend -  - hostid: null -    key_: proc.nprocs -    name: proc.nprocs -    search: -      key_: proc.nprocs -    type: 2 -    value_type: 3 -    selectApplications: extend +  - key: kernel.uname.sysname +    value_type: string + +  - key: kernel.all.cpu.wait.total +    value_type: int + +  - key: kernel.all.cpu.irq.hard +    value_type: int + +  - key: kernel.all.cpu.idle +    value_type: int + +  - key: kernel.uname.distro +    value_type: string + +  - key: kernel.uname.nodename +    value_type: string + +  - key: kernel.all.cpu.irq.soft +    value_type: int + +  - key: kernel.all.load.15_minute +    value_type: float + +  - key: kernel.all.cpu.sys +    value_type: int + +  - key: kernel.all.load.5_minute +    value_type: float + +  - key: mem.freemem +    value_type: int + +  - key: kernel.all.cpu.nice +    value_type: int + +  - key: mem.util.bufmem +    value_type: int + +  - key: swap.used +    value_type: int + +  - key: kernel.all.load.1_minute +    value_type: float + +  - key: kernel.uname.version +    value_type: string + +  - key: swap.length +    value_type: int + +  - key: mem.physmem +    value_type: int + +  - key: kernel.all.uptime +    value_type: int + +  - key: swap.free +    value_type: int + +  - key: mem.util.used +    value_type: int + +  - key: kernel.all.cpu.user +    value_type: int + +  - key: kernel.uname.machine +    value_type: string + +  - key: hinv.ncpu +    value_type: int + +  - key: mem.util.cached +    value_type: int + +  - key: kernel.all.cpu.steal +    value_type: int + +  - key: kernel.all.pswitch +    value_type: int + +  - key: kernel.uname.release +    value_type: string + +  - key: proc.nprocs +    value_type: int diff --git a/playbooks/aws/openshift-cluster/tasks/launch_instances.yml b/playbooks/aws/openshift-cluster/tasks/launch_instances.yml index 92155582e..236d84e74 100644 --- a/playbooks/aws/openshift-cluster/tasks/launch_instances.yml +++ b/playbooks/aws/openshift-cluster/tasks/launch_instances.yml @@ -99,7 +99,7 @@            iops: "{{ lookup('env', 'os_master_root_vol_iops') | default(500, true) }}"        node:          root: -          volume_size: "{{ lookup('env', 'os_node_root_vol_size') | default(25, true) }}" +          volume_size: "{{ lookup('env', 'os_node_root_vol_size') | default(85, true) }}"            device_type: "{{ lookup('env', 'os_node_root_vol_type') | default('gp2', true) }}"            iops: "{{ lookup('env', 'os_node_root_vol_iops') | default(500, true) }}"          docker: diff --git a/playbooks/aws/openshift-cluster/vars.yml b/playbooks/aws/openshift-cluster/vars.yml index fb1793a51..95bc4b3e2 100644 --- a/playbooks/aws/openshift-cluster/vars.yml +++ b/playbooks/aws/openshift-cluster/vars.yml @@ -1,11 +1,11 @@  ---  deployment_vars:    origin: -    # fedora, since centos requires marketplace -    image: ami-acd999c4 +    # centos-7, requires marketplace +    image: ami-96a818fe      image_name:      region: us-east-1 -    ssh_user: fedora +    ssh_user: centos      sudo: yes      keypair: libra      type: m4.large diff --git a/playbooks/libvirt/openshift-cluster/launch.yml b/playbooks/libvirt/openshift-cluster/launch.yml index 6630fa27d..830f9d216 100644 --- a/playbooks/libvirt/openshift-cluster/launch.yml +++ b/playbooks/libvirt/openshift-cluster/launch.yml @@ -42,7 +42,7 @@        count: "{{ num_infra }}"    - include: tasks/launch_instances.yml      vars: -      instances: "{{ infra_names }}" +      instances: "{{ node_names }}"        cluster: "{{ cluster_id }}"        type: "{{ k8s_type }}"        g_sub_host_type: "{{ sub_host_type }}" diff --git a/playbooks/openstack/openshift-cluster/files/heat_stack.yaml b/playbooks/openstack/openshift-cluster/files/heat_stack.yaml index a15ec749c..d53884e0d 100644 --- a/playbooks/openstack/openshift-cluster/files/heat_stack.yaml +++ b/playbooks/openstack/openshift-cluster/files/heat_stack.yaml @@ -16,8 +16,13 @@ parameters:    num_nodes:      type: number -    label: Number of nodes -    description: Number of nodes +    label: Number of compute nodes +    description: Number of compute nodes + +  num_infra: +    type: number +    label: Number of infrastructure nodes +    description: Number of infrastructure nodes    cidr:      type: string @@ -55,7 +60,12 @@ parameters:    node_image:      type: string      label: Node image -    description: Name of the image for the node servers +    description: Name of the image for the compute node servers + +  infra_image: +    type: string +    label: Infra image +    description: Name of the image for the infra node servers    master_flavor:      type: string @@ -65,7 +75,12 @@ parameters:    node_flavor:      type: string      label: Node flavor -    description: Flavor of the node servers +    description: Flavor of the compute node servers + +  infra_flavor: +    type: string +    label: Infra flavor +    description: Flavor of the infra node servers  outputs: @@ -83,15 +98,27 @@ outputs:    node_names:      description: Name of the nodes -    value: { get_attr: [ nodes, name ] } +    value: { get_attr: [ compute_nodes, name ] }    node_ips:      description: IPs of the nodes -    value: { get_attr: [ nodes, private_ip ] } +    value: { get_attr: [ compute_nodes, private_ip ] }    node_floating_ips:      description: Floating IPs of the nodes -    value: { get_attr: [ nodes, floating_ip ] } +    value: { get_attr: [ compute_nodes, floating_ip ] } + +  infra_names: +    description: Name of the nodes +    value: { get_attr: [ infra_nodes, name ] } + +  infra_ips: +    description: IPs of the nodes +    value: { get_attr: [ infra_nodes, private_ip ] } + +  infra_floating_ips: +    description: Floating IPs of the nodes +    value: { get_attr: [ infra_nodes, floating_ip ] }  resources: @@ -218,6 +245,29 @@ resources:            remote_mode: remote_group_id            remote_group_id: { get_resource: master-secgrp } +  infra-secgrp: +    type: OS::Neutron::SecurityGroup +    properties: +      name: +        str_replace: +          template: openshift-ansible-cluster_id-infra-secgrp +          params: +            cluster_id: { get_param: cluster_id } +      description: +        str_replace: +          template: Security group for cluster_id OpenShift infrastructure cluster nodes +          params: +            cluster_id: { get_param: cluster_id } +      rules: +        - direction: ingress +          protocol: tcp +          port_range_min: 80 +          port_range_max: 80 +        - direction: ingress +          protocol: tcp +          port_range_min: 443 +          port_range_max: 443 +    masters:      type: OS::Heat::ResourceGroup      properties: @@ -248,7 +298,7 @@ resources:                  cluster_id: { get_param: cluster_id }      depends_on: interface -  nodes: +  compute_nodes:      type: OS::Heat::ResourceGroup      properties:        count: { get_param: num_nodes } @@ -257,12 +307,14 @@ resources:          properties:            name:              str_replace: -              template: cluster_id-k8s_type-%index% +              template: cluster_id-k8s_type-sub_host_type-%index%                params:                  cluster_id: { get_param: cluster_id }                  k8s_type: node +                sub_host_type: compute            cluster_id: { get_param: cluster_id }            type:       node +          subtype:    compute            image:      { get_param: node_image }            flavor:     { get_param: node_flavor }            key_name:   { get_resource: keypair } @@ -277,3 +329,36 @@ resources:                params:                  cluster_id: { get_param: cluster_id }      depends_on: interface + +  infra_nodes: +    type: OS::Heat::ResourceGroup +    properties: +      count: { get_param: num_infra } +      resource_def: +        type: heat_stack_server.yaml +        properties: +          name: +            str_replace: +              template: cluster_id-k8s_type-sub_host_type-%index% +              params: +                cluster_id: { get_param: cluster_id } +                k8s_type: node +                sub_host_type: infra +          cluster_id: { get_param: cluster_id } +          type:       node +          subtype:    infra +          image:      { get_param: infra_image } +          flavor:     { get_param: infra_flavor } +          key_name:   { get_resource: keypair } +          net:        { get_resource: net } +          subnet:     { get_resource: subnet } +          secgrp: +            - { get_resource: node-secgrp } +            - { get_resource: infra-secgrp } +          floating_network: { get_param: external_net } +          net_name: +            str_replace: +              template: openshift-ansible-cluster_id-net +              params: +                cluster_id: { get_param: cluster_id } +    depends_on: interface diff --git a/playbooks/openstack/openshift-cluster/files/heat_stack_server.yaml b/playbooks/openstack/openshift-cluster/files/heat_stack_server.yaml index 55f64211a..9dcab3e60 100644 --- a/playbooks/openstack/openshift-cluster/files/heat_stack_server.yaml +++ b/playbooks/openstack/openshift-cluster/files/heat_stack_server.yaml @@ -19,6 +19,12 @@ parameters:      label: Type      description: Type master or node +  subtype: +    type: string +    label: Sub-type +    description: Sub-type compute or infra for nodes, default otherwise +    default: default +    key_name:      type: string      label: Key name @@ -102,11 +108,12 @@ resources:          env: { get_param: cluster_id }          host-type: { get_param: type }          env-host-type: -          str_template: +          str_replace:              template: cluster_id-openshift-type              params:                cluster_id: { get_param: cluster_id }                type:       { get_param: type } +        sub-host-type:    { get_param: subtype }    port:      type: OS::Neutron::Port diff --git a/playbooks/openstack/openshift-cluster/launch.yml b/playbooks/openstack/openshift-cluster/launch.yml index d41448dc0..d36bdbf26 100644 --- a/playbooks/openstack/openshift-cluster/launch.yml +++ b/playbooks/openstack/openshift-cluster/launch.yml @@ -90,7 +90,7 @@        ansible_ssh_host: '{{ item[2] }}'        ansible_ssh_user: "{{ deployment_vars[deployment_type].ssh_user }}"        ansible_sudo: "{{ deployment_vars[deployment_type].sudo }}" -      groups: 'tag_env_{{ cluster_id }}, tag_host-type_node, tag_env-host-type_{{ cluster_id }}-openshift-node, tag_sub-host-type_node' +      groups: 'tag_env_{{ cluster_id }}, tag_host-type_node, tag_env-host-type_{{ cluster_id }}-openshift-node, tag_sub-host-type_compute'      with_together:        - parsed_outputs.node_names        - parsed_outputs.node_ips @@ -115,6 +115,7 @@      with_flattened:        - parsed_outputs.master_floating_ips        - parsed_outputs.node_floating_ips +      - parsed_outputs.infra_floating_ips    - name: Wait for user setup      command: 'ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null {{ deployment_vars[deployment_type].ssh_user }}@{{ item }} echo {{ deployment_vars[deployment_type].ssh_user }} user is setup' @@ -125,6 +126,7 @@      with_flattened:        - parsed_outputs.master_floating_ips        - parsed_outputs.node_floating_ips +      - parsed_outputs.infra_floating_ips  - include: update.yml diff --git a/roles/etcd/templates/etcd.conf.j2 b/roles/etcd/templates/etcd.conf.j2 index 801be2c97..9ac23b1dd 100644 --- a/roles/etcd/templates/etcd.conf.j2 +++ b/roles/etcd/templates/etcd.conf.j2 @@ -16,8 +16,8 @@ ETCD_NAME=default  {% endif %}  ETCD_DATA_DIR={{ etcd_data_dir }}  #ETCD_SNAPSHOT_COUNTER="10000" -#ETCD_HEARTBEAT_INTERVAL="100" -#ETCD_ELECTION_TIMEOUT="1000" +ETCD_HEARTBEAT_INTERVAL="500" +ETCD_ELECTION_TIMEOUT="2500"  ETCD_LISTEN_CLIENT_URLS={{ etcd_listen_client_urls }}  #ETCD_MAX_SNAPSHOTS="5"  #ETCD_MAX_WALS="5" diff --git a/roles/fluentd_master/tasks/main.yml b/roles/fluentd_master/tasks/main.yml index d828db52a..d64900eb0 100644 --- a/roles/fluentd_master/tasks/main.yml +++ b/roles/fluentd_master/tasks/main.yml @@ -39,6 +39,9 @@      owner: 'td-agent'      mode: 0444 +- name: "Pause before restarting td-agent and openshift-master, depending on the number of nodes." +  pause: seconds={{ num_nodes|int * 5 }} +  - name: ensure td-agent is running    service:      name: 'td-agent' diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py index d733639c3..4e0989c5f 100755 --- a/roles/openshift_facts/library/openshift_facts.py +++ b/roles/openshift_facts/library/openshift_facts.py @@ -300,8 +300,7 @@ def set_registry_url_if_unset(facts):                  if deployment_type == 'enterprise':                      registry_url = "openshift3/ose-${component}:${version}"                  elif deployment_type == 'online': -                    registry_url = ("docker-registry.ops.rhcloud.com/" -                                    "openshift3/ose-${component}:${version}") +                    registry_url = ("openshift3/ose-${component}:${version}")                  facts[role]['registry_url'] = registry_url      return facts diff --git a/roles/os_zabbix/library/__init__.py b/roles/os_zabbix/library/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/roles/os_zabbix/library/__init__.py diff --git a/roles/os_zabbix/library/test.yml b/roles/os_zabbix/library/test.yml new file mode 100644 index 000000000..f585bcbb2 --- /dev/null +++ b/roles/os_zabbix/library/test.yml @@ -0,0 +1,92 @@ +--- +# This is a test playbook to create one of each of the zabbix ansible modules. +# ensure that the zbxapi module is installed +# ansible-playbook test.yml +- name: Test zabbix ansible module +  hosts: localhost +  gather_facts: no +  vars: +    zbx_server: http://localhost/zabbix/api_jsonrpc.php +    zbx_user: Admin +    zbx_password: zabbix + +  pre_tasks: +  - name: Create a template +    zbx_template: +      server: "{{ zbx_server }}" +      user: "{{ zbx_user }}" +      password: "{{ zbx_password }}" +      name: 'test template' +    register: template_output + +  - debug: var=template_output + +  - name: Create an item +    zbx_item: +      server: "{{ zbx_server }}" +      user: "{{ zbx_user }}" +      password: "{{ zbx_password }}" +      name: 'test item' +      key: 'kenny.item.1' +      template_name: "{{ template_output.results[0].host }}" +    register: item_output + +  - debug: var=item_output + +  - name: Create an trigger +    zbx_trigger: +      server: "{{ zbx_server }}" +      user: "{{ zbx_user }}" +      password: "{{ zbx_password }}" +      expression: '{test template:kenny.item.1.last()}>2' +      desc: 'Kenny desc' +    register: trigger_output + +  - debug: var=trigger_output + +  - name: Create a hostgroup +    zbx_hostgroup: +      server: "{{ zbx_server }}" +      user: "{{ zbx_user }}" +      password: "{{ zbx_password }}" +      name: 'kenny hostgroup' +    register: hostgroup_output + +  - debug: var=hostgroup_output + +  - name: Create a host +    zbx_host: +      server: "{{ zbx_server }}" +      user: "{{ zbx_user }}" +      password: "{{ zbx_password }}" +      name: 'kenny host' +      hostgroups: +      -  'kenny hostgroup' +    register: host_output + +  - debug: var=host_output + +  - name: Create a usergroup +    zbx_usergroup: +      server: "{{ zbx_server }}" +      user: "{{ zbx_user }}" +      password: "{{ zbx_password }}" +      name: kenny usergroup +      rights: +      - 'kenny hostgroup': rw +    register: usergroup_output + +  - debug: var=usergroup_output + +  - name: Create a user +    zbx_user: +      server: "{{ zbx_server }}" +      user: "{{ zbx_user }}" +      password: "{{ zbx_password }}" +      alias: kenny user +      passwd: zabbix +      usergroups: +      - kenny usergroup +    register: user_output + +  - debug: var=user_output diff --git a/roles/os_zabbix/library/zbx_host.py b/roles/os_zabbix/library/zbx_host.py new file mode 100644 index 000000000..d75dfdea1 --- /dev/null +++ b/roles/os_zabbix/library/zbx_host.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +''' +Zabbix host ansible module +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True + +def get_group_ids(zapi, hostgroup_names): +    ''' +    get hostgroups +    ''' +    # Fetch groups by name +    group_ids = [] +    for hgr in hostgroup_names: +        content = zapi.get_content('hostgroup', 'get', {'search': {'name': hgr}}) +        if content.has_key('result'): +            group_ids.append({'groupid': content['result'][0]['groupid']}) + +    return group_ids + +def get_template_ids(zapi, template_names): +    ''' +    get related templates +    ''' +    template_ids = [] +    # Fetch templates by name +    for template_name in template_names: +        content = zapi.get_content('template', 'get', {'search': {'host': template_name}}) +        if content.has_key('result'): +            template_ids.append({'templateid': content['results'][0]['templateid']}) +    return template_ids + +def main(): +    ''' +    Ansible module for zabbix host +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            name=dict(default=None, type='str'), +            hostgroup_names=dict(default=[], type='list'), +            template_names=dict(default=[], type='list'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +            interfaces=dict(default=[], type='list'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + +    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug'])) + +    #Set the instance and the template for the rest of the calls +    zbx_class_name = 'host' +    idname = "hostid" +    hname = module.params['name'] +    state = module.params['state'] + +    # selectInterfaces doesn't appear to be working but is needed. +    content = zapi.get_content(zbx_class_name, +                               'get', +                               {'search': {'host': hname}, +                                'selectGroups': 'groupid', +                                'selectParentTemplates': 'templateid', +                                'selectInterfaces': 'interfaceid', +                               }) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") + +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'host': hname, +                  'groups':  get_group_ids(zapi, module.params('hostgroup_names')), +                  'templates':  get_template_ids(zapi, module.params('template_names')), +                  'interfaces': module.params.get('interfaces', [{'type':  1,         # interface type, 1 = agent +                                                                  'main':  1,         # default interface? 1 = true +                                                                  'useip':  1,        # default interface? 1 = true +                                                                  'ip':  '127.0.0.1', # default interface? 1 = true +                                                                  'dns':  '',         # dns for host +                                                                  'port':  '10050',   # port for interface? 10050 +                                                                 }]) +                 } + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): + +            if key == 'templates' and zab_results.has_key('parentTemplates'): +                if zab_results['parentTemplates'] != value: +                    differences[key] = value + +            elif zab_results[key] != value and zab_results[key] != str(value): +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=zab_results, state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbx_hostgroup.py b/roles/os_zabbix/library/zbx_hostgroup.py new file mode 100644 index 000000000..a1eb875d4 --- /dev/null +++ b/roles/os_zabbix/library/zbx_hostgroup.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +''' Ansible module for hostgroup +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Zabbix hostgroup ansible module +# +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True + +def main(): +    ''' ansible module for hostgroup +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            name=dict(default=None, type='str'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + +    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug'])) + +    #Set the instance and the template for the rest of the calls +    zbx_class_name = 'hostgroup' +    idname = "groupid" +    hname = module.params['name'] +    state = module.params['state'] + +    content = zapi.get_content(zbx_class_name, +                               'get', +                               {'search': {'name': hname}, +                               }) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") + +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'name': hname} + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): +            if zab_results[key] != value and zab_results[key] != str(value): +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=zab_results, state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbx_item.py b/roles/os_zabbix/library/zbx_item.py new file mode 100644 index 000000000..57ec06463 --- /dev/null +++ b/roles/os_zabbix/library/zbx_item.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +''' + Ansible module for zabbix items +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Zabbix item ansible module +# +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True + +def get_value_type(value_type): +    ''' +    Possible values: +    0 - numeric float; +    1 - character; +    2 - log; +    3 - numeric unsigned; +    4 - text +    ''' +    vtype = 0 +    if 'int' in value_type: +        vtype = 3 +    elif 'char' in value_type: +        vtype = 1 +    elif 'str' in value_type: +        vtype = 4 + +    return vtype + +def main(): +    ''' +    ansible zabbix module for zbx_item +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            name=dict(default=None, type='str'), +            key=dict(default=None, type='str'), +            template_name=dict(default=None, type='str'), +            zabbix_type=dict(default=2, type='int'), +            value_type=dict(default='int', type='str'), +            applications=dict(default=[], type='list'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + +    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug'])) + +    #Set the instance and the template for the rest of the calls +    zbx_class_name = 'item' +    idname = "itemid" +    state = module.params['state'] +    key = module.params['key'] +    template_name = module.params['template_name'] + +    content = zapi.get_content('template', 'get', {'search': {'host': template_name}}) +    templateid = None +    if content['result']: +        templateid = content['result'][0]['templateid'] +    else: +        module.exit_json(changed=False, +                         results='Error: Could find template with name %s for item.' % template_name, +                         state="Unkown") + +    content = zapi.get_content(zbx_class_name, +                               'get', +                               {'search': {'key_': key}, +                                'selectApplications': 'applicationid', +                               }) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") + +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'name': module.params.get('name', module.params['key']), +                  'key_': key, +                  'hostid': templateid, +                  'type': module.params['zabbix_type'], +                  'value_type': get_value_type(module.params['value_type']), +                  'applications': module.params['applications'], +                 } + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): + +            if zab_results[key] != value and zab_results[key] != str(value): +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=zab_results, state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbx_mediatype.py b/roles/os_zabbix/library/zbx_mediatype.py new file mode 100644 index 000000000..a49aecd0f --- /dev/null +++ b/roles/os_zabbix/library/zbx_mediatype.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +''' + Ansible module for mediatype +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Zabbix mediatype ansible module +# +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True +def get_mtype(mtype): +    ''' +    Transport used by the media type. +    Possible values: +    0 - email; +    1 - script; +    2 - SMS; +    3 - Jabber; +    100 - Ez Texting. +    ''' +    mtype = mtype.lower() +    media_type = None +    if mtype == 'script': +        media_type = 1 +    elif mtype == 'sms': +        media_type = 2 +    elif mtype == 'jabber': +        media_type = 3 +    elif mtype == 'script': +        media_type = 100 +    else: +        media_type = 0 + +    return media_type + +def main(): +    ''' +    Ansible zabbix module for mediatype +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            description=dict(default=None, type='str'), +            mtype=dict(default=None, type='str'), +            smtp_server=dict(default=None, type='str'), +            smtp_helo=dict(default=None, type='str'), +            smtp_email=dict(default=None, type='str'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + +    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug'])) + +    #Set the instance and the template for the rest of the calls +    zbx_class_name = 'mediatype' +    idname = "mediatypeid" +    description = module.params['description'] +    state = module.params['state'] + +    content = zapi.get_content(zbx_class_name, 'get', {'search': {'description': description}}) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") + +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'description': description, +                  'type': get_mtype(module.params['media_type']), +                  'smtp_server': module.params['smtp_server'], +                  'smtp_helo': module.params['smtp_helo'], +                  'smtp_email': module.params['smtp_email'], +                 } + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): +            if zab_results[key] != value and \ +               zab_results[key] != str(value): +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=zab_results, state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbx_template.py b/roles/os_zabbix/library/zbx_template.py new file mode 100644 index 000000000..676fa7e49 --- /dev/null +++ b/roles/os_zabbix/library/zbx_template.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +''' +Ansible module for template +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Zabbix template ansible module +# +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True + +def main(): +    ''' Ansible module for template +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            name=dict(default=None, type='str'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + +    zbc = ZabbixConnection(module.params['server'], user, passwd, module.params['debug']) +    zapi = ZabbixAPI(zbc) + +    #Set the instance and the template for the rest of the calls +    zbx_class_name = 'template' +    idname = 'templateid' +    tname = module.params['name'] +    state = module.params['state'] +    # get a template, see if it exists +    content = zapi.get_content(zbx_class_name, +                               'get', +                               {'search': {'host': tname}, +                                'selectParentTemplates': 'templateid', +                                'selectGroups': 'groupid', +                                #'selectApplications': extend, +                               }) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") + +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'groups': module.params.get('groups', [{'groupid': '1'}]), +                  'host': tname, +                 } + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): +            if key == 'templates' and zab_results.has_key('parentTemplates'): +                if zab_results['parentTemplates'] != value: +                    differences[key] = value +            elif zab_results[key] != str(value) and zab_results[key] != value: +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=content['result'], state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbx_trigger.py b/roles/os_zabbix/library/zbx_trigger.py new file mode 100644 index 000000000..7cc9356c8 --- /dev/null +++ b/roles/os_zabbix/library/zbx_trigger.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +''' +ansible module for zabbix triggers +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Zabbix trigger ansible module +# +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True + + +def get_priority(priority): +    ''' determine priority +    ''' +    prior = 0 +    if 'info' in priority: +        prior = 1 +    elif 'warn' in priority: +        prior = 2 +    elif 'avg' == priority or 'ave' in priority: +        prior = 3 +    elif 'high' in priority: +        prior = 4 +    elif 'dis' in priority: +        prior = 5 + +    return prior + +def get_deps(zapi, deps): +    ''' get trigger dependencies +    ''' +    results = [] +    for desc in deps: +        content = zapi.get_content('trigger', +                                   'get', +                                   {'search': {'description': desc}, +                                    'expandExpression': True, +                                    'selectDependencies': 'triggerid', +                                   }) +        if content.has_key('result'): +            results.append({'triggerid': content['result'][0]['triggerid']}) + +    return results + +def main(): +    ''' +    Create a trigger in zabbix + +    Example: +    "params": { +        "description": "Processor load is too high on {HOST.NAME}", +        "expression": "{Linux server:system.cpu.load[percpu,avg1].last()}>5", +        "dependencies": [ +            { +                "triggerid": "14062" +            } +        ] +    }, + +    ''' + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            expression=dict(default=None, type='str'), +            description=dict(default=None, type='str'), +            dependencies=dict(default=[], type='list'), +            priority=dict(default='avg', type='str'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + + +    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug'])) + +    #Set the instance and the template for the rest of the calls +    zbx_class_name = 'trigger' +    idname = "triggerid" +    state = module.params['state'] +    description = module.params['description'] + +    content = zapi.get_content(zbx_class_name, +                               'get', +                               {'search': {'description': description}, +                                'expandExpression': True, +                                'selectDependencies': 'triggerid', +                               }) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'description': description, +                  'expression':  module.params['expression'], +                  'dependencies': get_deps(zapi, module.params['dependencies']), +                  'priority': get_priority(module.params['priority']), +                 } + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): + +            if zab_results[key] != value and zab_results[key] != str(value): +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=zab_results, state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbx_user.py b/roles/os_zabbix/library/zbx_user.py new file mode 100644 index 000000000..489023407 --- /dev/null +++ b/roles/os_zabbix/library/zbx_user.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +''' +ansible module for zabbix users +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Zabbix user ansible module +# +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True + +def get_usergroups(zapi, usergroups): +    ''' Get usergroups +    ''' +    ugroups = [] +    for ugr in usergroups: +        content = zapi.get_content('usergroup', +                                   'get', +                                   {'search': {'name': ugr}, +                                    #'selectUsers': 'userid', +                                    #'getRights': 'extend' +                                   }) +        if content['result']: +            ugroups.append({'usrgrpid': content['result'][0]['usrgrpid']}) + +    return ugroups + +def main(): +    ''' +    ansible zabbix module for users +    ''' + +    ##def user(self, name, state='present', params=None): + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            alias=dict(default=None, type='str'), +            passwd=dict(default=None, type='str'), +            usergroups=dict(default=None, type='list'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    password = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + +    zbc = ZabbixConnection(module.params['server'], user, password, module.params['debug']) +    zapi = ZabbixAPI(zbc) + +    ## before we can create a user media and users with media types we need media +    zbx_class_name = 'user' +    idname = "userid" +    alias = module.params['alias'] +    state = module.params['state'] + +    content = zapi.get_content(zbx_class_name, +                               'get', +                               {'output': 'extend', +                                'search': {'alias': alias}, +                                "selectUsrgrps": 'usergrpid', +                               }) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") + +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'alias': alias, +                  'passwd': module.params['passwd'], +                  'usrgrps': get_usergroups(zapi, module.params['usergroups']), +                 } + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): +            if key == 'passwd': +                differences[key] = value + +            elif zab_results[key] != value and zab_results[key] != str(value): +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=zab_results, state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbx_usergroup.py b/roles/os_zabbix/library/zbx_usergroup.py new file mode 100644 index 000000000..ede4c9df1 --- /dev/null +++ b/roles/os_zabbix/library/zbx_usergroup.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +''' +zabbix ansible module for usergroups +''' +# vim: expandtab:tabstop=4:shiftwidth=4 +# +#   Zabbix usergroup ansible module +# +# +#   Copyright 2015 Red Hat Inc. +# +#   Licensed under the Apache License, Version 2.0 (the "License"); +#   you may not use this file except in compliance with the License. +#   You may obtain a copy of the License at +# +#       http://www.apache.org/licenses/LICENSE-2.0 +# +#   Unless required by applicable law or agreed to in writing, software +#   distributed under the License is distributed on an "AS IS" BASIS, +#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +#   See the License for the specific language governing permissions and +#   limitations under the License. +# + +# This is in place because each module looks similar to each other. +# These need duplicate code as their behavior is very similar +# but different for each zabbix class. +# pylint: disable=duplicate-code + +# pylint: disable=import-error +from openshift_tools.monitoring.zbxapi import ZabbixAPI, ZabbixConnection + +def exists(content, key='result'): +    ''' Check if key exists in content or the size of content[key] > 0 +    ''' +    if not content.has_key(key): +        return False + +    if not content[key]: +        return False + +    return True + +def get_rights(zapi, rights): +    '''Get rights +    ''' +    perms = [] +    for right in rights: +        hstgrp = right.keys()[0] +        perm = right.values()[0] +        content = zapi.get_content('hostgroup', 'get', {'search': {'name': hstgrp}}) +        if content['result']: +            permission = 0 +            if perm == 'ro': +                permission = 2 +            elif perm == 'rw': +                permission = 3 +            perms.append({'id': content['result'][0]['groupid'], +                          'permission': permission}) +    return perms + +def get_userids(zapi, users): +    ''' Get userids from user aliases +    ''' +    userids = [] +    for alias in users: +        content = zapi.get_content('user', 'get', {'search': {'alias': alias}}) +        if content['result']: +            userids.append(content['result'][0]['userid']) + +    return userids + +def main(): +    ''' Ansible module for usergroup +    ''' + +    ##def usergroup(self, name, rights=None, users=None, state='present', params=None): + +    module = AnsibleModule( +        argument_spec=dict( +            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), +            user=dict(default=None, type='str'), +            password=dict(default=None, type='str'), +            name=dict(default=None, type='str'), +            rights=dict(default=[], type='list'), +            users=dict(default=[], type='list'), +            debug=dict(default=False, type='bool'), +            state=dict(default='present', type='str'), +        ), +        #supports_check_mode=True +    ) + +    user = module.params.get('user', os.environ['ZABBIX_USER']) +    passwd = module.params.get('password', os.environ['ZABBIX_PASSWORD']) + +    zapi = ZabbixAPI(ZabbixConnection(module.params['server'], user, passwd, module.params['debug'])) + +    zbx_class_name = 'usergroup' +    idname = "usrgrpid" +    uname = module.params['name'] +    state = module.params['state'] + +    content = zapi.get_content(zbx_class_name, +                               'get', +                               {'search': {'name': uname}, +                                'selectUsers': 'userid', +                               }) +    if state == 'list': +        module.exit_json(changed=False, results=content['result'], state="list") + +    if state == 'absent': +        if not exists(content): +            module.exit_json(changed=False, state="absent") + +        content = zapi.get_content(zbx_class_name, 'delete', [content['result'][0][idname]]) +        module.exit_json(changed=True, results=content['result'], state="absent") + +    if state == 'present': +        params = {'name': uname, +                  'rights': get_rights(zapi, module.params['rights']), +                  'userids': get_userids(zapi, module.params['users']), +                 } + +        if not exists(content): +            # if we didn't find it, create it +            content = zapi.get_content(zbx_class_name, 'create', params) +            module.exit_json(changed=True, results=content['result'], state='present') +        # already exists, we need to update it +        # let's compare properties +        differences = {} +        zab_results = content['result'][0] +        for key, value in params.items(): +            if key == 'rights': +                differences['rights'] = value + +            elif key == 'userids' and zab_results.has_key('users'): +                if zab_results['users'] != value: +                    differences['userids'] = value + +            elif zab_results[key] != value and zab_results[key] != str(value): +                differences[key] = value + +        if not differences: +            module.exit_json(changed=False, results=zab_results, state="present") + +        # We have differences and need to update +        differences[idname] = zab_results[idname] +        content = zapi.get_content(zbx_class_name, 'update', differences) +        module.exit_json(changed=True, results=content['result'], state="present") + +    module.exit_json(failed=True, +                     changed=False, +                     results='Unknown state passed. %s' % state, +                     state="unknown") + +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled +# import module snippets.  This are required +from ansible.module_utils.basic import * + +main() diff --git a/roles/os_zabbix/library/zbxapi.py b/roles/os_zabbix/library/zbxapi.py deleted file mode 100755 index 48f294938..000000000 --- a/roles/os_zabbix/library/zbxapi.py +++ /dev/null @@ -1,382 +0,0 @@ -#!/usr/bin/env python -# vim: expandtab:tabstop=4:shiftwidth=4 -''' -   ZabbixAPI ansible module -''' - -#   Copyright 2015 Red Hat Inc. -# -#   Licensed under the Apache License, Version 2.0 (the "License"); -#   you may not use this file except in compliance with the License. -#   You may obtain a copy of the License at -# -#       http://www.apache.org/licenses/LICENSE-2.0 -# -#   Unless required by applicable law or agreed to in writing, software -#   distributed under the License is distributed on an "AS IS" BASIS, -#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -#   See the License for the specific language governing permissions and -#   limitations under the License. -# -#  Purpose: An ansible module to communicate with zabbix. -# - -# pylint: disable=line-too-long -# Disabling line length for readability - -import json -import httplib2 -import sys -import os -import re -import copy - -class ZabbixAPIError(Exception): -    ''' -        ZabbixAPIError -        Exists to propagate errors up from the api -    ''' -    pass - -class ZabbixAPI(object): -    ''' -        ZabbixAPI class -    ''' -    classes = { -        'Action': ['create', 'delete', 'get', 'update'], -        'Alert': ['get'], -        'Application': ['create', 'delete', 'get', 'massadd', 'update'], -        'Configuration': ['export', 'import'], -        'Dcheck': ['get'], -        'Dhost': ['get'], -        'Drule': ['copy', 'create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Dservice': ['get'], -        'Event': ['acknowledge', 'get'], -        'Graph': ['create', 'delete', 'get', 'update'], -        'Graphitem': ['get'], -        'Graphprototype': ['create', 'delete', 'get', 'update'], -        'History': ['get'], -        'Hostgroup': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'], -        'Hostinterface': ['create', 'delete', 'get', 'massadd', 'massremove', 'replacehostinterfaces', 'update'], -        'Host': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'], -        'Hostprototype': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Httptest': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Iconmap': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Image': ['create', 'delete', 'get', 'update'], -        'Item': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Itemprototype': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Maintenance': ['create', 'delete', 'get', 'update'], -        'Map': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Mediatype': ['create', 'delete', 'get', 'update'], -        'Proxy': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Screen': ['create', 'delete', 'get', 'update'], -        'Screenitem': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'update', 'updatebyposition'], -        'Script': ['create', 'delete', 'execute', 'get', 'getscriptsbyhosts', 'update'], -        'Service': ['adddependencies', 'addtimes', 'create', 'delete', 'deletedependencies', 'deletetimes', 'get', 'getsla', 'isreadable', 'iswritable', 'update'], -        'Template': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massremove', 'massupdate', 'update'], -        'Templatescreen': ['copy', 'create', 'delete', 'get', 'isreadable', 'iswritable', 'update'], -        'Templatescreenitem': ['get'], -        'Trigger': ['adddependencies', 'create', 'delete', 'deletedependencies', 'get', 'isreadable', 'iswritable', 'update'], -        'Triggerprototype': ['create', 'delete', 'get', 'update'], -        'User': ['addmedia', 'create', 'delete', 'deletemedia', 'get', 'isreadable', 'iswritable', 'login', 'logout', 'update', 'updatemedia', 'updateprofile'], -        'Usergroup': ['create', 'delete', 'get', 'isreadable', 'iswritable', 'massadd', 'massupdate', 'update'], -        'Usermacro': ['create', 'createglobal', 'delete', 'deleteglobal', 'get', 'update', 'updateglobal'], -        'Usermedia': ['get'], -    } - -    def __init__(self, data=None): -        if not data: -            data = {} -        self.server = data.get('server', None) -        self.username = data.get('user', None) -        self.password = data.get('password', None) -        if any([value == None for value in [self.server, self.username, self.password]]): -            print 'Please specify zabbix server url, username, and password.' -            sys.exit(1) - -        self.verbose = data.get('verbose', False) -        self.use_ssl = data.has_key('use_ssl') -        self.auth = None - -        for cname, _ in self.classes.items(): -            setattr(self, cname.lower(), getattr(self, cname)(self)) - -        # pylint: disable=no-member -        # This method does not exist until the metaprogramming executed -        results = self.user.login(user=self.username, password=self.password) - -        if results[0]['status'] == '200': -            if results[1].has_key('result'): -                self.auth = results[1]['result'] -            elif results[1].has_key('error'): -                print "Unable to authenticate with zabbix server. {0} ".format(results[1]['error']) -                sys.exit(1) -        else: -            print "Error in call to zabbix. Http status: {0}.".format(results[0]['status']) -            sys.exit(1) - -    def perform(self, method, rpc_params): -        ''' -        This method calls your zabbix server. - -        It requires the following parameters in order for a proper request to be processed: -            jsonrpc - the version of the JSON-RPC protocol used by the API; -                      the Zabbix API implements JSON-RPC version 2.0; -            method - the API method being called; -            rpc_params - parameters that will be passed to the API method; -            id - an arbitrary identifier of the request; -            auth - a user authentication token; since we don't have one yet, it's set to null. -        ''' -        http_method = "POST" -        jsonrpc = "2.0" -        rid = 1 - -        http = None -        if self.use_ssl: -            http = httplib2.Http() -        else: -            http = httplib2.Http(disable_ssl_certificate_validation=True,) - -        headers = {} -        headers["Content-type"] = "application/json" - -        body = { -            "jsonrpc": jsonrpc, -            "method":  method, -            "params":  rpc_params.get('params', {}), -            "id":      rid, -            'auth':    self.auth, -        } - -        if method in ['user.login', 'api.version']: -            del body['auth'] - -        body = json.dumps(body) - -        if self.verbose: -            print body -            print method -            print headers -            httplib2.debuglevel = 1 - -        response, content = http.request(self.server, http_method, body, headers) - -        if response['status'] not in ['200', '201']: -            raise ZabbixAPIError('Error calling zabbix.  Zabbix returned %s' % response['status']) - -        if self.verbose: -            print response -            print content - -        try: -            content = json.loads(content) -        except ValueError as err: -            content = {"error": err.message} - -        return response, content - -    @staticmethod -    def meta(cname, method_names): -        ''' -        This bit of metaprogramming is where the ZabbixAPI subclasses are created. -        For each of ZabbixAPI.classes we create a class from the key and methods -        from the ZabbixAPI.classes values.  We pass a reference to ZabbixAPI class -        to each subclass in order for each to be able to call the perform method. -        ''' -        def meta_method(_class, method_name): -            ''' -            This meta method allows a class to add methods to it. -            ''' -            # This template method is a stub method for each of the subclass -            # methods. -            def template_method(self, params=None, **rpc_params): -                ''' -                This template method is a stub method for each of the subclass methods. -                ''' -                if params: -                    rpc_params['params'] = params -                else: -                    rpc_params['params'] = copy.deepcopy(rpc_params) - -                return self.parent.perform(cname.lower()+"."+method_name, rpc_params) - -            template_method.__doc__ = \ -              "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s/%s" % \ -              (cname.lower(), method_name) -            template_method.__name__ = method_name -            # this is where the template method is placed inside of the subclass -            # e.g. setattr(User, "create", stub_method) -            setattr(_class, template_method.__name__, template_method) - -        # This class call instantiates a subclass. e.g. User -        _class = type(cname, -                      (object,), -                      {'__doc__': \ -                      "https://www.zabbix.com/documentation/2.4/manual/api/reference/%s" % cname.lower()}) -        def __init__(self, parent): -            ''' -            This init method gets placed inside of the _class -            to allow it to be instantiated.  A reference to the parent class(ZabbixAPI) -            is passed in to allow each class access to the perform method. -            ''' -            self.parent = parent - -        # This attaches the init to the subclass. e.g. Create -        setattr(_class, __init__.__name__, __init__) -        # For each of our ZabbixAPI.classes dict values -        # Create a method and attach it to our subclass. -        # e.g.  'User': ['delete', 'get', 'updatemedia', 'updateprofile', -        #                'update', 'iswritable', 'logout', 'addmedia', 'create', -        #                'login', 'deletemedia', 'isreadable'], -        # User.delete -        # User.get -        for method_name in method_names: -            meta_method(_class, method_name) -        # Return our subclass with all methods attached -        return _class - -# Attach all ZabbixAPI.classes to ZabbixAPI class through metaprogramming -for _class_name, _method_names in ZabbixAPI.classes.items(): -    setattr(ZabbixAPI, _class_name, ZabbixAPI.meta(_class_name, _method_names)) - -def exists(content, key='result'): -    ''' Check if key exists in content or the size of content[key] > 0 -    ''' -    if not content.has_key(key): -        return False - -    if not content[key]: -        return False - -    return True - -def diff_content(from_zabbix, from_user, ignore=None): -    ''' Compare passed in object to results returned from zabbix -    ''' -    terms = ['search', 'output', 'groups', 'select', 'expand', 'filter'] -    if ignore: -        terms.extend(ignore) -    regex = '(' + '|'.join(terms) + ')' -    retval = {} -    for key, value in from_user.items(): -        if re.findall(regex, key): -            continue - -        # special case here for templates.  You query templates and -        # the zabbix api returns parentTemplates.  These will obviously fail. -        # So when its templates compare against parentTemplates. -        if key == 'templates' and from_zabbix.has_key('parentTemplates'): -            if from_zabbix['parentTemplates'] != value: -                retval[key] = value - -        elif from_zabbix[key] != str(value): -            retval[key] = str(value) - -    return retval - -def main(): -    ''' -    This main method runs the ZabbixAPI Ansible Module -    ''' - -    module = AnsibleModule( -        argument_spec=dict( -            server=dict(default='https://localhost/zabbix/api_jsonrpc.php', type='str'), -            user=dict(default=None, type='str'), -            password=dict(default=None, type='str'), -            zbx_class=dict(choices=ZabbixAPI.classes.keys()), -            params=dict(), -            debug=dict(default=False, type='bool'), -            state=dict(default='present', type='str'), -            ignore=dict(default=None, type='list'), -        ), -        #supports_check_mode=True -    ) - -    user = module.params.get('user', None) -    if not user: -        user = os.environ['ZABBIX_USER'] - -    passwd = module.params.get('password', None) -    if not passwd: -        passwd = os.environ['ZABBIX_PASSWORD'] - - - -    api_data = { -        'user': user, -        'password': passwd, -        'server': module.params['server'], -        'verbose': module.params['debug'] -    } - -    if not user or not passwd or not module.params['server']: -        module.fail_json(msg='Please specify the user, password, and the zabbix server.') - -    zapi = ZabbixAPI(api_data) - -    ignore = module.params['ignore'] -    zbx_class = module.params.get('zbx_class') -    rpc_params = module.params.get('params', {}) -    state = module.params.get('state') - - -    # Get the instance we are trying to call -    zbx_class_inst = zapi.__getattribute__(zbx_class.lower()) - -    # perform get -    # Get the instance's method we are trying to call - -    zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['get'] -    _, content = zbx_action_method(zbx_class_inst, rpc_params) - -    if state == 'list': -        module.exit_json(changed=False, results=content['result'], state="list") - -    if state == 'absent': -        if not exists(content): -            module.exit_json(changed=False, state="absent") -        # If we are coming from a query, we need to pass in the correct rpc_params for delete. -        # specifically the zabbix class name + 'id' -        # if rpc_params is a list then we need to pass it. (list of ids to delete) -        idname = zbx_class.lower() + "id" -        if not isinstance(rpc_params, list) and content['result'][0].has_key(idname): -            rpc_params = [content['result'][0][idname]] - -        zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['delete'] -        _, content = zbx_action_method(zbx_class_inst, rpc_params) -        module.exit_json(changed=True, results=content['result'], state="absent") - -    if state == 'present': -    # It's not there, create it! -        if not exists(content): -            zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['create'] -            _, content = zbx_action_method(zbx_class_inst, rpc_params) -            module.exit_json(changed=True, results=content['result'], state='present') - -    # It's there and the same, do nothing! -        diff_params = diff_content(content['result'][0], rpc_params, ignore) -        if not diff_params: -            module.exit_json(changed=False, results=content['result'], state="present") - -        # Add the id to update with -        idname = zbx_class.lower() + "id" -        diff_params[idname] = content['result'][0][idname] - - -        ## It's there and not the same, update it! -        zbx_action_method = zapi.__getattribute__(zbx_class.capitalize()).__dict__['update'] -        _, content = zbx_action_method(zbx_class_inst, diff_params) -        module.exit_json(changed=True, results=content, state="present") - -    module.exit_json(failed=True, -                     changed=False, -                     results='Unknown state passed. %s' % state, -                     state="unknown") - -# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import, locally-disabled -# import module snippets.  This are required -from ansible.module_utils.basic import * - -main() -  | 
