diff --git a/defaults/main.yml b/defaults/main.yml index 56ac373..b5c2801 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,12 +1,16 @@ --- -deployment_install_initd : true - # Directory structure for app deployment_user : "myUnixUsername" deployment_group : "{{ deployment_user }}" -deployment_work_dir : "/home/{{deployment_user}}/{{deployment_artifact_name}}" -deployment_current_dir : "{{deployment_work_dir}}/current" +deployment_work_dir : "/home/{{ deployment_user }}/{{ deployment_artifact_name }}" +deployment_current_dir : "{{ deployment_work_dir }}/current" + +# What daemon system to use +deployment_install_daemon : "initd" + +# Resolver what services to get the artifacts from +deployment_artifact_resolver : "nexus" # artifact settings deployment_artifact_name : "myApp" @@ -15,17 +19,11 @@ deployment_artifact_version : "LATEST" deployment_artifact_extension : "tgz" deployment_artifact_destination_name : "{{ deployment_artifact_name }}.{{ deployment_artifact_extension }}" -# Used within the init.d script -deployment_exec_cmd : "{{ deployment_current_dir }}/bin/{{ deployment_artifact_name }}" -deployment_exec_arg : "" - -# Used for getting PID ID, it should be a unique value -deployment_grep_name : "{{ deployment_exec_cmd }}" -# How long to probe for an active process upon service start / restart -deployment_timeout_start_sec : 5 -# Pause time to wait for application to bootstrap. Needed for e.g. apps including the new relic agent. -deployment_bootstrap_wait_sec : 0 +# How long to wait before starting to probe for service +deployment_delay_sec : 5 +# How long to wait before failing if an application is not up +deployment_timeout_wait_sec : 45 # HTTP GET request to check that the server is up and running # the content of the result is then checked and compared with _expected_content @@ -37,7 +35,20 @@ deployment_http_check_port : "80" deployment_http_check_domain : "{{ansible_default_ipv4.address}}" deployment_http_check_url : "{{deployment_http_check_protocol}}{{deployment_http_check_domain}}:{{deployment_http_check_port}}{{deployment_http_check_url_suffix}}" +# By default you deploy once and to override you must pass true to force +deployment_force : false +deployment_guard_file : "/var/local/deployment_first_boot_file" + + # nexus settings deployment_nexus_url_base : "" deployment_nexus_url_resolver : "{{ deployment_nexus_url_base }}/nexus/service/local/artifact/maven/resolve?r=releases&g={{ deployment_artifact_organization }}&a={{ deployment_artifact_name }}&e={{ deployment_artifact_extension }}&v={{ deployment_artifact_version }}" -deployment_nexus_url_download : "{{ deployment_nexus_url_base }}/nexus/content/repositories/releases/{{ nexus_artifact_info.json.data.repositoryPath }}" \ No newline at end of file +deployment_nexus_url_download : "{{ deployment_nexus_url_base }}/nexus/content/repositories/releases/{{ nexus_artifact_info.json.data.repositoryPath }}" + + +## *** Initd setting (if using initd) *** +# Used within the init.d script +deployment_exec_cmd : "{{ deployment_current_dir }}/bin/{{ deployment_artifact_name }}" +deployment_exec_arg : "" +# Used for getting PID ID, it should be a unique value +deployment_grep_name : "{{ deployment_exec_cmd }}" \ No newline at end of file diff --git a/handlers/main.yml b/handlers/main.yml index 68aafad..122bc71 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,27 +1,54 @@ --- -- name: "restartApp" - service: + +- name: restart app + debug: + msg="Restart app" + changed_when: true + notify: + - restart app initd + - restart app supervisor + +- name: restart app initd + service: name="{{ deployment_artifact_name }}" state="restarted" enabled="yes" - notify: "wait for application to bootstrap" - when: deployment_install_initd + changed_when: true + notify: wait 4 port + when: deployment_install_daemon == "initd" -- name: "wait for application to bootstrap" - pause: seconds={{ deployment_bootstrap_wait_sec }} +- name: restart app supervisor + supervisorctl: + name="{{ deployment_artifact_name }}" + state="restarted" changed_when: true - notify: "make http request to service" + notify: wait 4 port + when: deployment_install_daemon == "supervisor" -- name: "make http request to service" - uri: url={{deployment_http_check_url}} return_content=yes HEADER_Accept="text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" +- name: wait 4 port + wait_for: + port="{{ deployment_http_check_port }}" + host="{{ ansible_ssh_host | default(inventory_hostname) }}" + delay="{{ deployment_delay_sec }}" + timeout="{{ deployment_timeout_wait_sec }}" + changed_when: true + notify: HTTP request + +- name: HTTP request + uri: + url="{{ deployment_http_check_url }}" + return_content="yes" + HEADER_Accept="text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" + changed_when: true + notify: check payload register: webpage - tags: ["verify-working"] - notify: "fail if http request does not contain expected content" when: deployment_http_check_url_suffix is defined + tags: ["verify-working"] -- name: "fail if http request does not contain expected content" - fail: msg=" {{deployment_artifact_name}} is not happy, {{deployment_http_check_url}} does not return expected content [{{deployment_http_check_expected_content}}]" - when: "'{{deployment_http_check_expected_content}}' not in webpage.content" +- name: check payload + fail: + msg=" {{deployment_artifact_name}} is not happy, {{deployment_http_check_url}} does not return expected content [{{deployment_http_check_expected_content}}]" + when: deployment_http_check_expected_content not in webpage.content tags: ["verify-working"] diff --git a/tasks/init-script.yml b/tasks/daemon/init-script.yml similarity index 68% rename from tasks/init-script.yml rename to tasks/daemon/init-script.yml index 079be16..55fb727 100644 --- a/tasks/init-script.yml +++ b/tasks/daemon/init-script.yml @@ -1,6 +1,6 @@ --- -- name: "init-script | Create application init.d script" +- name: init-script | Create application init.d script initd: name="{{ deployment_artifact_name }}" path="{{ deployment_work_dir }}/{{ deployment_artifact_name }}.sh" @@ -14,14 +14,18 @@ owner="{{ deployment_user }}" group="{{ deployment_user }}" mode=0755 + notify: + - restart app tags: create_initscript -- name: "init-script | Create symlink for init script" +- name: init-script | Create symlink for init script file: - src="{{deployment_work_dir}}/{{deployment_artifact_name}}.sh" - dest="/etc/init.d/{{deployment_artifact_name}}" + src="{{ deployment_work_dir }}/{{ deployment_artifact_name }}.sh" + dest="/etc/init.d/{{ deployment_artifact_name }}" owner="root" group="root" mode="0755" state="link" + notify: + - restart app tags: link_initscript diff --git a/tasks/daemon/main.yml b/tasks/daemon/main.yml new file mode 100644 index 0000000..29a613a --- /dev/null +++ b/tasks/daemon/main.yml @@ -0,0 +1,9 @@ +--- + +- include: init-script.yml + when: deployment_install_daemon == "initd" + tags: ["initd"] + +- include: supervisor.yml + when: deployment_install_daemon == "supervisor" + tags: ["supervisor"] \ No newline at end of file diff --git a/tasks/daemon/supervisor.yml b/tasks/daemon/supervisor.yml new file mode 100644 index 0000000..360de70 --- /dev/null +++ b/tasks/daemon/supervisor.yml @@ -0,0 +1,10 @@ +--- + +- name: daemon | supervisor | Create Service file + template: + src="../../templates/supervisor.j2" + dest="/etc/supervisor/conf.d/{{ deployment_supervisor_name }}.ini.conf" + owner=root + mode=0640 + notify: + - restart app \ No newline at end of file diff --git a/tasks/directories.yml b/tasks/directories.yml deleted file mode 100644 index 831a79f..0000000 --- a/tasks/directories.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- - -- name: config | Get current date - shell: date +"%Y-%m-%d_%H_%M" - register: current_date - -- name: config | set new version directory - set_fact: - deployment_artifact_version_dir : "{{ deployment_work_dir }}/{{ current_date.stdout }}" - -- name : config | Create application base directories - file: - path="{{ item }}" - owner="{{ deployment_user }}" - group="{{ deployment_group }}" - mode="0755" - state="directory" - with_items: - - "{{ deployment_work_dir }}" - - "{{ deployment_artifact_version_dir }}" \ No newline at end of file diff --git a/tasks/directory-structure.yml b/tasks/directory-structure.yml new file mode 100644 index 0000000..063e65e --- /dev/null +++ b/tasks/directory-structure.yml @@ -0,0 +1,36 @@ +--- + +- name: directory structure | Change file owner for all files + file: + path="{{ deployment_artifact_version_dir }}" + owner="{{ deployment_user }}" + group="{{ deployment_group }}" + state="directory" + recurse="yes" + +- name: directory structure | Change file owner for all files + file: + path="{{ deployment_artifact_version_dir }}" + owner="{{ deployment_user }}" + group="{{ deployment_group }}" + state="directory" + recurse="yes" + +- name: directory structure | Create latest symlink + file: + src="{{ deployment_artifact_version_dir }}" + dest="{{ deployment_current_dir }}" + owner="{{ deployment_user }}" + group="{{ deployment_group }}" + mode="0755" + state="link" + notify: + - restart app + +- name: directory structure | Create deployment date file + copy: + content="" + dest="{{ deployment_current_dir }}/{{ current_date.stdout }}.deployment.date" + owner="{{ deployment_user }}" + group="{{ deployment_group }}" + when: download_artifact.changed \ No newline at end of file diff --git a/tasks/download.yml b/tasks/download.yml new file mode 100644 index 0000000..70a2e1b --- /dev/null +++ b/tasks/download.yml @@ -0,0 +1,40 @@ +--- + +- name: download | Get current date + shell: date +"%Y-%m-%d_%H_%M" + changed_when: False + register: current_date + +- name: download | set new version directory + set_fact: + deployment_artifact_version_dir : "{{ deployment_work_dir }}/{{ nexus_artifact_info.json.data.version }}" + +- name: download | Create application base directories + file: + path="{{ item }}" + owner="{{ deployment_user }}" + group="{{ deployment_group }}" + mode="0755" + state="directory" + with_items: + - "{{ deployment_work_dir }}" + - "{{ deployment_artifact_version_dir }}" + +- name: download | nexus | download artifact + get_url: + url="{{ deployment_nexus_url_download }}" + dest="{{ deployment_artifact_version_dir }}/{{ deployment_artifact_destination_name }}" + register: download_artifact + +- name: download | Unzip application (if .tgz) + command: "tar -xf {{deployment_artifact_version_dir}}/{{deployment_artifact_destination_name}} -C {{deployment_artifact_version_dir}} --strip-components 1" + when: deployment_artifact_destination_name.find('.tgz') >= 1 and download_artifact.changed + +- name: download | Unzip application (if .zip) + command: "unzip -o {{deployment_artifact_version_dir}}/{{deployment_artifact_destination_name}} -d {{deployment_artifact_version_dir}}" + when: deployment_artifact_destination_name.find('.zip') >= 1 and download_artifact.changed + +- name: download | Unzip config files (if .jar) (Optional) + command: "unzip {{deployment_artifact_version_dir}}/{{deployment_artifact_destination_name}} -d {{deployment_artifact_version_dir}} *.conf" + when: deployment_artifact_destination_name.find('.jar') >= 1 and download_artifact.changed + ignore_errors: yes diff --git a/tasks/get-artifact.yml b/tasks/get-artifact.yml deleted file mode 100644 index 6496ebb..0000000 --- a/tasks/get-artifact.yml +++ /dev/null @@ -1,20 +0,0 @@ ---- - -- name: "get-artifact | Make the http request to find the latest version on nexus" - uri: - url="{{ deployment_nexus_url_resolver }}" - method=GET - HEADER_Accept="application/json" - HEADER_Authorization="{{nexus_credentials | default(omit) }}" - register: nexus_artifact_info - tags: ["artifact-info"] - -#- name: "show nexus artifact information" -# debug: var=nexus_artifact_info.json.data -# tags: ["artifact-info"] - -- name: "get-artifact | download artifact" - get_url: - url="{{ deployment_nexus_url_download }}" - dest="{{ deployment_artifact_version_dir }}/{{deployment_artifact_destination_name}}" - diff --git a/tasks/main.yml b/tasks/main.yml index da565f8..188d573 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,18 +1,29 @@ --- -- include: directories.yml - tags: ["deploy-directories"] - -- include: init-script.yml - when: deployment_install_initd - tags: ["deploy-initd"] - -- include: get-artifact.yml - tags: ["deploy-artifact"] - -- include: unpack.yml - tags: ["deploy-unpack"] - +- name: main | Check if first boot file exists + stat: + path="{{ deployment_guard_file }}" + register: reg_guard_file + +- include: resolver/main.yml + when: not reg_guard_file.stat.exists or deployment_force + +- include: download.yml + when: not reg_guard_file.stat.exists or deployment_force + tags: ["download"] + +- include: daemon/main.yml + when: not reg_guard_file.stat.exists or deployment_force + tags: ["initd"] + +- include: directory-structure.yml + when: not reg_guard_file.stat.exists or deployment_force + tags: ["directory", "directory-structure"] + +- name: main | Touch file guard + copy: + content="" + dest="{{ deployment_guard_file }}" diff --git a/tasks/resolver/main.yml b/tasks/resolver/main.yml new file mode 100644 index 0000000..7702838 --- /dev/null +++ b/tasks/resolver/main.yml @@ -0,0 +1,4 @@ +--- + +- include: nexus.yml + when: deployment_artifact_resolver == "nexus" \ No newline at end of file diff --git a/tasks/resolver/nexus.yml b/tasks/resolver/nexus.yml new file mode 100644 index 0000000..de45a5b --- /dev/null +++ b/tasks/resolver/nexus.yml @@ -0,0 +1,19 @@ +--- + +- name: resolve | nexus | Make the http request to find the latest version on nexus + uri: + url="{{ deployment_nexus_url_resolver }}" + method=GET + HEADER_Accept="application/json" + HEADER_Authorization="{{ nexus_credentials | default(omit) }}" + register: nexus_artifact_info + tags: ["artifact-info"] + +- name: resolve | nexus | Show nexus url + debug: + var=deployment_nexus_url_resolver + +- name: resolve | nexus | Show nexus artifact information + debug: + var=nexus_artifact_info.json.data + tags: ["artifact-info"] diff --git a/tasks/unpack.yml b/tasks/unpack.yml deleted file mode 100644 index c3c12a5..0000000 --- a/tasks/unpack.yml +++ /dev/null @@ -1,39 +0,0 @@ ---- - -- name: "unpack | Unzip application (if .tgz)" - command: "tar -xf {{deployment_artifact_version_dir}}/{{deployment_artifact_destination_name}} -C {{deployment_artifact_version_dir}} --strip-components 1" - when: deployment_artifact_destination_name.find('.tgz') >= 1 - -- name: "unpack | Unzip application (if .zip)" - command: "unzip -o {{deployment_artifact_version_dir}}/{{deployment_artifact_destination_name}} -d {{deployment_artifact_version_dir}}" - when: deployment_artifact_destination_name.find('.zip') >= 1 - -- name: "unpack | Unzip config files (if .jar) (Optional)" - command: "unzip {{deployment_artifact_version_dir}}/{{deployment_artifact_destination_name}} -d {{deployment_artifact_version_dir}} *.conf" - when: deployment_artifact_destination_name.find('.jar') >= 1 - ignore_errors: yes - -- name: "unpack | Change file owner for all files" - file: - path="{{deployment_artifact_version_dir}}" - owner="{{ deployment_user }}" - group="{{ deployment_group }}" - state="directory" - recurse="yes" - -- name: "unpack | Create latest symlink" - file: - src="{{ deployment_artifact_version_dir }}" - dest="{{ deployment_current_dir }}" - owner="{{ deployment_user }}" - group="{{ deployment_group }}" - mode="0755" - state="link" - notify: - - restartApp - -- name: "unpack | check http service for non-service content (e.g. static files)" - debug: msg="placeholder task to notify http request check" - when: not deployment_install_initd - changed_when: true - notify: "make http request to service" \ No newline at end of file diff --git a/templates/supervisor.j2 b/templates/supervisor.j2 new file mode 100644 index 0000000..daf9630 --- /dev/null +++ b/templates/supervisor.j2 @@ -0,0 +1,41 @@ +[program:{{ deployment_supervisor_name | mandatory }}] + +# Command to run and arguments +command={{ deployment_supervisor_command | mandatory }} + +#Number of process to spawn +process_name={{ deployment_supervisor_process_name | default(deployment_supervisor_name) }} +numprocs={{ deployment_supervisor_numprocs | default("1") }} +#numprocs_start + +# Starting/restart/stop +autostart={{ deployment_supervisor_autostart | default("true") }} +# process will be restart when the program exits with not exist codes +autorestart={{ deployment_supervisor_autostart | default("false") }} +# total number of seconds which the program needs to stay running after a startup to consider the start successful. +startsecs={{ deployment_supervisor_startsecs | default("0") }} +startretries={{ deployment_supervisor_startretries | default("3") }} +stopsignal={{ deployment_supervisor_stopsignal | default("TERM") }} +stopwaitsecs={{ deployment_supervisor_stopwaitsecs | default("10") }} +# The list of “expected” exit codes for this program +exitcodes={{ deployment_supervisor_exitcodes | default("0,2") }} + +# User to run a process as +user={{ deployment_supervisor_user | mandatory }} + +# Log +redirect_stderr={{ deployment_supervisor_redirect_stderr | default("true") }} +stdout_logfile={{ deployment_supervisor_log | default("/dev/null") }} +stdout_logfile_maxbytes={{ deployment_supervisor_max_log_size | default("50MB") }} +stdout_logfile_backups={{ deployment_supervisor_log_backups | default("0") }} + +#Enviornment +{% if deployment_supervisor_env_vars is defined and deployment_supervisor_env_vars | length > 0 %} +environment={% for name, var in deployment_supervisor_env_vars.iteritems() %}{{ name|upper }}="{{ var }}"{% if not loop.last %},{% endif%}{% endfor %} +{% endif %} + +#Directory to change to +{% if deployment_supervisor_directory is defined %}directory={{ deployment_supervisor_directory }}{% endif %} + +#UMASK +{% if deployment_supervisor_umask is defined %}umask={{ deployment_supervisor_umask }}{% endif %}