blob: 6d44e8d7e16ae89e2dc42f65698f67cd2e05ee02 [file] [log] [blame]
#!/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()