How to Create Custom Ansible Wildfly Module – Part 4
Introduction
Hi there! Welcome to the last part for this long journey. Oops, I mean long posts regarding Ansible Wildfly Module. The reason why I posted such a multiple how-to is to reach the ultimate goal, which is the deployment. So yeah, it is time to set up the deployment.
Deployment
Application server, in this case Wildfly, almost has no meaning without deploying your WAR or EAR into it. Because deployment means making your software system available for use. Also deployment involves several activities which sometimes inter related between them. Therefore, imagine we can make all of those things automatically. It will make your life easier, won’t it?
Use Case
I had a feeling that you already knew what are the use cases. Well, I know you were right. The use cases are only deploy and undeploy artifact (WAR or EAR) into and out of Wildfly.
Cheat Sheet
This tutorial is running on JDK 8, Wildfly 10, Ansible 2.1.2 and python 2.7. Also, here are JBoss CLI commands to deploy and undeploy built artifact.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# deploy in standalone mode deploy WAR_NAME # deploy in domain mode deploy WAR_NAME --server-groups=GROUP_NAME # force deploy for standalone and domain mode deploy WAR_NAME --force # undeploy in standalone mode undeploy WAR_NAME # undeploy in domain mode undeploy WAR_NAME --server-groups=GROUP_NAME |
But now is a little bit special. The deployment is not only for domain mode, but for standalone mode as well. So let’s start the step by step!
Step by Step
Step 1 – Create Python File
As usual, create a file and give it a name jcli_deploy.py
. Put it into library
folder. Then add hash bang and import statement as well.
1 2 3 4 |
#!/usr/bin/python from ansible.module_utils.basic import * import subprocess |
Step 2 – Create Function to Check Deployment Existence
We have to create function to check whether the artifact has already deployed or not. Besides the need of Ansible changed status, this function will determine whenever we need to put force flag while executing deployment command.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
def isArtifactAlreadyDeployed(data): cmd = data['jboss_home'] + '/bin/jboss-cli.sh' cli = "deployment-info --name=%s" % (data['artifact']) controller = "--controller=%s:%s" % (data['controller_host'],data['controller_port']) user = "-u=%s" % (data['user']) password = "-p=%s" % (data['password']) p = subprocess.Popen(["sh", cmd, "-c", cli, controller, user, password], stdout=subprocess.PIPE) result = p.communicate()[0] created = False remoteExists = False result = str(result) if "WFLYCTL0216" in result: created = False else: created = True if "WFLYPRT0053" in result: remoteExists = False else: remoteExists = True return remoteExists, created |
Note:
- We have six dictionary keys, which are
jboss_home
,server_group_name
,controller_host,
controller_port
,user
andpassword
. These keys will be defined in the main method. - Whenever the result contains
WFLYCTL0216
, it is assumed that the deployment has already existed. - Whenever the result contains
WFLYPRT0053
, it is assumed that the remote host cannot be reached.
Step 3 – Create Functions for Deployment
Based on use cases, we will define two functions. The first function is deployment_present
, which will be used to deploy artifact to Wildfly. Another one is deployment_absent
to undeploy artifact from Widlfly.
deployment_present
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
def deployment_present(data): cmd = data['jboss_home'] + '/bin/jboss-cli.sh' controller = "--controller=%s:%s" % (data['controller_host'],data['controller_port']) user = "-u=%s" % (data['user']) password = "-p=%s" % (data['password']) mode = data['server_mode'] exists, created = isArtifactAlreadyDeployed(data) isError = False hasChanged = True meta = {} result = "" if not exists: mesg = "Could not connect http-remoting://%s:%s" % (data['controller_host'],data['controller_port']) meta = {"status": "Error", "response": mesg} isError = True hasChanged = False else: if not created: if mode == 'standalone': cli = "deploy %s/%s" % (data['artifact_dir'],data['artifact']) else: cli = "deploy %s/%s --server-groups=%s" % (data['artifact_dir'],data['artifact'],data['server_group_name']) p = subprocess.Popen(["sh", cmd, "-c", cli, controller, user, password], stdout=subprocess.PIPE) result,err = p.communicate() else: cli = "deploy %s/%s --force" % (data['artifact_dir'],data['artifact']) #same behaviour between standalone and domain p = subprocess.Popen(["sh", cmd, "-c", cli, controller, user, password], stdout=subprocess.PIPE) result,err = p.communicate() result = str(result) if "WFLYDC0074" in result: meta = {"status" : "Failed to deploy", "response" : result} isError = True else: meta = {"status" : "OK", "response" : result} return isError, hasChanged, meta |
deployment_absent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
ef deployment_absent(data): cmd = data['jboss_home'] + '/bin/jboss-cli.sh' controller = "--controller=%s:%s" % (data['controller_host'],data['controller_port']) user = "-u=%s" % (data['user']) password = "-p=%s" % (data['password']) mode = data['server_mode'] exists, created = isArtifactAlreadyDeployed(data) isError = False hasChanged = True meta = {} if not exists: mesg = "Could not connect http-remoting://%s:%s" % (data['controller_host'],data['controller_port']) meta = {"status": "Error", "response": mesg} isError = True hasChanged = False else: if not created: hasChanged = False resp = "Deployment %s does not exist" % (data['artifact']) meta = {"status" : "OK", "response" : resp} else: if mode == 'standalone': cli = "undeploy %s" % (data['artifact']) else: cli = "undeploy %s --server-groups=%s" % (data['artifact'],data['server_group_name']) p = subprocess.Popen(["sh", cmd, "-c", cli, controller, user, password], stdout=subprocess.PIPE) result,err = p.communicate() result = str(result) if "WFLYDC0074" in result: meta = {"status" : "Failed to undeploy", "response" : result} isError = True else: meta = {"status": "OK", "response": result} return isError, hasChanged, meta |
Note:
- There are four additional field dictionary keys. Those keys are:
- server_group_name: to deploy artifact to all hosts in the same server group. This keys only valid for domain mode.
- server_mode: select the deployment for standalone or domain mode
- artifact_dir: artifact directory
- artifact: artifact name
- Deployment command will return WFLYDC0074 if the deployment fails. Whenever we received that error, we will set Ansible state to error.
Step 4 – Define Main Function
After collecting all keys and state key, we can create the main function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
def main(): fields = { "jboss_home" : {"required": True, "type": "str"}, "server_group_name": { "required": True, "type": "str" }, "artifact": { "required": True, "type": "str" }, "artifact_dir": { "required": True, "type": "str" }, "controller_host": { "required": False, "default": "localhost", "type": "str" }, "controller_port": { "required": False, "default": 9990, "type": "int" }, "server_mode" : { "required": True, "choices": ['standalone', 'domain'], "type": "str" }, "user" : { "required": True, "type": "str" }, "password" : { "required": True, "type": "str" }, "state": { "default": "present", "choices": ['present', 'absent'], "type": 'str' }, } choice_map = { "present": deployment_present, "absent": deployment_absent, } module = AnsibleModule(argument_spec=fields) is_error, has_changed, result = choice_map.get( module.params['state'])(module.params) if not is_error: module.exit_json(changed=has_changed, meta=result) else: module.fail_json(msg="Error creating server", meta=result) if __name__ == '__main__': main() |
Step 5 – play.yml
Update the play.yml
by adding jcli_deploy
module.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
- name: Deploy artifact jcli_deploy: jboss_home: /Users/it-ops/Documents/java_dev/server/wildfly-10.0.0.Final/ server_group_name: group1 server_mode: domain artifact: demo-0.0.1-SNAPSHOT.war artifact_dir: opt/workspace/sample-code/target/ state: present user: wildfly password: password register: hasil - debug: var=hasil |
Execute the playbook and you will see similar result:
Conclusion
After reaching the last post, now we can automate most of the things we need in order to make an automation related to Wildfly. Once we have things automated, especially related with artifact deployment, now we can move to another big thing, which is continuous deployment.
I will bring this topic somewhere in the future. Meanwhile, I have a contributor who like to share his thought about IT world as well. Hope to see him soon. Have a nice day!
Great writeup!
Have you thought of contributing this to the Ansible project?
Would be create to see this as an official core or extras module!
Especially as WildFly is closely tied to RedHat, just like Ansible … you stand a fair chance 🙂
Hi..
Thank you for reading this blog.
Initially, when I wrote this article, I was thinking to contribute to Ansible project. But, as time goes, this idea slightly fades away.
Well, it starts to pop up again. I will use this as a reminder and encouragement 🙂
Once again, thank you for your support.
Hi ,
Thanks for sharing precious information .We are awaiting for continuous deployment article with Ansible .Please let me know if you provide online training for Ansible .
Thank you ,
Kumar .
Hi Kumar
I am glad that my blog did help.
Currently I am writing blog only for sharing what I have learn so far.
I don’t have any online training.
However I put your request into my article queue.
I have done it actually with combination of maven, jenkins and ansible.
It is just a simple deployment, without pipeline.
You can check on my repo https://github.com/ru-rocker/vagrant-ci.