#!/usr/bin/env bash # # Usage: # release # jobs ... # packages ... # src ... # # This currently represents *binary* jobs by default. # TODO: Add the concept of *script* jobs with the associated adjustments. fail() { echo $* >&2 ; exit 1 ; } createPackage() { local _package=$1 mkdir -p {packages,src,blobs}/${_package}/ touch {packages,src,blobs}/${_package}/.gitkeep cat > packages/${_package}/README.md < packages/${_package}/packaging < packages/${_package}/prepare < packages/${_package}/spec < jobs/${jobName}/README.md < jobs/${jobName}/templates/bin/control < \${pidFile} # Write the shell script's PID to the pidFile set_pid if (( \${pid} == 0 )) ; then echo \$\$ > \${pidFile} ; fi if [[ -z \${1:-} ]] ; then fail "\$0 start|stop" ; fi ; action=\$1 ; shift case \${action} in (start) user exec \${pkgPath}/bin/${jobName} ;; (stop) send_signal TERM ;; (*) fail "Unknown action ${action}" ;; esac ;; EOF cat > jobs/${jobName}/templates/shell/env.erb <> "\${logPath}/\${jobName}.log" # STD{OUT,ERR} echo -e "\$(date +'%Y-%m-%dT%H:%M:%S') \$(whoami) > \$0 \$*" source /var/vcap/jobs/\${jobName}/shell/functions <% if p('${jobName//-/_}.debug') == "true" %>turn_debugging_on<% end %> jobPath="/var/vcap/jobs/\${jobName}" pkgPath="/var/vcap/packages/\${jobName}" runPath="/var/vcap/sys/run/\${jobName}" tmpPath="/var/vcap/sys/tmp/\${jobName}" storePath="/var/vcap/store/\${jobName}" userName="root" groupName="root" LANG="en_US.UTF-8" HOME="\${HOME:-"/home/\${userName}"}" pidFile="\${runPath}/\${jobName}.pid" LD_LIBRARY_PATH="\${LD_LIBRARY_PATH:-}" export LANG HOME LD_LIBRARY_PATH add_packages_to_path configure_job_paths set_pid EOF cat > jobs/${jobName}/templates/shell/functions <&2 exit 1 } user() { local _action=\$1 ; shift case \${_action} in (exec) exec chpst -u "\${userName}:\${groupName}" "\$@" ;; (run) chpst -u "\${userName}:\${groupName}" "\$@" ;; (chown) chown -R "\${userName}:\${groupName}" "\$@" ;; esac } set_pid() { pid=0 if [[ -s \${pidFile} ]] then pid=\$(head -1 \${pidFile}) fi } send_signal() { if (( \${pid:-0} > 0 )) then kill -\${1} \${pid} fi } turn_debugging_on() { echo "Turning Debugging On" export PS4='+(\${BASH_SOURCE}:\${LINENO})> \${FUNCNAME[0]:+\${FUNCNAME[0]}(): }' export DEBUG="true" set -x set -v } add_packages_to_path() { # Add all packages' /bin & /sbin into \$PATH for _path in \$(ls -d /var/vcap/packages/*/*bin) do PATH="\${_path}:\${PATH}" done ; export PATH } configure_job_paths() { paths=( "\${jobPath}" "\${runPath}" "\${logPath}" "\${tmpPath}" "\${storePath}" ) if (( \${UID} == 0 )) then for _path in "\${paths[@]}" do [[ -d \${_path} ]] || mkdir -p "\${_path}" chown -R \${userName}:\${groupName} "\${_path}" chmod 0775 "\${_path}" done fi } graceful_stop() { rm -f \${pidFile} exit 0 # Normal exit, return code 0 } EOF cat > jobs/${jobName}/monit < jobs/${jobName}/spec < docs/${releaseName}.md < docs/notes.md < ${releaseName}-dev </dev/null then fail "'bosh' command was not found in your path, please 'gem install bosh_cli' and try again." fi } bosh_target_check() { boshTarget=\$(bosh target 2>&1) case "\${boshTarget}" in (Current\ target\ is*) echo \${boshTarget} ;; (*) fail "A bosh director is not targeted, please target a director and login then try again." ;; esac } latest_uploaded_stemcell() { bosh stemcells | awk "/bosh/&&/\${stemcellOS}/" | awk -F'|' '{ print \$2, \$3 }' | sort -nr -k2 | head -n1 | awk '{ print \$1 }' } usage() { echo " Usage: \$0 [options] Where [options] for the 'prepare', 'manifest' and 'stemcell' actions are: 'warden' or 'aws-ec2' " } requireCommands() { for cmd in \${@} do if ! command -v \${cmd} &>/dev/null then echo "\${cmd} must be installed and available in the PATH in order to run \$0" exit 1 fi done } select_infrastructure() { infrastructure=\${1:-} if ! [[ -n \${infrastructure:-} ]] then usage fail fi } prepare_blobs() { [[ -d \${releasePath}/blobs ]] || mkdir \${releasePath}/blobs echo "Preparing all packages..." for script in \${releasePath}/packages/*/prepare do if [[ -s \${script} ]] then echo \${script} ( cd \${releasePath}/blobs ; \${SHELL} \${script} ) fi done } prepare_stemcell() { select_infrastructure \$* stemcellOS=\${stemcellOS:-"centos"} directorCPI=\$(bosh status | awk '/CPI/{print \$2}') directorUUID=\$(awk -F: '/target_uuid/{print \$2}' ~/.bosh_config | tr -d ' ') directorName=\$(awk -F: '/target_name/{print \$2}' ~/.bosh_config) deploymentName="\${releaseName}-\${infrastructure}" [[ -d \${tmpPath} ]] || mkdir -p \${tmpPath} case \${infrastructure} in (aws-ec2) if [[ \${directorCPI} != aws ]] then fail "No AWS BOSH Director targeted. Please use 'bosh target' first." fi hypervisor="xen" case \${stemcellOS} in (ubuntu) stemcellURL="http://bosh.io/stemcells/bosh-aws-xen-light-ubuntu-trusty-go_agent" ;; (centos) stemcellURL="http://bosh.io/stemcells/bosh-aws-xen-light-centos-7-go_agent" ;; (*) fail "Unknown Stemcell OS '\${stemcellOS}'" ;; esac ;; (warden) if ! [[ "\${directorName}" =~ "Bosh Lite Director" ]] then fail "No BOSH Lite bosh-lite with warden CPI.\nPlease use 'bosh target' first." fi hypervisor="warden" case \${stemcellOS} in (ubuntu) stemcellURL="https://bosh.io/d/stemcells/bosh-warden-boshlite-ubuntu-trusty-go_agent" ;; (centos) stemcellURL="https://bosh.io/d/stemcells/bosh-warden-boshlite-centos-go_agent" ;; (*) fail "Unknown Stemcell OS '\${stemcellOS}'" ;; esac ;; (*) usage fail ;; esac shift stemcell=\${stemcell:-\$(latest_uploaded_stemcell)} if [[ -z \${stemcell} ]] then stemcellFile="\${stemcellsPath}/\$(basename \${stemcellURL}).tar.gz" if [[ -s \${stemcellFile} ]] then echo -e "\nUploading local stemcell \${stemcellFile}..." bosh upload stemcell \${stemcellFile} else echo -e "\nUploading latest \${hypervisor}/\${stemcellOS} stemcell..." bosh upload stemcell \${stemcellURL} fi stemcell=\$(latest_uploaded_stemcell) fi } prepare_dev_release() { echo "bosh create release --with-tarball --force" bosh create release --with-tarball --force echo "bosh -n upload release" bosh -n upload release } prepare_manifest() { select_infrastructure \$* prepare_stemcell \$* releaseName=\$(basename \$PWD | sed -e 's/-boshrelease//') directorCPI=\$(bosh status | awk '/CPI/{print \$2}') directorUUID=\$(awk -F: '/target_uuid/{print \$2}' ~/.bosh_config | tr -d ' ') directorName=\$(awk -F: '/target_name/{print \$2}' ~/.bosh_config) deploymentName="\${releaseName}-\${infrastructure}" requireCommands spiff bosh echo "Preparing to build the manifest... " sed \\ -e "s/DIRECTOR-UUID/\${directorUUID}/g" \\ -e "s/NAME/\${releaseName}/g" \\ -e "s/STEMCELL/\${stemcell}/g" \\ -e "s/ENVIRONMENT/\${releaseName}-\${ENVIRONMENT:-"dev"}/g" \\ "\${templatesPath}/stub.yml" > "\${tmpPath}/targeted-director-stub.yml" echo "Merging templates using the spiff..." spiff merge \\ "\${templatesPath}/deployment.yml" \\ "\${templatesPath}/jobs.yml" \\ "\${templatesPath}/infrastructure/\${infrastructure}.yml" \\ "\${tmpPath}/targeted-director-stub.yml" \\ \$* > "\${manifestsPath}/\${deploymentName}-manifest.yml" rm "\${tmpPath}/targeted-director-stub.yml" echo bosh deployment "\${manifestsPath}/\${deploymentName}-manifest.yml" bosh deployment "\${manifestsPath}/\${deploymentName}-manifest.yml" echo "bosh status" bosh status } if [[ \${DEBUG:-"false"} == "true" ]] then # Enable xtrace with context if debug is true. export PS4='+(\${BASH_SOURCE}:\${LINENO})> \${FUNCNAME[0]:+\${FUNCNAME[0]}(): }' set -x fi releasePath=\$(cd \$(dirname \$0) ; echo \$PWD) tmpPath=\${releasePath}/tmp manifestsPath=\${releasePath}/manifests stemcellsPath=\${releasePath}/stemcells releaseName=\$(awk -F: '/final_name/{print \$2}' config/final.yml | tr -d ' ') templatesPath="\${releasePath}/templates" if (( \$# > 0 )) then action=\$1 shift else usage fail fi bosh_target_check bosh_cli_check declare -a args if (( \${#@} )) then args=(\$(echo "\${@}")) fi case \${action} in (prepare) if (( \${#args[@]} == 0 )) then usage fail fi prepare_blobs prepare_dev_release prepare_stemcell "\${args[@]}" prepare_manifest "\${args[@]}" ;; (release|dev) prepare_dev_release ;; (blobs) prepare_blobs ;; (stemcell) prepare_stemcell "\${args[@]}" ;; (manifest) prepare_manifest "\${args[@]}" ;; (destroy|delete) echo "bosh -n delete deployment ${releaseName} --force" bosh -n delete deployment ${releaseName} --force ;; (*) usage fail "Unknown action \${action}." ;; esac exit 0 EOF chmod +x ${releaseName}-dev cat > templates/stub.yml < templates/deployment.yml < templates/jobs.yml < templates/infrastructure/warden.yml < templates/infrastructure/aws-ec2.yml < LICENSE < config/final.yml < config/dev.yml < config/blobs.yml < config/settings.yml < config/private.yml < README.md < .gitignore <<'EOF' #* *# *.swp *~ .DS_Store .blobs .blobs/ .dev_builds/ .final_builds/ .final_builds/jobs/**/*.tgz .final_builds/packages/**/*.tgz .idea .vagrant blobs/* config/dev.yml config/private.yml config/settings.yml dev_releases/ my*.yml releases/*.tgz manifests/*.yml stemcells/*z tmp/ EOF git add . git commit -a -m "${releaseName} BOSH Release Initialized." echo "${releaseName} BOSH Release created in ${PWD}" } createSrc() { echo "TODO: Implement create src function." } # # Usage: bosh-create # Where is one of release|job(s)|package(s) # Name list is the list of names to create. # set -x declare releaseName jobs=() packages=() srcs=() while (( $# )) do token=$1 shift 1 case ${token} in (-job|-jobs|job|jobs) kind=job ;; (-release|release) kind=release ;; (package|packages|-package|-packages) kind=package ;; (-src|src) kind=src ;; (*) case ${kind} in (release) releaseName=$token ;; (job) jobs+=($token) ;; (package) packages+=($token) ;; (src) srcs+=($token) ;; (*) fail "One of -release,-job(s),-package(s),-src(s) must be given." ;; esac ;; esac done if [[ -n ${releaseName} ]] then createRelease ${releaseName} fi for job in ${jobs[@]} do createJob ${job} done for package in ${packages[@]} do createPackage ${package} done for src in ${srcs[@]} do createSrc ${package} done exit 0