metron-deployment/ansible/extra_modules/ambari_service_state.py (282 lines of code) (raw):

#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. # DOCUMENTATION = ''' --- module: ambari_service_state version_added: "2.1" author: Apache Metron (https://metron.apache.org) short_description: Start/Stop/Change Service or Component State description: - Start/Stop/Change Service or Component State options: host: description: The hostname for the ambari web server port: description: The port for the ambari web server username: description: The username for the ambari web server password: description: The name of the cluster in web server required: yes cluster_name: description: The name of the cluster in ambari required: yes service_name: description: The name of the service to alter required: no component_name: description: The name of the component to alter required: no component_host: description: The host running the targeted component. Required when component_name is used. required: no state: description: The desired service/component state. wait_for_complete: description: Whether to wait for the request to complete before returning. Default is False. required: no requirements: [ 'requests'] ''' EXAMPLES = ''' # must use full relative path to any files in stored in roles/role_name/files/ - name: Create a new ambari cluster ambari_cluster_state: host: localhost port: 8080 username: admin password: admin cluster_name: my_cluster cluster_state: present blueprint_var: roles/my_role/files/blueprint.yml blueprint_name: hadoop wait_for_complete: True - name: Start the ambari cluster ambari_cluster_state: host: localhost port: 8080 username: admin password: admin cluster_name: my_cluster cluster_state: started wait_for_complete: True - name: Stop the ambari cluster ambari_cluster_state: host: localhost port: 8080 username: admin password: admin cluster_name: my_cluster cluster_state: stopped wait_for_complete: True - name: Delete the ambari cluster ambari_cluster_state: host: localhost port: 8080 username: admin password: admin cluster_name: my_cluster cluster_state: absent ''' RETURN = ''' results: description: The content of the requests object returned from the RESTful call returned: success type: string ''' __author__ = 'apachemetron' import json try: import requests except ImportError: REQUESTS_FOUND = False else: REQUESTS_FOUND = True def main(): argument_spec = dict( host=dict(type='str', default=None, required=True), port=dict(type='int', default=None, required=True), username=dict(type='str', default=None, required=True), password=dict(type='str', default=None, required=True), cluster_name=dict(type='str', default=None, required=True), state=dict(type='str', default=None, required=True, choices=['started', 'stopped', 'deleted']), service_name=dict(type='str', required=False), component_name=dict(type='str', default=None, required=False), component_host=dict(type='str', default=None, required=False), wait_for_complete=dict(default=False, required=False, type='bool'), ) required_together = ['component_name', 'component_host'] module = AnsibleModule( argument_spec=argument_spec, required_together=required_together ) if not REQUESTS_FOUND: module.fail_json( msg='requests library is required for this module') p = module.params host = p.get('host') port = p.get('port') username = p.get('username') password = p.get('password') cluster_name = p.get('cluster_name') state = p.get('state') service_name = p.get('service_name') component_name = p.get('component_name') component_host = p.get('component_host') wait_for_complete = p.get('wait_for_complete') component_mode = False ambari_url = 'http://{0}:{1}'.format(host, port) if component_name: component_mode = True try: if not cluster_exists(ambari_url, username, password, cluster_name): module.fail_json(msg="Cluster name {0} does not exist".format(cluster_name)) if state in ['started', 'stopped', 'installed']: desired_state = '' if state == 'started': desired_state = 'STARTED' elif state in ['stopped','installed']: desired_state = 'INSTALLED' if component_mode: if desired_state == 'INSTALLED': if(can_add_component(ambari_url, username, password, cluster_name, component_name, component_host)): add_component_to_host(ambari_url, username, password, cluster_name, component_name, component_host) request = set_component_state(ambari_url, username, password, cluster_name, component_name, component_host, desired_state) else: request = set_service_state(ambari_url,username,password,cluster_name,service_name, desired_state) if wait_for_complete: try: request_id = json.loads(request.content)['Requests']['id'] except ValueError: module.exit_json(changed=True, results=request.content) status = wait_for_request_complete(ambari_url, username, password, cluster_name, request_id, 2) if status != 'COMPLETED': module.fail_json(msg="Request failed with status {0}".format(status)) module.exit_json(changed=True, results=request.content) elif state == 'deleted': if component_mode: request = delete_component(ambari_url, username, password, cluster_name, component_name, component_host) else: request = delete_service(ambari_url,username,password,cluster_name,service_name) module.exit_json(changed=True, results=request.content) except requests.ConnectionError, e: module.fail_json(msg="Could not connect to Ambari client: " + str(e.message)) except Exception, e: module.fail_json(msg="Ambari client exception occurred: " + str(e.message)) def get_clusters(ambari_url, user, password): r = get(ambari_url, user, password, '/api/v1/clusters') if r.status_code != 200: msg = 'Could not get cluster list: request code {0}, \ request message {1}'.format(r.status_code, r.content) raise Exception(msg) clusters = json.loads(r.content) return clusters['items'] def cluster_exists(ambari_url, user, password, cluster_name): clusters = get_clusters(ambari_url, user, password) return cluster_name in [item['Clusters']['cluster_name'] for item in clusters] def get_request_status(ambari_url, user, password, cluster_name, request_id): path = '/api/v1/clusters/{0}/requests/{1}'.format(cluster_name, request_id) r = get(ambari_url, user, password, path) if r.status_code != 200: msg = 'Could not get cluster request status: request code {0}, \ request message {1}'.format(r.status_code, r.content) raise Exception(msg) service = json.loads(r.content) return service['Requests']['request_status'] def wait_for_request_complete(ambari_url, user, password, cluster_name, request_id, sleep_time): while True: status = get_request_status(ambari_url, user, password, cluster_name, request_id) if status == 'COMPLETED': return status elif status in ['FAILED', 'TIMEDOUT', 'ABORTED', 'SKIPPED_FAILED']: return status else: time.sleep(sleep_time) def set_service_state(ambari_url, user, password, cluster_name, service_name, desired_state): path = '/api/v1/clusters/{0}/services/{1}'.format(cluster_name,service_name) request = {"RequestInfo": {"context": "Setting {0} to {1} via REST".format(service_name,desired_state)}, "Body": {"ServiceInfo": {"state": "{0}".format(desired_state)}}} payload = json.dumps(request) r = put(ambari_url, user, password, path, payload) if r.status_code not in [202, 200]: msg = 'Could not set service state: request code {0}, \ request message {1}'.format(r.status_code, r.content) raise Exception(msg) return r def set_component_state(ambari_url, user, password, cluster_name, component_name, component_host, desired_state): path = '/api/v1/clusters/{0}/hosts/{1}/host_components/{2}'.format(cluster_name,component_host,component_name) request = {"RequestInfo": {"context": "Setting {0} to {1} via REST".format(component_name,desired_state)}, "Body": {"HostRoles": {"state": "{0}".format(desired_state)}}} payload = json.dumps(request) r = put(ambari_url, user, password, path, payload) if r.status_code not in [202, 200]: msg = 'Could not set component state: request code {0}, \ request message {1}'.format(r.status_code, r.content) raise Exception(msg) return r def delete_component(ambari_url, user, password, cluster_name, component_name, component_host): enable_maint_mode(ambari_url, user, password, cluster_name, component_name, component_host) path = '/api/v1/clusters/{0}/hosts/{1}/host_components/{2}'.format(cluster_name,component_host,component_name) r = delete(ambari_url,user,password,path) if r.status_code not in [202, 200]: msg = 'Could not set service state: request code {0}, \ request message {1}'.format(r.status_code, r.content) raise Exception(msg) return r def enable_maint_mode(ambari_url, user, password, cluster_name, component_name, component_host): path = '/api/v1/clusters/{0}/hosts/{1}/host_components/{2}'.format(cluster_name,component_host,component_name) request = {"RequestInfo":{"context":"Turn On Maintenance Mode for {0}".format(component_name)}, "Body":{"HostRoles":{"maintenance_state":"ON"}}} payload = json.dumps(request) r = put(ambari_url, user, password, path, payload) if r.status_code not in [202, 200]: msg = 'Could not set maintenance mode: request code {0}, \ request message {1}'.format(r.status_code, r.content) raise Exception(msg) return r def delete_service(ambari_url, user, password, cluster_name, service_name): path = '/api/v1/clusters/{0}/services/{1}'.format(cluster_name,service_name) r = delete(ambari_url,user,password,path) if r.status_code not in [202, 200]: msg = 'Could not delete service: request code {0}, \ request message {1}'.format(r.status_code, r.content) raise Exception(msg) return r def add_component_to_host(ambari_url, user, password, cluster_name, component_name, component_host): path = '/api/v1/clusters/{0}/hosts/{1}/host_components/{2}'.format(cluster_name,component_host,component_name) r = post(ambari_url, user, password, path,'') if r.status_code not in [202,201,200]: msg = 'Could not add {0} to host {1}: request code {2}, \ request message {3}'.format(component_name,component_host,r.status_code, r.content) raise Exception(msg) return r def can_add_component(ambari_url, user, password, cluster_name, component_name, component_host): path = '/api/v1/clusters/{0}/hosts/{1}/host_components/{2}'.format(cluster_name,component_host,component_name) r = get(ambari_url, user, password, path) return r.status_code == 404 def get(ambari_url, user, password, path): r = requests.get(ambari_url + path, auth=(user, password)) return r def put(ambari_url, user, password, path, data): headers = {'X-Requested-By': 'ambari'} r = requests.put(ambari_url + path, data=data, auth=(user, password), headers=headers) return r def post(ambari_url, user, password, path, data): headers = {'X-Requested-By': 'ambari'} r = requests.post(ambari_url + path, data=data, auth=(user, password), headers=headers) return r def delete(ambari_url, user, password, path): headers = {'X-Requested-By': 'ambari'} r = requests.delete(ambari_url + path, auth=(user, password), headers=headers) return r from ansible.module_utils.basic import * if __name__ == '__main__': main()