diff options
Diffstat (limited to 'roles')
23 files changed, 1353 insertions, 393 deletions
| diff --git a/roles/etcd/tasks/main.yml b/roles/etcd/tasks/main.yml index 79a91dfde..27bfb7de9 100644 --- a/roles/etcd/tasks/main.yml +++ b/roles/etcd/tasks/main.yml @@ -1,6 +1,6 @@  ---  - name: Install etcd -  yum: pkg=etcd state=present +  yum: pkg=etcd-2.* state=present  - name: Validate permissions on the config dir    file: 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..d592dc306 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 < 3 ) | ternary(15, (num_nodes|int * 5)) }} +  - name: ensure td-agent is running    service:      name: 'td-agent' diff --git a/roles/openshift_common/README.md b/roles/openshift_common/README.md index eb4ef26e8..1eb04626f 100644 --- a/roles/openshift_common/README.md +++ b/roles/openshift_common/README.md @@ -1,7 +1,7 @@ -OpenShift Common -================ +OpenShift/Atomic Enterprise Common +=================================== -OpenShift common installation and configuration tasks. +OpenShift/Atomic Enterprise common installation and configuration tasks.  Requirements  ------------ 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/openshift_manage_node/tasks/main.yml b/roles/openshift_manage_node/tasks/main.yml index d17f3f532..74e702248 100644 --- a/roles/openshift_manage_node/tasks/main.yml +++ b/roles/openshift_manage_node/tasks/main.yml @@ -16,3 +16,10 @@    command: >      {{ openshift.common.admin_binary }} manage-node {{ item }} --schedulable=true    with_items: openshift_scheduleable_nodes + +- name: Label nodes +  command: > +    {{ openshift.common.client_binary }} label --overwrite node {{ item.openshift.common.hostname }} {{ item.openshift.node.labels | oo_combine_dict  }} +  with_items: +    -  "{{ openshift_node_vars }}" +  when: "'labels' in item.openshift.node and item.openshift.node.labels != {}" diff --git a/roles/openshift_master/tasks/main.yml b/roles/openshift_master/tasks/main.yml index 8d6c02e7f..3ee21b902 100644 --- a/roles/openshift_master/tasks/main.yml +++ b/roles/openshift_master/tasks/main.yml @@ -54,6 +54,10 @@        sdn_cluster_network_cidr: "{{ osm_cluster_network_cidr | default(None) }}"        sdn_host_subnet_length: "{{ osm_host_subnet_length | default(None) }}"        default_subdomain: "{{ osm_default_subdomain | default(None) }}" +      custom_cors_origins: "{{ osm_custom_cors_origins | default(None) }}" +      default_node_selector: "{{ osm_default_node_selector | default(None) }}" +      api_server_args: "{{ osm_api_server_args | default(None) }}" +      controller_args: "{{ osm_controller_args | default(None) }}"  # TODO: These values need to be configurable  - name: Set dns OpenShift facts diff --git a/roles/openshift_master/templates/master.yaml.v1.j2 b/roles/openshift_master/templates/master.yaml.v1.j2 index 01c0ea7e4..44567aa22 100644 --- a/roles/openshift_master/templates/master.yaml.v1.j2 +++ b/roles/openshift_master/templates/master.yaml.v1.j2 @@ -2,6 +2,9 @@ apiLevels:  - v1beta3  - v1  apiVersion: v1 +{% if api_server_args is defined and api_server_args %} +apiServerArguments: {{ api_server_args }} +{% endif %}  assetConfig:    logoutURL: ""    masterPublicURL: {{ openshift.master.public_api_url }} @@ -13,11 +16,16 @@ assetConfig:      keyFile: master.server.key      maxRequestsInFlight: 0      requestTimeoutSeconds: 0 +{% if controller_args is defined and controller_args %} +controllerArguments: {{ controller_args }} +{% endif %}  corsAllowedOrigins: -{# TODO: add support for user specified corsAllowedOrigins #}  {% for origin in ['127.0.0.1', 'localhost', openshift.common.hostname, openshift.common.ip, openshift.common.public_hostname, openshift.common.public_ip] %}    - {{ origin }}  {% endfor %} +{% for custom_origin in openshift.master.custom_cors_origins | default("") %} +  - {{ custom_origin }} +{% endfor %}  {% if openshift.master.embedded_dns | bool %}  dnsConfig:    bindAddress: {{ openshift.master.bind_addr }}:{{ openshift.master.dns_port }} @@ -93,7 +101,7 @@ policyConfig:    openshiftSharedResourcesNamespace: openshift  {# TODO: Allow users to override projectConfig items #}  projectConfig: -  defaultNodeSelector: "" +  defaultNodeSelector: "{{ openshift.master.default_node_selector | default("") }}"    projectRequestMessage: ""    projectRequestTemplate: ""    securityAllocator: diff --git a/roles/openshift_master/templates/v1_partials/oauthConfig.j2 b/roles/openshift_master/templates/v1_partials/oauthConfig.j2 index f6fd88c65..4ca644876 100644 --- a/roles/openshift_master/templates/v1_partials/oauthConfig.j2 +++ b/roles/openshift_master/templates/v1_partials/oauthConfig.j2 @@ -10,6 +10,20 @@        {{ key }}: {{ identity_provider[key] }}"  {% endif %}  {% endfor %} +{% elif identity_provider.kind == 'LDAPPasswordIdentityProvider' %} +      attributes: +{% for attribute_key in identity_provider.attributes %} +        {{ attribute_key }}: +{% for attribute_value in identity_provider.attributes[attribute_key] %} +        - {{ attribute_value }} +{% endfor %} +{% endfor %} +{% for key in ('bindDN', 'bindPassword', 'ca') %} +      {{ key }}: "{{ identity_provider[key] }}" +{% endfor %} +{% for key in ('insecure', 'url') %} +      {{ key }}: {{ identity_provider[key] }} +{% endfor %}  {% elif identity_provider.kind == 'RequestHeaderIdentityProvider' %}        headers: {{ identity_provider.headers }}  {% if 'clientCA' in identity_provider %} diff --git a/roles/openshift_node/README.md b/roles/openshift_node/README.md index 5edb3b8dd..300e6b495 100644 --- a/roles/openshift_node/README.md +++ b/roles/openshift_node/README.md @@ -34,6 +34,18 @@ openshift_common  Example Playbook  ---------------- +Notes +----- + +Currently we support re-labeling nodes but we don't re-schedule running pods nor remove existing labels. That means you will have to trigger the re-schedulling manually. To re-schedule your pods, just follow the steps below: + +``` +oadm manage-node --schedulable=false ${NODE} +oadm manage-node --evacuate ${NODE} +oadm manage-node --schedulable=true ${NODE} +```` + +  TODO  License diff --git a/roles/openshift_node/tasks/main.yml b/roles/openshift_node/tasks/main.yml index e84e74b40..adffca252 100644 --- a/roles/openshift_node/tasks/main.yml +++ b/roles/openshift_node/tasks/main.yml @@ -6,6 +6,9 @@  - fail:      msg: This role requres that osn_cluster_dns_ip is set    when: osn_cluster_dns_ip is not defined or not osn_cluster_dns_ip +- fail: +    msg: "SELinux is disabled, This deployment type requires that SELinux is enabled." +  when: (not ansible_selinux or ansible_selinux.status != 'enabled') and deployment_type in ['enterprise', 'online']  - name: Install OpenShift Node package    yum: pkg=openshift-node state=present @@ -33,6 +36,7 @@        registry_url: "{{ oreg_url | default(none) }}"        debug_level: "{{ openshift_node_debug_level | default(openshift.common.debug_level) }}"        portal_net: "{{ openshift_master_portal_net | default(None) }}" +      kubelet_args: "{{ openshift_node_kubelet_args | default(None) }}"  # TODO: add the validate parameter when there is a validation command to run  - name: Create the Node config @@ -63,11 +67,13 @@    lineinfile:      dest: /etc/sysconfig/docker      regexp: '^OPTIONS=.*' -    line: "OPTIONS='--insecure-registry={{ openshift.node.portal_net }} --selinux-enabled'" +    line: "OPTIONS='--insecure-registry={{ openshift.node.portal_net }} \ +{% if ansible_selinux and ansible_selinux.status == '''enabled''' %}--selinux-enabled{% endif %}'"    when: docker_check.stat.isreg  - name: Allow NFS access for VMs    seboolean: name=virt_use_nfs state=yes persistent=yes +  when: ansible_selinux and ansible_selinux.status == "enabled"  - name: Start and enable openshift-node    service: name=openshift-node enabled=yes state=started diff --git a/roles/openshift_node/templates/node.yaml.v1.j2 b/roles/openshift_node/templates/node.yaml.v1.j2 index 7778a2a61..e6f75a4c0 100644 --- a/roles/openshift_node/templates/node.yaml.v1.j2 +++ b/roles/openshift_node/templates/node.yaml.v1.j2 @@ -8,6 +8,9 @@ imageConfig:    format: {{ openshift.node.registry_url }}    latest: false  kind: NodeConfig +{% if openshift.common.kubelet_args is defined and openshift.common.kubelet_args %} +kubeletArguments: {{ kubelet_args }} +{% endif %}  masterKubeConfig: system:node:{{ openshift.common.hostname }}.kubeconfig  networkPluginName: {{ openshift.common.sdn_network_plugin_name }}  nodeName: {{ openshift.common.hostname }} 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() - | 
