├── .gitignore ├── COPYING ├── Makefile.am ├── NEWS ├── README.markdown ├── TODO ├── autogen.sh ├── configure.ac ├── init ├── Makefile.am ├── pacemaker-cloud ├── pcloud-cape-sshd@.service ├── pcloud-cped.service ├── pcloud-qpidd.service └── pcloud-vmlauncher.service ├── man ├── Makefile.am ├── cped.1 ├── dped.1 ├── pacemaker_cloud_example.8 ├── pacemaker_cloud_overview.8 ├── pcloudsh.1 └── vmlauncher.1 ├── pacemaker-cloud.spec.in ├── src ├── .gitignore ├── Makefile.am ├── cape.c ├── cape.h ├── capeadmin.c ├── caped.c ├── cf2pe.xsl ├── cim_service.c ├── cim_service.h ├── common_agent.cpp ├── common_agent.h ├── config_loader.cpp ├── config_loader.h ├── cpe_agent.cpp ├── cpe_agent.h ├── cpe_agent_register.cpp ├── cpe_httpd.cpp ├── cpe_httpd.h ├── cpe_impl.cpp ├── cpe_impl.h ├── cped2.py ├── deltacloud.c ├── init-dbus.h ├── inst_ctrl.c ├── inst_ctrl.h ├── libinit.c ├── mainloop.cpp ├── mainloop.h ├── matahari.cpp ├── matahari.h ├── openstackv1.c ├── pcloudsh │ ├── .gitignore │ ├── F14-x86_64-jeos-assembly.tdl │ ├── F14-x86_64-jeos.tdl │ ├── F15-x86_64-jeos-assembly.tdl │ ├── F15-x86_64-jeos.tdl │ ├── F16-x86_64-jeos-assembly.tdl │ ├── F16-x86_64-jeos.tdl │ ├── Makefile.am │ ├── U10-x86_64-jeos-assembly.tdl │ ├── U10-x86_64-jeos.tdl │ ├── __init__.py │ ├── assembly.py │ ├── assembly_factory.py │ ├── assy-wordpress-F16.tdl │ ├── assy-wordpress-mysql-F16.tdl │ ├── assy1-F14.tdl │ ├── assy1-F15.tdl │ ├── assy1-F16.tdl │ ├── assy1-U10.tdl │ ├── assy1.tdl │ ├── cpe.py │ ├── db_helper.py │ ├── deployable.py │ ├── deployable_factory.py │ ├── eventreceiver.py │ ├── eventrunner.py │ ├── ifconfig.py │ ├── jeos.py │ ├── keys │ │ └── README │ ├── libvirt_assembly.py │ ├── libvirt_deployable.py │ ├── openstack_assembly.py │ ├── openstack_deployable.py │ ├── pcloudsh │ ├── pcmkconfig.py.in │ ├── resource.py │ ├── resource_templates │ │ ├── aeolus-conductor.xml │ │ ├── apache2.xml │ │ ├── condor.xml │ │ ├── conductor-dbomatic.xml │ │ ├── conductor-delayed_job.xml │ │ ├── deltacloud-core.xml │ │ ├── deltacloud-ec2-us-east-1.xml │ │ ├── deltacloud-ec2-us-west-1.xml │ │ ├── deltacloud-mock.xml │ │ ├── dummy.xml │ │ ├── httpd.xml │ │ ├── imagefactory.xml │ │ ├── mysqld.xml │ │ ├── ntpd.xml │ │ ├── postgresql.xml │ │ └── qpidd.xml │ ├── rhel61-x86_64-jeos-assembly.tdl │ ├── rhel61-x86_64-jeos.tdl │ └── vmlauncher ├── pcmk_pe.c ├── pcmk_pe.h ├── qmf_agent.cpp ├── qmf_agent.h ├── qmf_job.h ├── qmf_multiplexer.cpp ├── qmf_multiplexer.h ├── qmf_object.cpp ├── qmf_object.h ├── recover.c ├── schema.xml ├── trans.h ├── trans_cim.c └── trans_ssh.c └── tests ├── .gitignore ├── Makefile.am ├── check_basic.c ├── check_escalation.c ├── check_reconfig.c ├── check_recover.c ├── conductor ├── README ├── conductor.rb ├── config.ru ├── cpe-rest └── run ├── cpe-tool2.c ├── pe_test.c ├── run.py ├── sim_deltacloud_dummy.c ├── sim_deltacloud_master.c ├── sim_recovery.c ├── t_F16_x86_64_1.tdl └── templates ├── f14.ks ├── f14.tdl ├── rhel6.ks └── rhel6.tdl /.gitignore: -------------------------------------------------------------------------------- 1 | autom4te.cache 2 | Makefile 3 | Makefile.in 4 | aclocal.m4 5 | config.h 6 | config.h.in 7 | config.h.in~ 8 | config.log 9 | config.status 10 | config.guess 11 | config.sub 12 | configure 13 | depcomp 14 | install-sh 15 | missing 16 | stamp-h1 17 | *.o 18 | .deps 19 | *.pyc 20 | py-compile 21 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010-2011 Red Hat, Inc. 2 | # 3 | # Authors: 4 | # Angus Salkeld 5 | # Steven Dake 6 | # 7 | # This file is part of pacemaker-cloud. 8 | # 9 | # pacemaker-cloud is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 2 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # pacemaker-cloud is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU Lesser General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with pacemaker-cloud. If not, see . 21 | 22 | SPEC = $(PACKAGE_NAME).spec 23 | 24 | TARFILE = $(PACKAGE_NAME)-$(VERSION).tar.gz 25 | 26 | AUTOMAKE_OPTIONS = foreign 27 | 28 | MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure depcomp \ 29 | config.guess config.sub missing install-sh \ 30 | autoheader automake autoconf 31 | 32 | EXTRA_DIST = autogen.sh COPYING pacemaker-cloud.spec.in 33 | 34 | dist_doc_DATA = COPYING 35 | 36 | SUBDIRS = init man src tests src/pcloudsh 37 | 38 | $(TARFILE): 39 | $(MAKE) dist 40 | 41 | coverity: 42 | cov-build --dir=cov make 43 | cov-analyze --dir cov \ 44 | --concurrency \ 45 | --all \ 46 | --security \ 47 | --wait-for-license 48 | cov-format-errors --dir cov 49 | 50 | $(SPEC): $(SPEC).in 51 | DATE=$(shell date "+%a %b %d %Y") 52 | sed \ 53 | -e "s#@version@#$(VERSION)#g" \ 54 | -e "s#@date@#$(DATE)#g" \ 55 | $< > $@; 56 | 57 | RPMBUILDOPTS = --define "_sourcedir $(abs_builddir)" \ 58 | --define "_specdir $(abs_builddir)" \ 59 | --define "_builddir $(abs_builddir)" \ 60 | --define "_srcrpmdir $(abs_builddir)" \ 61 | --define "_rpmdir $(abs_builddir)" 62 | 63 | srpm: clean 64 | $(MAKE) $(SPEC) $(TARFILE) 65 | rpmbuild $(RPMBUILDOPTS) --nodeps -bs $(SPEC) 66 | 67 | rpm: clean 68 | $(MAKE) $(SPEC) $(TARFILE) 69 | rpmbuild $(RPMBUILDOPTS) -ba $(SPEC) 70 | 71 | .PHONY: coverity srpm rpm 72 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | I'd like to spend a moment to tell you about a new project myself and Angus 2 | Salkeld are working on. The project, called the Pacemaker Cloud Policy 3 | Engine, is a cloud-specific policy engine and will act as a sub-project 4 | of the Pacemaker project. 5 | 6 | We are doing a ground-up implementation of a cloud policy manager, using a 7 | few other open source building block components. 8 | 9 | Our dependencies are: 10 | QPID/QMF (provides a management bus for communication of the various components) 11 | Upstart (provides a mechanism to launch our internal processes) 12 | Pacemaker Policy Engine (provides a mechanism for us to make policy decisions) 13 | Matahari (provides a mechanism to monitor VM images) 14 | 15 | We have decided on a general model for managing cloud deployments: 16 | Assembly: A VM image with a Matahari instance 17 | Deployable: Collection of Assemblies 18 | 19 | We are working on 5 components at the moment: 20 | 1. QMF model of the methods/events for various components 21 | 2. CLI Shell 22 | 2.1 requests the CPE start a deployable 23 | 2.2 requests the CPE stop a deployable 24 | 2.3 Displays assembly failures 25 | 3. Cloud Policy Engine 26 | 3.1 starts a deployable policy engine 27 | 3.2 Stops a deployable policy engine 28 | 4. VM Launcher 29 | 4.1 Starts VM images 30 | 5. Deployable Policy Engine 31 | 5.1 Requests VM launcher to start images 32 | 5.2 Monitors a VM image via matahari 33 | 5.3 Starts applications via matahari 34 | 5.4 Stops applications via matahari 35 | 5.5 Recovers failures detected by matahari managed applications 36 | 5.6 Uses the Pacemaker policy engine library to make decisions about which 37 | sort of matahari actions to take 38 | 39 | Our repository is here: 40 | git://github.com/cloud-policy-engine/cloud-policy-engine 41 | 42 | Our mailing list is here: 43 | http://oss.clusterlabs.org/mailman/listinfo/pcmk-cloud 44 | 45 | A good slidedeck which shows our objective and rational is here: 46 | http://www.redhat.com/summit/2011/presentations/summit/whats_new/thursday/dake_th_1130_high_availability_in_the_cloud.pdf 47 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Cloud Policy Engine 2 | 3 | ------------------------------------------------------------------------------- 4 | 5 | ## Table of Contents 6 | 7 | 1. Mandatory Host Dependencies 8 | 2. Optional Host Dependencies 9 | 3. Building on Specific Distributions 10 | 4. Definitions 11 | 5. Architecture 12 | 13 | 14 | ## 1) Mandatory Host Dependencies 15 | 16 | * [libqb 0.10.1 or later](https://github.com/asalkeld/libqb) 17 | 18 | * [pacemaker](http://www.clusterlabs.org/) 19 | 20 | * [glib 2.0](http://www.gtk.org/) 21 | 22 | * [dbus-glib](http://www.freedesktop.org/wiki/Software/dbus) 23 | 24 | * [libxml2](http://xmlsoft.org/) 25 | 26 | * [libcurl](http://curl.haxx.se/) 27 | 28 | * [libmicrohttpd](http://www.gnu.org/software/libmicrohttpd/) 29 | 30 | * [oz 0.7.0 or later](http://www.aeolusproject.org/oz.html) 31 | 32 | * An IAAS platform of some type - the developers typically test with OpenStack 33 | 34 | ## 2) Optional Host Dependencies 35 | 36 | * [libssh2)](http://www.libssh2.org/) 37 | 38 | - To build without, ./configure --disable-transport-ssh2 39 | 40 | * [qpid (QMFv2)](http://qpid.apache.org/) 41 | 42 | - To build without, ./configure --disable-transport-matahari 43 | 44 | * [sblim sfcc](http://sblim.sourceforge.net/) 45 | 46 | - To build without, ./configure --disable-transport-cim 47 | 48 | * [deltacloud](http://deltalcloud.apache.org/) 49 | 50 | - To build without, ./configure --disable-api-deltacloud 51 | 52 | ### 1.1) Dependencies to run pcloudsh 53 | 54 | * m2crypto 55 | * python-libguestfs 56 | * python-qpid-qmf 57 | * python-daemon 58 | 59 | ## 2) Building on Specific Distributions 60 | 61 | ### Installing on Fedora 15: 62 | 63 | fedora15# yum install autoconf automake gcc-c++ glib2-devel libqb-devel \ 64 | dbus-glib-devel libxml2-devel pacemaker-libs-devel libtool-ltdl-devel \ 65 | qpid-cpp-client-devel qpid-qmf-devel libmicrohttpd-devel libcurl-devel 66 | fedora15# make rpm 67 | fedora15# rpm -ivh $(arch)/*.rpm 68 | 69 | ### Installing on Fedora 14: 70 | 71 | qpid on f14 is out of date. libqb is not available in f14. Please obtain 72 | copies of the source tree from section 1 for those packages and build from 73 | source. Note on 64 bit systems, qpid does not autodetect the libdir is 74 | 64 bit, so --libdir=/usr/lib64 must be specified. 75 | 76 | fedora14# yum install autoconf automake gcc-c++ glib2-devel \ 77 | dbus-glib-devel libxml2-devel pacemaker-libs-devel libtool-ltdl-devel \ 78 | libmicrohttpd-devel libcurl-devel 79 | 80 | fedora14# cd libqb 81 | fedora14# make rpm 82 | fedora14# rpm -ivh $(arch)/*.rpm 83 | 84 | install qpid, overwriting your default install 85 | 86 | fedora14# make rpm 87 | fedora14# rpm -ivh $(arch)/*.rpm 88 | 89 | ## 3) Definitions 90 | 91 | _Assembly_ = user defined guest composed of a VM image, Matahari active 92 | monitoring agent, boot configuration tools, and applications 93 | 94 | _Deployable_ = user defined set of assemblies and services 95 | 96 | _CPE_ = Cloud Policy Engine, starts and stops DPE's 97 | 98 | _DPE_ = Deployable Policy Engine, controls the services in a customer deployment 99 | 100 | ## 4) Architecture 101 | 102 | Description of the program flow given some different scenarios: 103 | 104 | ### Create new deployment 105 | 106 | 1. Cloud management software sends cpe the assembly & service config 107 | in XML (via QMF). Note very simerlar to what pacemaker PE wants. 108 | 2. CPE asks upstart/systemd to start a new DPE. 109 | 3. CPE stores the config somewhere (DB or file) 110 | 4. CPE waits for the DPE QMF agent to be available, then asks it to 111 | load the config and managemt the deployment. 112 | 5. DPE gathers config + state and sends it to the PE 113 | 6. DPE performs the actions (using matahari) as instructed by PE 114 | 115 | 116 | ### Destroy deployment 117 | 118 | 1. Cloud managemt software tells CPE to destroy a deployment 119 | 2. CPE asks upstart/systemd to stop the DPE and deletes the config 120 | 121 | 122 | ### DPE dies or gets restarted 123 | 124 | 1. CPE notices death of CPE and starts a new one 125 | 2. CPE waits for the DPE QMF agent to be available, then asks it to 126 | load the config and managemt the deployment. 127 | 3. DPE gathers config + state and sends it to the PE 128 | 4. DPE performs the actions (using matahari) as instructed by PE 129 | 130 | 131 | ### Assembly Instance misses heartbeat 132 | 133 | 1. DPE notices the Assembly has missed a heartbeat. 134 | 2. send a QMF event (assembly failure) 135 | 3. DPE gathers config + state and sends it to the PE 136 | 4. DPE performs the actions (using matahari) as instructed by PE 137 | (move services to other assemblies) 138 | 139 | 140 | ### User modifies the deployment configuration 141 | 142 | 1. Cloud management software sends cpe the assembly & service config 143 | in XML (via QMF). Note very simerlar to what pacemaker PE wants. 144 | 2. CPE sees the DPE is already running. 145 | 3. CPE stores the config somewhere (DB or file) 146 | 4. CPE then notifys the DPE that the config has changed. 147 | 5. DPE gathers config + state and sends it to the PE 148 | 6. DPE performs the actions (using matahari) as instructed by PE 149 | 150 | 151 | ### User accesses the event log. 152 | 153 | 1. cloud management software accesses event log 154 | Since CPE/DPE is only one part of the cloud software the logs 155 | need to be inserted into a larger picture. 156 | So we need an API to log important events. 157 | 158 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | ====================== 2 | Release Zoysia (1.0) 3 | ====================== 4 | + Assembly/deployable/resource model for organizing virtual machines. 5 | + Assembly/deployble/resource restart on failure detection. 6 | + Recovery escalation on failure. 7 | + Full Aeolus integration including configuration, visualization and event 8 | recording. 9 | + Basic OpenStack integration including image building and restart. 10 | + Merged into Debian, EPEL6, Fedora 15, Fedora 16, Fedora 17, Fedora 18, Ubuntu. 11 | + Local resource monitoring and VM healthchecking via Matahari. 12 | + Local resource monitoring and VM healthchecking via ssh. 13 | 14 | ======================= 15 | Interim Release Goals 16 | ======================= 17 | 0.5 - Full Fedora 15/Fedora 16 integration of assembly/deployable/resource 18 | restart single node. 19 | 0.6 - Division of supported infrastructure into separate RPMs. 20 | Ubuntu assembly support. 21 | Wordpress + MySql demonstration. 22 | Human parsable event display in pcloudsh. 23 | Aeolus restart on failure detection. 24 | OpenStack image generation and restart integration. 25 | Recovery escalation. 26 | QMF fd api usage to reduce cpu utilization. 27 | 0.7 - Deltacloud integration for VM start/stop control in dped-mh. 28 | Deltacloud integration for VM start/stop control in dped-ssh. 29 | Removal of vmlauncher. 30 | blocking ssh-based agent VM/resource control in separate binary dped-ssh. 31 | timer splits for escalation in dped-mh. 32 | timer splits for escalation in dped-ssh. 33 | startup ordering of resources and VMs in dped-mh. 34 | startup ordering of resources and VMs in dped-ssh. 35 | Full Fedora 17 integration. 36 | Allow shell to choose between matahari or ssh monitoring 37 | rewrite cped in python (could move to next release). 38 | 0.8 - API communication between cped and Aeolus. 39 | restart VMs and resources on failure via Aeolus. 40 | support Aeolus launching a DPED via CPE interface. 41 | make dped-ssh non-blocking 42 | 0.9 - Application resource monitoring integration with Aeolus conductor. 43 | 1.0 - Configuration and event recording with Aeolus conductor. 44 | 45 | ========================= 46 | Priority Sorted Backlog 47 | ========================= 48 | ------------------ 49 | Person (WHO) 50 | ------------------ 51 | a = Angus 52 | s = Steven 53 | u = Unassigned 54 | 55 | ------------------ 56 | Components (CMP) 57 | ------------------ 58 | CPE = Cloud Policy Engine main binary 59 | DPEM = Deployable Policy Engine binary in C++ for QMF/Matahari connections 60 | DPES = Deployable Policy Engine binary in C for SSH connections 61 | PSH = Pacemaker Cloud Shell 62 | API = API communication between IAAS platform and Pacemaker Cloud 63 | PKG = Packaging 64 | MAN = Manual Pages 65 | DEM = demonstrations 66 | 67 | --- --- ------------------------------------------------------------------ 68 | WHO CMP Description 69 | --- --- ------------------------------------------------------------------ 70 | 71 | 0.7: Release date: MARCH 15, 2012 72 | 73 | s - DPES - Implementation of SSH based monitoring in dped-ssh 74 | s - DPES - add support for recovery escalation policy to DPES 75 | a - DPEM - deltacloud integration in dped-ssh 76 | a - DPEM - startup ordering of resources and VMs in dped-mh 77 | s - SHL - allow shell to choose between matahari or ssh monitoring process 78 | s - DPES - startup ordering of resources and VMs in dped-ssh 79 | s - DPES - deltacloud integration in dped-mh 80 | a - CPE - rewrite cped in python 81 | s - VML - Removal of vmlauncher 82 | s - SHL - Full Fedora 17 integration 83 | 84 | post 0.7: 85 | u - DPES - make dped-ssh nonblocking 86 | u - PKG - lsb init scripts 87 | u - PKG - EPEL packages 88 | u - SHL - show assembly online/offline 89 | u - SHL - show resource status 90 | u - API - Aeolus VM state visualization 91 | u - API - Aeolus conductor API integration with CPE API 92 | u - CPE - extend upstart/systemd client code to include getting events on 93 | failure. 94 | u - PKG - debian packaging 95 | 96 | ===================== 97 | Open Questions List 98 | ===================== 99 | None at this time. 100 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this to generate all the initial makefiles, etc. 3 | 4 | echo Building configuration system... 5 | autoreconf -i -v && echo Now run ./configure and make 6 | 7 | -------------------------------------------------------------------------------- /init/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010-2011 Red Hat, Inc. 2 | # 3 | # Authors: Angus Salkeld 4 | # 5 | # This file is part of pacemaker-cloud. 6 | # 7 | # pacemaker-cloud is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # pacemaker-cloud is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with pacemaker-cloud. If not, see . 19 | 20 | MAINTAINERCLEANFILES = Makefile.in 21 | 22 | sysconfsysconfdir = $(sysconfdir)/sysconfig 23 | sysconfsysconf_DATA = pacemaker-cloud 24 | 25 | systemdconfdir = /lib/systemd/system 26 | systemdconf_DATA = pcloud-cped.service pcloud-vmlauncher.service \ 27 | pcloud-qpidd.service pcloud-cape-sshd@.service pcloud-cape-cim.service 28 | 29 | EXTRA_DIST = $(systemdconf_DATA) $(sysconfsysconf_DATA) 30 | 31 | -------------------------------------------------------------------------------- /init/pacemaker-cloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdake/pacemaker-cloud/bbc3f96b4697f53133516ff51ba0e0a04ae9de51/init/pacemaker-cloud -------------------------------------------------------------------------------- /init/pcloud-cape-sshd@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Deployable Policy Engine 3 | 4 | [Service] 5 | WorkingDirectory=/var/lib/pacemaker-cloud 6 | StandardOutput=null 7 | StandardError=null 8 | ExecStart=/usr/sbin/cape-sshd-os1 %i 9 | ExecReload=/bin/kill -HUP $MAINPID 10 | Type=simple 11 | TimeoutSec=5 12 | Restart=on-failure 13 | -------------------------------------------------------------------------------- /init/pcloud-cped.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Cloud Policy Engine 3 | Wants=pcloud-qpidd.service 4 | 5 | [Service] 6 | WorkingDirectory=/var/lib/pacemaker-cloud 7 | EnvironmentFile=/etc/sysconfig/pacemaker-cloud 8 | StandardOutput=null 9 | StandardError=null 10 | ExecStart=/usr/sbin/cped -v $cped_opts 11 | Type=simple 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /init/pcloud-qpidd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=qpidd for pacemaker-cloud 3 | After=syslog.target 4 | 5 | [Service] 6 | StandardOutput=null 7 | StandardError=null 8 | ExecStart=/usr/sbin/qpidd --auth no -p 49000 --no-data-dir 9 | Type=simple 10 | User=qpidd 11 | Group=qpidd 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /init/pcloud-vmlauncher.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=VM Launcher 3 | Wants=pcloud-qpidd.service 4 | 5 | [Service] 6 | WorkingDirectory=/var/lib/pacemaker-cloud 7 | StandardOutput=null 8 | StandardError=null 9 | ExecStart=/usr/bin/vmlauncher 10 | Type=simple 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /man/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010-2011 Red Hat, Inc. 2 | # 3 | # Authors: Steven Dake 4 | # 5 | # This file is part of pacemaker-cloud. 6 | # 7 | # pacemaker-cloud is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # pacemaker-cloud is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with pacemaker-cloud. If not, see . 19 | 20 | MAINTAINERCLEANFILES = Makefile.in 21 | 22 | dist_man_MANS = cped.1 vmlauncher.1 dped.1 pcloudsh.1 pacemaker_cloud_overview.8 pacemaker_cloud_example.8 23 | -------------------------------------------------------------------------------- /man/cped.1: -------------------------------------------------------------------------------- 1 | .TH CPED 1 "Jul 2011" "cped" 2 | 3 | .SH NAME 4 | cped - Pacemaker Cloud High Availability Management Daemon 5 | 6 | .SH SYNOPSIS 7 | .B cped [OPTIONS] 8 | 9 | .SH DESCRIPTION 10 | This daemon maintains high availability of deployables in the system. A 11 | deployable is a collection of assemblies that serve a common purpose, such 12 | as providing an end'user web service. Assemblies are a composition of 13 | a virtual machine base install, Matahari monitoring and control agents, and 14 | user defined application resources. 15 | 16 | The default options will result in a working system. These options are 17 | typically meant for developers. 18 | 19 | .SH OPTIONS 20 | .TP 21 | .B "\-d [ \-\-daemon ]" 22 | Run as a daemon by detaching from the local terminal. 23 | 24 | .TP 25 | .B "\-h [ \-\-help ]" 26 | Display options to the cped daemon. 27 | 28 | .TP 29 | .B "\-b [ \-\-broker ]" 30 | Specify the qpidd broker host name. Currently this option is not meant to 31 | be used, since only single node is currently supported. 32 | 33 | .TP 34 | .B "\-p [ \-\-port ]" 35 | Specify the qpidd port over which to communicate. 36 | 37 | .TP 38 | .B "\-g [ \-\-gssapi ]" 39 | Force GSSAPI authentication when communicating with other processes in the 40 | system including Matahari agents. 41 | 42 | .TP 43 | .B "\-u [ \-\-username ]" 44 | Specify the username to use when communicating with other processes in the 45 | system including Matahari agents. 46 | 47 | .TP 48 | .B "\-p [ \-\-password ]" 49 | Specify the password to use when communicating with other processes in the 50 | system including Matahari agents. 51 | 52 | .TP 53 | .B "\-p [ \-\-service ]" 54 | Specify the service to use when communicating with other processes in the 55 | system including Matahari agents. 56 | 57 | .TP 58 | .B "\-H [ \-\-http-port ]" 59 | Specify the port that the HTTP API will listen on 60 | system including Matahari agents. 61 | 62 | .TP 63 | .B "\-c [ \-\-conductor ]" 64 | Specify the aeolus-conductor host name to communicate with. 65 | 66 | .TP 67 | .B "\-C [ \-\-conductor-port ]" 68 | Specify the aeolus-conductor port to communicate with. 69 | 70 | .SH SEE ALSO 71 | dped(1), vmlauncher(1), pcloudsh(1), pacemaker_cloud_overview(8), pacemaker_cloud_example(8) 72 | 73 | .SH AUTHORS 74 | Angus Salkeld 75 | Steven Dake 76 | -------------------------------------------------------------------------------- /man/dped.1: -------------------------------------------------------------------------------- 1 | .TH DPED 1 "Jul 2011" "dped" 2 | 3 | .SH NAME 4 | dped - Deployable Policy Engine 5 | 6 | .SH SYNOPSIS 7 | .B dped [OPTIONS] 8 | 9 | .SH DESCRIPTION 10 | This daemon maintains the high availability of assemblies and resources 11 | in a deployable. dped will restart assemblies using vmlauncher and 12 | restart resources using Matahari. dped will also generate QMF events 13 | for all of these conditions (resource/assembly failure and restart). 14 | 15 | The default options will result in a working system. These options are 16 | typically meant for developers. 17 | 18 | .SH OPTIONS 19 | .TP 20 | .B "\-d [ \-\-daemon ]" 21 | Run as a daemon by detaching from the local terminal. 22 | 23 | .TP 24 | .B "\-h [ \-\-help ]" 25 | Display options to the dped daemon. 26 | 27 | .TP 28 | .B "\-b [ \-\-broker ]" 29 | Specify the qpidd broker host name. Currently this option is not meant to 30 | be used, since only single node is currently supported. 31 | 32 | .TP 33 | .B "\-p [ \-\-port ]" 34 | Specify the qpidd port over which to communicate. 35 | 36 | .TP 37 | .B "\-g [ \-\-gssapi ]" 38 | Force GSSAPI authentication when communicating with other processes in the 39 | system including Matahari agents. 40 | 41 | .TP 42 | .B "\-u [ \-\-username ]" 43 | Specify the username to use when communicating with other processes in the 44 | system including Matahari agents. 45 | 46 | .TP 47 | .B "\-p [ \-\-password ]" 48 | Specify the password to use when communicating with other processes in the 49 | system including Matahari agents. 50 | 51 | .TP 52 | .B "\-p [ \-\-service ]" 53 | Specify the service to use when communicating with other processes in the 54 | system including Matahari agents. 55 | 56 | .SH SEE ALSO 57 | cped(1). vmlauncher(1), pcloudsh(1), pacemaker_cloud_overview(8), pacemaker_cloud_example(8) 58 | 59 | .SH AUTHORS 60 | Angus Salkeld 61 | -------------------------------------------------------------------------------- /man/pacemaker_cloud_example.8: -------------------------------------------------------------------------------- 1 | .TH PACEMAKER_CLOUD_EXAMPLE 8 "Aug 2011" "pacemaker_cloud_example" 2 | 3 | .SH NAME 4 | pacemaker_cloud_example - Pacemaker Cloud Usage Example 5 | 6 | .SH DESCRIPTION 7 | The pacemaker cloud project provides high levels of service availability 8 | for high scale cloud deployments. This example uses the concepts 9 | described in the pacemaker_cloud_overview(8), to create a highly 10 | available cloud deployment. 11 | 12 | .SH SETUP 13 | Ensure the pcloud\-cped service is started, using for example: 14 | .br 15 | systemctl start pcloud\-cped.service 16 | .PP 17 | Ensure a compatible OS image is available, for example: 18 | .br 19 | /var/lib/libvirt/images/Fedora\-14\-x86_64\-DVD.iso 20 | /var/lib/libvirt/images/Uubuntu\-10.04.3\-server\-amd64.iso 21 | 22 | .br 23 | To create an openstack deployment you need to do the following: 24 | .br 25 | nova-manage user admin $USERNAME 26 | .br 27 | nova-manage network create default 10.0.0.0/24 1 256 --bridge=br0 28 | 29 | .SH PCLOUDSH 30 | Start the pcloudsh(1) command as root, 31 | and enter the following pcloudsh commands: 32 | .PP 33 | .nf 34 | jeos_create F16 x86_64 35 | assembly_create assy1 F16 x86_64 36 | assembly_clone assy1 assy2 37 | assembly_clone assy1 assy3 38 | assembly_resource_add httpdone httpd assy1 39 | assembly_resource_add httpdtwo httpd assy2 40 | assembly_resource_add httpdthree httpd assy3 41 | 42 | deployable_create dep1 43 | # or for an openstack deployment 44 | deployable_create dep1 openstack $USERNAME 45 | 46 | deployable_assembly_add dep1 assy1 47 | deployable_assembly_add dep1 assy2 48 | deployable_assembly_add dep1 assy3 49 | deployable_start dep1 50 | 51 | note Ubuntu's httpd server is "apache2". Replace assembly_resource_add 52 | data that uses http with apache2. 53 | 54 | .SH AVAILABILITY TESTING 55 | Keep pcloudsh running to verify that appropriate events 56 | are reported for the following operations: 57 | .PP 58 | .B Resource restart 59 | .PP 60 | Log in to one of the assemblies (the default root password is "password") 61 | and stop httpd. Verify that httpd is restarted via pacemaker\-cloud. 62 | .PP 63 | .B Assembly restart 64 | .PP 65 | Open the virtual machine manager GUI and use the "force off" 66 | functionality on a virtual machine (assembly). The virtual machine manager 67 | should display that the assembly is restarted. Log in to the restarted 68 | virtual machine and verify httpd was restarted properly too. 69 | 70 | .SH TROUBLESHOOTING 71 | Ensure TCP port 49000 is not blocked by your firewall. 72 | Ensure SELinux is setup appropriately or disabled. 73 | 74 | .SH WEBSITE 75 | http://www.pacemaker\-cloud.org/ 76 | 77 | .SH SEE ALSO 78 | cped(1), dped(1), vmlauncher(1), pcloudsh(1), pacemaker_cloud_overview(8) 79 | 80 | .SH AUTHORS 81 | Pádraig Brady 82 | Steven Dake 83 | Angus Salkeld 84 | -------------------------------------------------------------------------------- /man/pacemaker_cloud_overview.8: -------------------------------------------------------------------------------- 1 | .TH PACEMAKER_CLOUD_OVERVIEW 8 "Jul 2011" "pacemaker_cloud_overview" 2 | 3 | .SH NAME 4 | pacemaker_cloud_overview \- Pacemaker Cloud High Availability Overview 5 | 6 | .SH DESCRIPTION 7 | The pacemaker cloud project provides high levels of service availability 8 | for high scale cloud deployments. Our approach to high availability is to 9 | detect failures, isolate failures, followed by restart of the failed 10 | components. When repeated component failures occur the software escalates 11 | those failures into failures of higher level components. 12 | 13 | .SH MODEL 14 | .B "assembly" 15 | An assembly is a virtual machine image with active monitoring provided by 16 | Matahari. Matahari monitors resources such as httpd. 17 | 18 | .B "deployable" 19 | A deployable is a collection of assemblies that serve a common task. An example 20 | would be a collection of 3 images with one database, one web server, and one 21 | JBOSS server. 22 | 23 | .B "resource" 24 | An applicaton contained inside an assembly which is monitored and recovered 25 | in the event of failure. 26 | 27 | .B "jeos" 28 | A JEOS is an acronym meaning Just Enough Operating System. It is the bare image 29 | necessary to boot an image in a libvirt managed cloud environment. 30 | 31 | .B "pcloudsh" 32 | The pcloudsh is a test harness which also provides user functionality for 33 | executing the behavior of the system. This component would be an integration 34 | point for other cloud infrastructure software. 35 | 36 | .B "vmlauncher" 37 | The vmlauncher is a simple test harness daemon which launches assemblies on 38 | the local node. 39 | 40 | .B "cped" 41 | The Cloud Policy Engine Daemon launches a dped process for each deployable to 42 | manage the state of the deployable and ensure it remains as available as 43 | possible. 44 | 45 | .B "dped" 46 | The Deployable Policy Engine Daemon instructs vmlauncher to launch virtual 47 | machines (assemblies). Once those assemblies are launched the application 48 | state and virtual machine state is monitored by Matahari. If a failure of 49 | an application or virtual machine is detected, it is restarted. 50 | 51 | .SH FEATURES AVALABLE TODAY 52 | .B "Active monitoring and recovery of application failure" 53 | The software actively monitors resources using Matahari such as httpd and 54 | restarts them if they fail. 55 | 56 | .B "Active monitoring and recovery of assembly failure" 57 | The software actively monitors assemblies using Matahari and restarts them if 58 | they fail. 59 | 60 | .B "Active monitoring and recovery of deployable failure" 61 | The software actvel montors for a deployable failure and restarts them if 62 | they fail. 63 | 64 | .B Integration with OpenStack http://www.openstack.org/ 65 | To use with OpenStack the only change you need to make is when creating the 66 | deployable: 67 | deployable_create openstack 68 | 69 | .SH FEATURES PLANNED FOR THE FUTURE 70 | .B "Recovery escalation" 71 | .nf 72 | The developers plan to add support for recovery escalation. Recovery 73 | escalation works by escalating a lower level repetitive component failure into 74 | a higher level recovery action. For example, if httpd fails 5 times in 1 hour, 75 | the software terminates the containing assembly and restarts it. If that 76 | assembly then has repeated failures, the software would terminate the assembly 77 | and escalate the recovery by restarting the containing deployable. If the 78 | deployable fails repeatedly, the deployable is relocated to a different cloud 79 | provider if supportd by the IAAS platform. 80 | 81 | .B "Integraton with IAAS platforms" 82 | .nf 83 | The developers integreated with or will integrate with the following IAAS platforms: 84 | .PP 85 | .nf 86 | .B Aeolus http://www.aeolus.org 87 | .B libvirt http://www.libvirt.org (testing only) 88 | .B OpenStack http://www.openstack.org 89 | .B oVirt http://www.ovirt.org 90 | 91 | .SH LIMITATONS 92 | Pacemaker Cloud is demo-grade software using best known practices for 93 | providing high levels of service availablity in a cloud environment. Because 94 | of lacking integraton with cloud management software, we are not yet able to 95 | run assemblies on multple nodes or external cloud providers. 96 | 97 | .SH WEBSITE 98 | http://www.pacemaker\-cloud.org/ 99 | 100 | .SH SEE ALSO 101 | cped(1), dped(1), vmlauncher(1), pcloudsh(1), pacemaker_cloud_example(8) 102 | 103 | .SH AUTHORS 104 | Steven Dake 105 | Angus Salkeld 106 | -------------------------------------------------------------------------------- /man/pcloudsh.1: -------------------------------------------------------------------------------- 1 | .TH PCLOUDSH 1 "Jul 2011" "pcloudsh" 2 | 3 | .SH NAME 4 | plcoudsh - Pacemaker Cloud High Availability Cloud Shell 5 | 6 | .SH SYNOPSIS 7 | .B pcloudsh [OPTIONS] 8 | 9 | .SH DESCRIPTION 10 | This command allows configuration, launching, and monitoring of assemblies and 11 | resources using Pacemaker Cloud. 12 | 13 | To configure Pacemaker Cloud, a deployable must be created. A deployable 14 | is a collection of assemblies. Assemblies are formed from JEOS (just enough 15 | operating system) images. The first step is to create a JEOS image for a 16 | specific distribution. An assembly is then created from a JEOS image source 17 | and includes end-user applications that should be monitored. Resources are 18 | configured for an assembly. The assebles are added to a deployable. 19 | 20 | To launch deployables, the deployable_start command should be used. 21 | 22 | After a deployable is launched, any changes in its state, such as a failure of 23 | a resource or assembly will be displayed in the shell. When a resource 24 | or assembly is recovered, the shell will display these events. 25 | 26 | The pcloudsh tool offers a command line operating mode as well as a shell mode. 27 | The tool contains built-in help for each command. The pcloudsh tool must be 28 | run as root, as it creates QEMU images. 29 | 30 | .SH OPTIONS 31 | .TP 32 | .B "jeos_create " 33 | 34 | Create a JEOS image 35 | 36 | The jeos_create action creates a "(J)ust (E)nough (O)perating (S)ystem" image 37 | file. This step should only be done once at initialization and can take up 38 | to 30 minutes to complete. The current JEOS image types supported are either 39 | Fedora 14, 15, Fedora 16, RHEL6.1, or Ubuntu 10.03. The only supported 40 | architecture is x86_64. 41 | 42 | .TP 43 | .B "jeos_list" 44 | 45 | Lists the currently configured JEOS images 46 | 47 | .TP 48 | .B "assembly_create " 49 | 50 | Create an assembly 51 | 52 | The assembly_create action creates an assembly from the JEOS base image. 53 | Some post processing is done of the assembly image to ensure it will boot 54 | such as changing its mac address. A new mac address is randomly generated 55 | for the new assembly. 56 | 57 | .TP 58 | .B "assembly_clone " 59 | 60 | Clones an assembly 61 | 62 | The assembly_clone action creates a copy of the original assembly. Some 63 | post processing is done of the assembly image to ensure it will boot such 64 | as changing its mac address. A new mac address is randomly generated 65 | for the clone. 66 | 67 | .TP 68 | .B "assembly_delete '" 69 | 70 | Delete an existing assembly 71 | 72 | The assembly_delete action deletes the named assembly. No error checking is 73 | done to ensure it is not already part of an deployable. Use this command with 74 | caution. 75 | 76 | .TP 77 | .B "assembly_list" 78 | 79 | List the assemblies 80 | 81 | The assembly_list action lists all assemblies in the database. 82 | 83 | .TP 84 | .B "assembly_resource_add 85 | 86 | Add a resource to an assembly 87 | 88 | .TP 89 | .B "assembly_resource_list " 90 | 91 | List resources for an assembly 92 | 93 | .TP 94 | .B "assembly_resource_remove " 95 | 96 | Remove a resource from an assembly 97 | 98 | .TP 99 | .B "deployable_assembly_add " 100 | 101 | Add an assembly to a deployable 102 | 103 | The deployable_assembly_add action adds the assembly to the 104 | deployable and stores it in the pcloudsh database. 105 | 106 | pcloudsh# help deployable_assembly_remove 107 | 108 | .TP 109 | .B "deployable_assembly_remove '" 110 | 111 | Remove an assembly from a deployable 112 | 113 | The deployable_assembly_remove action removes an existing assembly 114 | from an existing deployable and stores 115 | it in the pcloudsh database. 116 | 117 | .TP 118 | .B "deployable_create " 119 | 120 | Create a new deployable 121 | 122 | The deployable_create action creates a new deployable and stores it in the 123 | pcloudsh database. 124 | 125 | .TP 126 | .B "deployable_list " 127 | 128 | List all existing deployables 129 | 130 | The deployable_list action lists all deployables registered in the pcloudsh 131 | database. 132 | 133 | .TP 134 | .B "deployable_start " 135 | 136 | Start a new deployable 137 | 138 | The deployable_start action starts a new deployable in the system 139 | 140 | .TP 141 | .B "deployable_status " 142 | 143 | Get the status of a deployable 144 | 145 | The deployable_status action queries a deployable in the system 146 | 147 | .TP 148 | .B "deployable_stop 149 | 150 | Stop a new deployable" 151 | 152 | The deployable_stop action stops a deployable in the system 153 | 154 | .SH SEE ALSO 155 | dped(1), vmlauncher(1), pcloudsh(1), pacemaker_cloud_overview(8), pacemaker_cloud_example(8) 156 | 157 | .SH AUTHORS 158 | Steven Dake 159 | Angus Salkeld 160 | -------------------------------------------------------------------------------- /man/vmlauncher.1: -------------------------------------------------------------------------------- 1 | .TH VMLAUNCHER 1 "Jul 2011" "vmlauncher" 2 | 3 | .SH NAME 4 | vmlauncher - Pacemaker Cloud Virtual Machine Assembly Launcher 5 | 6 | .SH SYNOPSIS 7 | .B vmlauncher [OPTIONS] 8 | 9 | .SH DESCRIPTION 10 | This daemon launches virtual machines at the request of the administrator 11 | when using pcloudsh. This daemon starts automatically in systemd systems. 12 | 13 | The command line options are meant for developer use of the software. 14 | 15 | .SH OPTIONS 16 | .TP 17 | .B "\-d [ \-\-daemon ]" 18 | Run as a daemon by detaching from the local terminal. 19 | 20 | .TP 21 | .B "\-h [ \-\-help ]" 22 | Display options to the cped daemon. 23 | 24 | .SH SEE ALSO 25 | cped(1), dped(1), pcloudsh(1), pacemaker_cloud_overview(8), pacemaker_cloud_example(8) 26 | 27 | .SH AUTHORS 28 | Angus Salkeld 29 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | org/ 2 | cped 3 | rpc/netdb.h 4 | cape-mh-dc 5 | cape-mh-os 6 | cape-sshd-dc 7 | cape-sshd-os 8 | -------------------------------------------------------------------------------- /src/cape.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Steven Dake 5 | * Angus Salkeld 6 | * 7 | * This file is part of pacemaker-cloud. 8 | * 9 | * pacemaker-cloud is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * pacemaker-cloud is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with pacemaker-cloud. If not, see . 21 | */ 22 | 23 | #ifndef CAPE_H_DEFINED 24 | #define CAPE_H_DEFINED 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | #include "pcmk_pe.h" 39 | 40 | /* 41 | * Limits of the system 42 | */ 43 | #define ASSEMBLY_NAME_MAX 1024 /* Maximum assembly length in bytes */ 44 | #define RESOURCE_NAME_MAX 1024 /* Maximum resource length in bytes */ 45 | #define COMMAND_MAX 32000 /* Maximum command length in bytes */ 46 | #define METHOD_NAME_MAX 20 /* Maximum method name in bytes */ 47 | #define OP_NAME_MAX 15 /* Maximum interval length in bytes */ 48 | #define RESOURCE_COMMAND_MAX 4096 /* Command maximum */ 49 | #define RESOURCE_ENVIRONMENT_MAX 2048 /* Maximum environment allowed */ 50 | 51 | /* 52 | * Timers of the system 53 | */ 54 | #define KEEPALIVE_TIMEOUT 15 /* seconds */ 55 | #define SSH_TIMEOUT 5000 /* milliseconds */ 56 | #define PENDING_TIMEOUT 250 /* milliseconds */ 57 | #define HEALTHCHECK_TIMEOUT 3000 /* milliseconds */ 58 | 59 | #define OCF_ROOT "/usr/lib/ocf" /* OCF root directory */ 60 | 61 | struct application { 62 | char *name; 63 | char *uuid; 64 | qb_map_t *node_map; 65 | }; 66 | 67 | enum recover_state { 68 | RECOVER_STATE_UNKNOWN, 69 | RECOVER_STATE_RUNNING, 70 | RECOVER_STATE_FAILED, 71 | RECOVER_STATE_STOPPED, 72 | RECOVER_STATE_UNRECOVERABLE, 73 | }; 74 | #define NODE_NUM_STATES 3 /* only the first 3 states used by matahari.cpp */ 75 | 76 | typedef void (*recover_restart_fn_t)(void* inst); 77 | typedef void (*recover_escalate_fn_t)(void* inst); 78 | typedef void (*recover_state_changing_fn_t)(void* inst, 79 | enum recover_state from, 80 | enum recover_state to); 81 | struct recover { 82 | void * instance; 83 | enum recover_state state; 84 | int num_failures; 85 | int failure_period; 86 | qb_util_stopwatch_t *sw; 87 | recover_restart_fn_t restart; 88 | recover_escalate_fn_t escalate; 89 | recover_state_changing_fn_t state_changing; 90 | }; 91 | void recover_init(struct recover* r, 92 | const char * escalation_failures, 93 | const char * escalation_period, 94 | recover_restart_fn_t recover_restart_fn, 95 | recover_escalate_fn_t recover_escalate_fn, 96 | recover_state_changing_fn_t recover_state_changing_fn); 97 | 98 | void recover_state_set(struct recover* r, enum recover_state state); 99 | 100 | struct assembly { 101 | char *name; 102 | char *uuid; 103 | char *address; 104 | char instance_id[64]; 105 | char image_id[64]; 106 | struct application *application; 107 | qb_map_t *resource_map; 108 | int fd; 109 | void *transport; 110 | qb_util_stopwatch_t *sw_instance_create; 111 | qb_util_stopwatch_t *sw_instance_connected; 112 | struct recover recover; 113 | }; 114 | 115 | struct reference_param { 116 | char *name; 117 | char *assembly; 118 | char *parameter; 119 | xmlNode *xmlnode; 120 | }; 121 | 122 | struct resource { 123 | char *name; 124 | char *type; 125 | char *rclass; 126 | char *rprovider; 127 | struct assembly *assembly; 128 | struct pe_operation *monitor_op; 129 | qb_loop_timer_handle monitor_timer; 130 | struct recover recover; 131 | qb_map_t *ref_params_map; 132 | }; 133 | 134 | void resource_action_completed(struct pe_operation *op, enum ocf_exitcode rc); 135 | 136 | void cape_init(int debug); 137 | 138 | int cape_load(const char * name); 139 | 140 | void cape_load_from_buffer(const char *buffer); 141 | 142 | int32_t cape_admin_init(void); 143 | 144 | void cape_admin_event_send(const char *app, 145 | struct assembly *a, 146 | struct resource *r, 147 | const char *state, 148 | const char *reason); 149 | void cape_admin_fini(void); 150 | 151 | int32_t instance_create(struct assembly *assembly); 152 | 153 | int instance_destroy(struct assembly *assembly); 154 | 155 | void cape_exit(void); 156 | 157 | #ifdef __cplusplus 158 | } 159 | #endif 160 | #endif /* CAPE_H_DEFINED */ 161 | -------------------------------------------------------------------------------- /src/capeadmin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #include "config.h" 22 | 23 | #ifdef HAVE_FCNTL_H 24 | #include 25 | #endif /* HAVE_FCNTL_H */ 26 | 27 | #ifdef HAVE_SYS_SOCKET_H 28 | #include 29 | #endif /* HAVE_SYS_SOCKET_H */ 30 | 31 | #ifdef HAVE_SYS_UN_H 32 | #include 33 | #endif /* HAVE_SYS_UN_H */ 34 | 35 | #ifdef HAVE_SYS_STAT_H 36 | #include 37 | #endif 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "cape.h" 46 | 47 | 48 | #ifndef UNIX_PATH_MAX 49 | #define UNIX_PATH_MAX 108 50 | #endif /* UNIX_PATH_MAX */ 51 | 52 | static int sockfd = -1; 53 | 54 | static void 55 | event_spammer(void *data, size_t len) 56 | { 57 | ssize_t rc; 58 | ssize_t processed = 0; 59 | 60 | if (sockfd < 0) { 61 | return; 62 | } 63 | retry_send: 64 | rc = send(sockfd, data, len, MSG_NOSIGNAL); 65 | if (rc == -1) { 66 | qb_perror(LOG_ERR, "event_spammer"); 67 | return; 68 | } 69 | 70 | processed += rc; 71 | if (processed != len) { 72 | goto retry_send; 73 | } 74 | } 75 | 76 | void 77 | cape_admin_event_send(const char *app, 78 | struct assembly *a, 79 | struct resource *r, 80 | const char *state, 81 | const char *reason) 82 | { 83 | xmlNode *xevent; 84 | xmlNode *xapp; 85 | xmlNode *xnode; 86 | xmlNode *xresource; 87 | xmlNode *ev_level; 88 | xmlChar *mem_buf; 89 | int mem_size; 90 | xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); 91 | 92 | xevent = xmlNewNode(NULL, BAD_CAST "event"); 93 | xmlDocSetRootElement(doc, xevent); 94 | 95 | xapp = xmlNewChild(xevent, NULL, BAD_CAST "application", NULL); 96 | xmlNewProp(xapp, BAD_CAST "name", BAD_CAST app); 97 | ev_level = xapp; 98 | if (a) { 99 | xnode = xmlNewChild(xapp, NULL, BAD_CAST "node", NULL); 100 | xmlNewProp(xnode, BAD_CAST "name", BAD_CAST a->name); 101 | ev_level = xnode; 102 | } 103 | if (a && r) { 104 | xresource = xmlNewChild(xnode, NULL, BAD_CAST "resource", NULL); 105 | xmlNewProp(xresource, BAD_CAST "name", BAD_CAST r->name); 106 | ev_level = xresource; 107 | } 108 | xmlNewChild(ev_level, NULL, BAD_CAST "state", BAD_CAST state); 109 | xmlNewChild(ev_level, NULL, BAD_CAST "reason", BAD_CAST reason); 110 | 111 | xmlDocDumpMemory(doc, &mem_buf, &mem_size); 112 | 113 | event_spammer(mem_buf, mem_size); 114 | 115 | xmlFree(mem_buf); 116 | xmlFreeDoc(doc); 117 | } 118 | 119 | static int32_t 120 | _fd_nonblock_cloexec_set(int32_t fd) 121 | { 122 | int32_t res = 0; 123 | int32_t oldflags = fcntl(fd, F_GETFD, 0); 124 | 125 | if (oldflags < 0) { 126 | oldflags = 0; 127 | } 128 | oldflags |= FD_CLOEXEC; 129 | res = fcntl(fd, F_SETFD, oldflags); 130 | if (res == -1) { 131 | res = -errno; 132 | qb_perror(LOG_ERR, 133 | "Could not set close-on-exit on fd:%d", fd); 134 | return res; 135 | } 136 | 137 | res = fcntl(fd, F_SETFL, O_NONBLOCK); 138 | if (res == -1) { 139 | res = -errno; 140 | qb_log(LOG_ERR, "Could not set non-blocking on fd:%d", fd); 141 | } 142 | 143 | return res; 144 | } 145 | 146 | static int32_t 147 | _unix_sock_connect(const char *socket_name, int32_t * sock_pt) 148 | { 149 | int32_t request_fd; 150 | struct sockaddr_un address; 151 | int32_t res = 0; 152 | 153 | request_fd = socket(PF_LOCAL, SOCK_STREAM, 0); 154 | if (request_fd == -1) { 155 | return -errno; 156 | } 157 | res = _fd_nonblock_cloexec_set(request_fd); 158 | if (res < 0) { 159 | goto error_connect; 160 | } 161 | 162 | memset(&address, 0, sizeof(struct sockaddr_un)); 163 | address.sun_family = AF_UNIX; 164 | 165 | snprintf(address.sun_path, UNIX_PATH_MAX - 1, "%s", socket_name); 166 | if (connect(request_fd, (struct sockaddr *)&address, 167 | sizeof(address)) == -1) { 168 | res = -errno; 169 | goto error_connect; 170 | } 171 | 172 | *sock_pt = request_fd; 173 | return 0; 174 | 175 | error_connect: 176 | close(request_fd); 177 | *sock_pt = -1; 178 | 179 | return res; 180 | } 181 | 182 | int32_t 183 | cape_admin_init(void) 184 | { 185 | return _unix_sock_connect("pacemaker-cloud-cped", &sockfd); 186 | } 187 | 188 | void 189 | cape_admin_fini(void) 190 | { 191 | close(sockfd); 192 | } 193 | 194 | -------------------------------------------------------------------------------- /src/caped.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Steven Dake 5 | * Angus Salkeld 6 | * 7 | * This file is part of pacemaker-cloud. 8 | * 9 | * pacemaker-cloud is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * pacemaker-cloud is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with pacemaker-cloud. If not, see . 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "cape.h" 29 | 30 | #define LOG_TAG_QPID 1 31 | #define LOG_TAG_GLIB 2 32 | #define LOG_TAG_PCMK 3 33 | 34 | static const char *my_tags_stringify(uint32_t tags) 35 | { 36 | if (qb_bit_is_set(tags, QB_LOG_TAG_LIBQB_MSG_BIT)) { 37 | return "QB "; 38 | } else if (tags == LOG_TAG_QPID) { 39 | return "QPID "; 40 | } else if (tags == LOG_TAG_GLIB) { 41 | return "GLIB "; 42 | } else if (tags == LOG_TAG_PCMK) { 43 | return "PCMK "; 44 | } else { 45 | return "MAIN "; 46 | } 47 | } 48 | 49 | static void 50 | my_glib_handler(const gchar *log_domain, GLogLevelFlags flags, const gchar *message, gpointer user_data) 51 | { 52 | uint32_t log_level = LOG_WARNING; 53 | GLogLevelFlags msg_level = (GLogLevelFlags)(flags & G_LOG_LEVEL_MASK); 54 | 55 | switch (msg_level) { 56 | case G_LOG_LEVEL_CRITICAL: 57 | case G_LOG_FLAG_FATAL: 58 | log_level = LOG_CRIT; 59 | break; 60 | case G_LOG_LEVEL_ERROR: 61 | log_level = LOG_ERR; 62 | break; 63 | case G_LOG_LEVEL_MESSAGE: 64 | log_level = LOG_NOTICE; 65 | break; 66 | case G_LOG_LEVEL_INFO: 67 | log_level = LOG_INFO; 68 | break; 69 | case G_LOG_LEVEL_DEBUG: 70 | log_level = LOG_DEBUG; 71 | break; 72 | 73 | case G_LOG_LEVEL_WARNING: 74 | case G_LOG_FLAG_RECURSION: 75 | case G_LOG_LEVEL_MASK: 76 | log_level = LOG_WARNING; 77 | break; 78 | } 79 | 80 | qb_log_from_external_source(__FUNCTION__, __FILE__, "%s", 81 | log_level, __LINE__, 82 | LOG_TAG_GLIB, message); 83 | } 84 | 85 | static void 86 | show_usage(const char *name) 87 | { 88 | printf("usage: \n"); 89 | printf("%s [cloud app name]\n", name); 90 | printf("\n"); 91 | printf(" options:\n"); 92 | printf("\n"); 93 | printf(" -v verbose\n"); 94 | printf(" -g debug\n"); 95 | printf(" -o log to stdout\n"); 96 | printf(" -h show this help text\n"); 97 | printf("\n"); 98 | } 99 | 100 | static int32_t 101 | signal_int(int32_t rsignal, void *data) 102 | { 103 | qb_log(LOG_INFO, "exiting on signal %d", rsignal); 104 | cape_exit(); 105 | qb_loop_stop(NULL); 106 | return -1; 107 | } 108 | 109 | int 110 | main(int argc, char * argv[]) 111 | { 112 | const char *options = "vhodg"; 113 | int32_t opt; 114 | int32_t do_stdout = QB_FALSE; 115 | int daemonize = 0; 116 | int debug = 0; 117 | int loglevel = LOG_INFO; 118 | qb_loop_t *loop; 119 | char *cloud_app = NULL; 120 | char *prog_name = strrchr(argv[0], '/'); 121 | 122 | if (prog_name) { 123 | prog_name++; 124 | } else { 125 | prog_name = argv[0]; 126 | } 127 | 128 | while ((opt = getopt(argc, argv, options)) != -1) { 129 | switch (opt) { 130 | case 'd': 131 | daemonize = QB_TRUE; 132 | break; 133 | case 'o': 134 | do_stdout = QB_TRUE; 135 | break; 136 | case 'v': 137 | loglevel++; 138 | break; 139 | case 'g': 140 | debug++; 141 | break; 142 | case 'h': 143 | default: 144 | show_usage(argv[0]); 145 | exit(0); 146 | break; 147 | } 148 | } 149 | 150 | if (optind < argc) { 151 | cloud_app = argv[optind]; 152 | } else { 153 | show_usage(prog_name); 154 | exit(EXIT_FAILURE); 155 | } 156 | 157 | qb_log_init(prog_name, LOG_DAEMON, loglevel); 158 | qb_log_format_set(QB_LOG_SYSLOG, "%g[%p] %b"); 159 | qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP, LOG_INFO - loglevel); 160 | if (!daemonize || do_stdout) { 161 | qb_log_filter_ctl(QB_LOG_STDOUT, QB_LOG_FILTER_ADD, 162 | QB_LOG_FILTER_FILE, "*", loglevel); 163 | qb_log_format_set(QB_LOG_STDOUT, "%g[%6p] %b"); 164 | qb_log_ctl(QB_LOG_STDOUT, QB_LOG_CONF_ENABLED, QB_TRUE); 165 | } 166 | pe_log_init(LOG_TAG_PCMK, loglevel); 167 | qb_log_tags_stringify_fn_set(my_tags_stringify); 168 | g_log_set_default_handler(my_glib_handler, NULL); 169 | 170 | qb_enter(); 171 | loop = qb_loop_create(); 172 | 173 | qb_loop_signal_add(NULL, QB_LOOP_LOW, SIGINT, NULL, signal_int, NULL); 174 | 175 | cape_init(debug); 176 | 177 | cape_admin_init(); 178 | 179 | if (cape_load(cloud_app) != 0) { 180 | qb_perror(LOG_ERR, "failed to load the configuration"); 181 | qb_log_fini(); 182 | exit(EXIT_FAILURE); 183 | } 184 | 185 | qb_loop_run(loop); 186 | 187 | cape_admin_fini(); 188 | 189 | qb_leave(); 190 | 191 | return 0; 192 | } 193 | -------------------------------------------------------------------------------- /src/cim_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Author: Zane Bitter 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #ifndef CIM_SERVICE_H_DEFINED 23 | #define CIM_SERVICE_H_DEFINED 24 | 25 | /** 26 | * Open a connection to the specified CIM server. 27 | * @param server the server to connect to 28 | * @return a handle to a CIM connection. 29 | */ 30 | void *cim_service_connect(const char *server); 31 | 32 | /** 33 | * Close the connection to a CIM server. 34 | * @param transport handle to the connection 35 | */ 36 | void cim_service_disconnect(void *transport); 37 | 38 | /** 39 | * Query the specified service to see if it is running. 40 | * @param transport handle to the connection 41 | * @param service the name of the service to query 42 | * @return 1 if the service is started, 0 if it is not started, negative if 43 | * an error occurred. 44 | */ 45 | int cim_service_started(void *transport, const char *service); 46 | 47 | /** 48 | * Start the specified service. 49 | * @param transport handle to the connection 50 | * @param service the name of the service to start 51 | * @return 0 on success, negative on failure. 52 | */ 53 | int cim_service_start(void *transport, const char *service); 54 | 55 | /** 56 | * Stop the specified service. 57 | * @param transport handle to the connection 58 | * @param service the name of the service to stop 59 | * @return 0 on success, negative on failure. 60 | */ 61 | int cim_service_stop(void *transport, const char *service); 62 | 63 | #endif /* CIM_SERVICE_H_DEFINED */ 64 | -------------------------------------------------------------------------------- /src/common_agent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010-2011 Red Hat, Inc. 3 | * 4 | * Author: Andrew Beekhof 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2.1 of the License, or (at your option) any later version. 10 | * 11 | * This software is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public 17 | * License along with this library; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | */ 20 | #ifndef COMMON_AGENT_H_DEFINED 21 | #define COMMON_AGENT_H_DEFINED 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | #include "mainloop.h" 34 | 35 | 36 | /* The _Noreturn keyword of draft C1X. */ 37 | #ifndef _Noreturn 38 | # if (3 <= __GNUC__ || (__GNUC__ == 2 && 8 <= __GNUC_MINOR__) \ 39 | || 0x5110 <= __SUNPRO_C) 40 | # define _Noreturn __attribute__ ((__noreturn__)) 41 | # elif 1200 <= _MSC_VER 42 | # define _Noreturn __declspec (noreturn) 43 | # else 44 | # define _Noreturn 45 | # endif 46 | #endif 47 | 48 | using namespace std; 49 | using namespace qmf; 50 | using namespace qpid::log; 51 | 52 | #include "org/pacemakercloud/QmfPackage.h" 53 | 54 | class CommonAgent 55 | { 56 | private: 57 | mainloop_qmf_session_t *qmf_source; 58 | Selector log_selector; 59 | const char* proc_name; 60 | int broker_port; 61 | string broker_host; 62 | string broker_username; 63 | string broker_password; 64 | string broker_service; 65 | bool broker_gssapi; 66 | 67 | protected: 68 | list _non_opt_args; 69 | int http_port_; 70 | int conductor_port_; 71 | string conductor_host_; 72 | string conductor_auth_; 73 | 74 | public: 75 | qb_loop_t *mainloop; 76 | CommonAgent() : broker_host("localhost"), broker_port(49000), broker_gssapi(false) {}; 77 | ~CommonAgent() {}; 78 | AgentSession agent_session; 79 | qpid::messaging::Connection agent_connection; 80 | qmf::org::pacemakercloud::PackageDefinition package; 81 | 82 | virtual void setup(void) {}; 83 | virtual bool event_dispatch(AgentEvent *event) { return false; }; 84 | virtual void signal_handler(int32_t rsignal); 85 | int init(int argc, char **argv, const char *proc_name); 86 | void run(); 87 | void usage(); 88 | void unsupported( int arg ) _Noreturn; 89 | virtual int http_port(void) { return 0; }; 90 | void http_port(int port) { this->http_port_ = port; }; 91 | virtual int conductor_port(void) { return 0; }; 92 | void conductor_port(int port) { this->conductor_port_ = port; }; 93 | virtual const char* conductor_host(void) { return NULL; }; 94 | void conductor_host(const char* host) { this->conductor_host_ = host; }; 95 | virtual const char* conductor_auth(void) { return NULL; }; 96 | void conductor_auth(const char* auth) { this->conductor_auth_ = auth; }; 97 | }; 98 | 99 | #endif /* COMMON_AGENT_H_DEFINED */ 100 | -------------------------------------------------------------------------------- /src/config_loader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #include 22 | #include 23 | 24 | #include "config_loader.h" 25 | 26 | int32_t 27 | config_get(std::string& uuid, xmlDoc** doc) 28 | { 29 | std::string filename = "/var/run/"; 30 | filename += uuid + ".xml"; 31 | 32 | *doc = xmlParseFile(filename.c_str()); 33 | if (*doc == NULL) { 34 | qb_log(LOG_ERR, "failed to load %s", filename.c_str()); 35 | return -1; 36 | } 37 | qb_log(LOG_INFO, "loaded %s", filename.c_str()); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/config_loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #ifndef _CONFIG_LOADER_H_ 22 | #define _CONFIG_LOADER_H_ 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | /** 29 | * get the list of deployable to be managed by cpe 30 | * 31 | * @return return code 32 | */ 33 | int32_t 34 | config_list(); 35 | 36 | /** 37 | * get the XML config for a given deployable uuid 38 | * 39 | * @param uuid(in) deployable uuid 40 | * @param xml(out) xml object 41 | * @return return code 42 | */ 43 | int32_t 44 | config_get(std::string& uuid, xmlDoc** doc); 45 | 46 | #endif /* _CONFIG_LOADER_H_ */ 47 | 48 | -------------------------------------------------------------------------------- /src/cpe_agent.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: 5 | * Steven Dake 6 | * Angus Salkeld 7 | * 8 | * This file is part of pacemaker-cloud. 9 | * 10 | * pacemaker-cloud is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * pacemaker-cloud is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with pacemaker-cloud. If not, see . 22 | */ 23 | 24 | #include "config.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "mainloop.h" 33 | 34 | #include "cpe_agent.h" 35 | #include "cpe_httpd.h" 36 | #include "cpe_impl.h" 37 | 38 | using namespace std; 39 | using namespace qmf; 40 | 41 | 42 | CpeAgent::CpeAgent() 43 | { 44 | this->http_port(8888); 45 | this->conductor_host("localhost"); 46 | this->conductor_port(3000); 47 | this->conductor_auth("admin:password"); 48 | } 49 | 50 | void CpeAgent::impl_set(CpeImpl *impl) 51 | { 52 | this->impl = impl; 53 | } 54 | 55 | int 56 | CpeAgent::console_handler(void) 57 | { 58 | ConsoleEvent event; 59 | 60 | if (console_session->nextEvent(event)) { 61 | cout << "event" <getConnectedBrokerAgent().getName()) { 66 | extra = " [Connected Broker]"; 67 | cout << "Agent Added: " << event.getAgent().getName() << extra << endl; 68 | } 69 | } 70 | } 71 | 72 | return QB_TRUE; 73 | } 74 | 75 | int 76 | main(int argc, char **argv) 77 | { 78 | CpeAgent agent; 79 | CpeImpl impl; 80 | int32_t rc; 81 | 82 | agent.impl_set(&impl); 83 | rc = agent.init(argc, argv, "cpe"); 84 | 85 | CpeHttpd http(agent.http_port()); 86 | http.impl_set(&impl); 87 | bool http_status = http.run(); 88 | 89 | if (http_status) { 90 | agent.register_hook(); 91 | } 92 | 93 | if (rc == 0) { 94 | agent.run(); 95 | } 96 | return rc; 97 | } 98 | 99 | void 100 | CpeAgent::setup(void) 101 | { 102 | _cpe = qmf::Data(package.data_cpe); 103 | agent_session.addData(_cpe, "cpe"); 104 | } 105 | 106 | bool 107 | CpeAgent::event_dispatch(AgentEvent *event) 108 | { 109 | const string& methodName(event->getMethodName()); 110 | uint32_t rc = 0; 111 | string uuid; 112 | string monitor; 113 | 114 | switch (event->getType()) { 115 | case qmf::AGENT_METHOD: 116 | if (methodName == "deployable_start") { 117 | uuid = event->getArguments()["uuid"].asString(); 118 | monitor = event->getArguments()["monitor"].asString(); 119 | 120 | rc = impl->dep_start(uuid, monitor); 121 | 122 | event->addReturnArgument("rc", rc); 123 | 124 | } else if (methodName == "deployable_stop") { 125 | uuid = event->getArguments()["uuid"].asString(); 126 | monitor = event->getArguments()["monitor"].asString(); 127 | 128 | rc = impl->dep_stop(uuid, monitor); 129 | 130 | event->addReturnArgument("rc", rc); 131 | } else if (methodName == "deployable_reload") { 132 | uuid = event->getArguments()["uuid"].asString(); 133 | monitor = event->getArguments()["monitor"].asString(); 134 | 135 | rc = impl->dep_reload(uuid, monitor); 136 | 137 | event->addReturnArgument("rc", rc); 138 | } 139 | if (rc == 0) { 140 | agent_session.methodSuccess(*event); 141 | } else { 142 | agent_session.raiseException(*event, "oops"); 143 | } 144 | break; 145 | 146 | default: 147 | break; 148 | } 149 | return true; 150 | } 151 | -------------------------------------------------------------------------------- /src/cpe_agent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #ifndef _CPE_H_ 23 | #define _CPE_H_ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include "org/pacemakercloud/QmfPackage.h" 32 | #include "common_agent.h" 33 | #include "cpe_impl.h" 34 | 35 | class CpeAgent : public CommonAgent 36 | { 37 | private: 38 | qmf::Data _cpe; 39 | qpid::messaging::Connection *console_connection; 40 | qmf::ConsoleSession *console_session; 41 | CpeImpl *impl; 42 | string conductor_hook; 43 | 44 | public: 45 | CpeAgent(); 46 | ~CpeAgent() {}; 47 | void impl_set(CpeImpl *impl); 48 | void setup(void); 49 | bool event_dispatch(AgentEvent *event); 50 | int console_handler(void); 51 | using CommonAgent::http_port; 52 | int http_port(void) { return this->http_port_; }; 53 | using CommonAgent::conductor_port; 54 | int conductor_port(void) { return this->conductor_port_; }; 55 | using CommonAgent::conductor_host; 56 | const char* conductor_host(void) { return this->conductor_host_.c_str(); }; 57 | using CommonAgent::conductor_auth; 58 | const char* conductor_auth(void) { return this->conductor_auth_.c_str(); }; 59 | 60 | /* Register our http server with conductor. */ 61 | bool register_hook(void); 62 | }; 63 | #endif /* _CPE_H_ */ 64 | -------------------------------------------------------------------------------- /src/cpe_agent_register.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "cpe_agent.h" 7 | 8 | typedef struct curl_recv_info { 9 | char *data; 10 | size_t size; 11 | } curl_recv_info_t; 12 | 13 | static size_t 14 | curl_recv(void *ptr, size_t size, size_t nmemb, void *userp) 15 | { 16 | size_t realsize = size * nmemb; 17 | curl_recv_info_t *mem = (curl_recv_info_t *)userp; 18 | 19 | mem->data = (char *)realloc(mem->data, mem->size + realsize + 1); 20 | if (!mem->data) { 21 | fprintf(stderr, "couldn't allocate curl recv buffer\n"); 22 | exit(EXIT_FAILURE); 23 | } 24 | 25 | memcpy(&(mem->data[mem->size]), ptr, realsize); 26 | mem->size += realsize; 27 | mem->data[mem->size] = 0; 28 | 29 | return realsize; 30 | } 31 | 32 | static size_t 33 | curl_process_header(void *contents, size_t size, size_t nmemb, void *userp) 34 | { 35 | size_t realsize = size * nmemb; 36 | char *ptr = (char *)contents; 37 | char **location = (char **)userp; 38 | 39 | if (strncmp((char *)ptr, "Location:", 9) == 0) { 40 | *location = strndup(ptr+10, size-10); 41 | if (!*location) { 42 | fprintf(stderr, "couldn't allocate Location: buffer\n"); 43 | exit(EXIT_FAILURE); 44 | } 45 | } 46 | 47 | return realsize; 48 | } 49 | 50 | /* Register our http server with conductor, 51 | * and record the correspond hook returned by conductor. 52 | * 53 | * TODO: This is a synchronous function, and requires 54 | * conductor to be already started. Support retries 55 | * to remove the ordering dependency. */ 56 | 57 | bool CpeAgent::register_hook(void) 58 | { 59 | bool status = false; 60 | 61 | CURL* curl = curl_easy_init(); 62 | if (!curl) 63 | return false; 64 | 65 | /* TODO: change localhost below to the actual hostname, 66 | * if conductor host is not localhost. */ 67 | char *hook_location = NULL; 68 | asprintf(&hook_location, 69 | "" 70 | " https://%s:%d/pacemaker-cloud/api" 71 | " 1" 72 | "", 73 | "localhost", this->http_port()); 74 | if (!hook_location) { 75 | fprintf(stderr, "Couldn't allocate hook_location\n"); 76 | return false; 77 | } 78 | 79 | curl_recv_info_t response = {0,}; 80 | char *conductor_location = NULL; 81 | 82 | struct curl_slist *headerlist = NULL; 83 | char *conductor_url; 84 | asprintf(&conductor_url, "http://%s:%d/conductor/api/hooks", 85 | this->conductor_host(), this->conductor_port()); 86 | if (!conductor_url) { 87 | fprintf(stderr, "Couldn't allocate conductor_url\n"); 88 | free(hook_location); 89 | return false; 90 | } 91 | 92 | curl_easy_setopt(curl, CURLOPT_URL, conductor_url); 93 | curl_easy_setopt(curl, CURLOPT_POSTFIELDS, hook_location); 94 | headerlist = curl_slist_append(headerlist, "Content-Type: application/xml"); 95 | headerlist = curl_slist_append(headerlist, "Accept: application/xml"); 96 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); 97 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "cpe-agent/1.0"); 98 | 99 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_recv); 100 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); 101 | 102 | curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_process_header); 103 | curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &conductor_location); 104 | 105 | curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 106 | curl_easy_setopt(curl, CURLOPT_USERPWD, this->conductor_auth()); 107 | 108 | CURLcode res = curl_easy_perform(curl); 109 | 110 | if (res) { 111 | fprintf(stderr, "Error registering hook with conductor: %s\n", curl_easy_strerror(res)); 112 | } else { 113 | long http_code = 0; 114 | curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); 115 | if (http_code >= 400 || !conductor_location) { 116 | const char* message=""; 117 | if (http_code < 400) 118 | message = " no Location: header"; 119 | else if (http_code == 401) 120 | message = " (Unauthorized)"; 121 | fprintf(stderr, "Error registering hook with conductor: %ld%s\n", http_code, message); 122 | if (response.data && *(response.data)) 123 | fprintf(stderr, "%s\n", response.data); 124 | } else { 125 | status = true; 126 | this->conductor_hook = conductor_location; 127 | /* We currently ignore the confirmation xml in the body (response.data) 128 | * and just rely on the location. */ 129 | fprintf(stderr, "HOOK [info] %s\n", this->conductor_hook.c_str()); 130 | } 131 | } 132 | 133 | free(conductor_location); 134 | free(response.data); 135 | curl_easy_cleanup(curl); 136 | free(conductor_url); 137 | curl_slist_free_all(headerlist); 138 | free(hook_location); 139 | 140 | return status; 141 | } 142 | -------------------------------------------------------------------------------- /src/cpe_httpd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #ifndef _CPE_HTTPD_H_ 23 | #define _CPE_HTTPD_H_ 24 | 25 | #include 26 | #include 27 | 28 | class CpeHttpd { 29 | private: 30 | struct MHD_Daemon *daemon; 31 | CpeImpl *impl; 32 | const int port; 33 | 34 | public: 35 | CpeHttpd(int port); 36 | ~CpeHttpd(); 37 | 38 | bool run(void); 39 | void impl_set(CpeImpl *impl); 40 | CpeImpl * impl_get(void) {return impl;}; 41 | }; 42 | 43 | #endif // _CPE_HTTPD_H_ 44 | -------------------------------------------------------------------------------- /src/cpe_impl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "cpe_impl.h" 29 | #include "init-dbus.h" 30 | #include "mainloop.h" 31 | 32 | using namespace std; 33 | 34 | CpeImpl::CpeImpl() 35 | { 36 | dbus_init(); 37 | } 38 | 39 | CpeImpl::~CpeImpl() 40 | { 41 | // TODO Auto-generated destructor stub 42 | } 43 | 44 | uint32_t 45 | CpeImpl::dep_start(string& dep_uuid, string& dep_monitor) 46 | { 47 | int32_t rc = init_job_start(dep_monitor.c_str(), dep_uuid.c_str()); 48 | 49 | if (rc == 0) { 50 | qb_log(LOG_INFO, "started dped instance=%s", dep_uuid.c_str()); 51 | return 0; 52 | } else { 53 | errno = -rc; 54 | qb_perror(LOG_ERR, "Failed to start dped instance=%s", dep_uuid.c_str()); 55 | return -rc; 56 | } 57 | } 58 | 59 | uint32_t 60 | CpeImpl::dep_reload(string& dep_uuid, string& dep_monitor) 61 | { 62 | int32_t rc = init_job_reload(dep_monitor.c_str(), dep_uuid.c_str()); 63 | 64 | if (rc == 0) { 65 | qb_log(LOG_INFO, "reloaded dped instance=%s", dep_uuid.c_str()); 66 | return 0; 67 | } else { 68 | errno = -rc; 69 | qb_perror(LOG_ERR, "Failed to reload dped instance=%s", dep_uuid.c_str()); 70 | return -rc; 71 | } 72 | } 73 | 74 | uint32_t 75 | CpeImpl::dep_stop(string& dep_uuid, string& dep_monitor) 76 | { 77 | int32_t rc = init_job_stop(dep_monitor.c_str(), dep_uuid.c_str()); 78 | 79 | if (rc == 0) { 80 | qb_log(LOG_INFO, "stopped dped instance=%s", dep_uuid.c_str()); 81 | return 0; 82 | } else { 83 | errno = -rc; 84 | qb_perror(LOG_ERR, "Failed to stop dped instance=%s", dep_uuid.c_str()); 85 | return -rc; 86 | } 87 | } 88 | 89 | uint32_t 90 | CpeImpl::dep_list(std::list * list) 91 | { 92 | return 0; //TODO list deployables 93 | } 94 | -------------------------------------------------------------------------------- /src/cpe_impl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #ifndef CPE_IMPL_H_ 23 | #define CPE_IMPL_H_ 24 | 25 | #include 26 | #include 27 | #include "mainloop.h" 28 | #include 29 | #include 30 | 31 | class CpeImpl { 32 | public: 33 | CpeImpl(); 34 | virtual ~CpeImpl(); 35 | 36 | uint32_t dep_start(std::string& uuid, std::string& monitor); 37 | uint32_t dep_stop(std::string& uuid, std::string& monitor); 38 | uint32_t dep_reload(std::string& uuid, std::string& monitor); 39 | uint32_t dep_list(std::list * list); 40 | }; 41 | 42 | #endif /* CPE_IMPL_H_ */ 43 | -------------------------------------------------------------------------------- /src/cped2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (C) 2012 Red Hat, Inc. 4 | # 5 | # Author: Angus Salkeld 6 | # 7 | # This program is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU General Public License 9 | # as published by the Free Software Foundation; either version 2 10 | # of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | # 20 | import functools 21 | import errno 22 | import socket 23 | from tornado.netutil import bind_unix_socket 24 | from tornado.ioloop import IOLoop 25 | #import httpserver 26 | 27 | def main(): 28 | 29 | def handle_message(sock, fd, events): 30 | if IOLoop.ERROR & events: 31 | IOLoop.instance().remove_handler(fd) 32 | sock.close() 33 | print('closing connection') 34 | return 35 | 36 | print('received_message') 37 | chunk = sock.recv(1024) 38 | print(chunk) 39 | 40 | def handle_connection(sock, fd, events): 41 | print('handling new connection') 42 | try: 43 | (connection, address) = sock.accept() 44 | except socket.error, e: 45 | if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN): 46 | return 47 | raise 48 | 49 | message_callback = functools.partial(handle_message, connection) 50 | IOLoop.instance().add_handler(connection.fileno(), 51 | message_callback, 52 | IOLoop.ERROR|IOLoop.READ) 53 | 54 | unix_socket = bind_unix_socket('pacemaker-cloud-cped') 55 | accept_callback = functools.partial(handle_connection, unix_socket) 56 | IOLoop.instance().add_handler(unix_socket.fileno(), 57 | accept_callback, 58 | IOLoop.READ) 59 | 60 | IOLoop.instance().start() 61 | 62 | if __name__ == '__main__': 63 | main() 64 | 65 | -------------------------------------------------------------------------------- /src/deltacloud.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Steven Dake 5 | * Angus Salkeld 6 | * 7 | * This file is part of pacemaker-cloud. 8 | * 9 | * pacemaker-cloud is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * pacemaker-cloud is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with pacemaker-cloud. If not, see . 21 | */ 22 | 23 | #include 24 | #include 25 | 26 | #include "config.h" 27 | 28 | #include "cape.h" 29 | #include "trans.h" 30 | 31 | /* 32 | * External API 33 | */ 34 | void instance_state_get(char *instance_id, 35 | void (*completion_func)(char *status, char *ip_addr, void *data), 36 | void *data) 37 | { 38 | struct deltacloud_api api; 39 | struct deltacloud_instance instance; 40 | int rc; 41 | 42 | rc = deltacloud_initialize(&api, "http://localhost:3001/api", "dep-wp", ""); 43 | if (rc < 0) { 44 | qb_log(LOG_ERR, "Failed to initialize libdeltacloud: %s", 45 | deltacloud_get_last_error_string()); 46 | 47 | qb_leave(); 48 | return; 49 | } 50 | 51 | rc = deltacloud_get_instance_by_id(&api, instance_id, &instance); 52 | if (strcmp(instance.state, "RUNNING") == 0 && instance.private_addresses->address) { 53 | completion_func("ACTIVE", instance.private_addresses->address, data); 54 | } else { 55 | completion_func("PENDING", NULL, data); 56 | } 57 | } 58 | 59 | void instance_create_from_image_id(char *image_id, 60 | void (*completion_func)(char *instance_id, void *data), 61 | void *data) 62 | { 63 | struct deltacloud_api api; 64 | char *instance_id; 65 | int rc; 66 | 67 | rc = deltacloud_initialize(&api, "http://localhost:3001/api", "dep-wp", ""); 68 | if (rc < 0) { 69 | qb_log(LOG_ERR, "Failed to initialize libdeltacloud: %s", 70 | deltacloud_get_last_error_string()); 71 | 72 | qb_leave(); 73 | return; 74 | } 75 | rc = deltacloud_create_instance(&api, image_id, NULL, 0, &instance_id); 76 | if (rc < 0) { 77 | qb_log(LOG_ERR, "Failed to initialize libdeltacloud: %s", 78 | deltacloud_get_last_error_string()); 79 | 80 | qb_leave(); 81 | return; 82 | } 83 | completion_func(instance_id, data); 84 | deltacloud_free(&api); 85 | } 86 | 87 | 88 | void image_id_get(char *image_name, 89 | void (*completion_func)(char *image_id, void *data), 90 | void *data) 91 | { 92 | static struct deltacloud_api api; 93 | struct deltacloud_image *images_head; 94 | struct deltacloud_image *images; 95 | int rc; 96 | 97 | qb_enter(); 98 | 99 | if (deltacloud_initialize(&api, "http://localhost:3001/api", 100 | "dep-wp", "") < 0) { 101 | qb_log(LOG_ERR, "Failed to initialize libdeltacloud: %s", 102 | deltacloud_get_last_error_string()); 103 | 104 | qb_leave(); 105 | return; 106 | } 107 | rc = deltacloud_get_images(&api, &images); 108 | if (rc < 0) { 109 | qb_log(LOG_ERR, "Failed to initialize libdeltacloud: %s", 110 | deltacloud_get_last_error_string()); 111 | 112 | qb_leave(); 113 | return; 114 | } 115 | 116 | for (images_head = images; images; images = images->next) { 117 | if (strcmp(images->name, image_name) == 0) { 118 | completion_func(images->id, data); 119 | break; 120 | } 121 | } 122 | deltacloud_free_image_list(&images_head); 123 | deltacloud_free(&api); 124 | 125 | qb_leave(); 126 | } 127 | 128 | void instance_destroy_by_instance_id(char *instance_id, 129 | void (*completion_func)(void *data), 130 | void *data) 131 | { 132 | struct deltacloud_api api; 133 | struct deltacloud_instance instance; 134 | int rc; 135 | 136 | rc = deltacloud_initialize(&api, "http://localhost:3001/api", "dep-wp", ""); 137 | if (rc < 0) { 138 | qb_log(LOG_ERR, "Failed to initialize libdeltacloud: %s", 139 | deltacloud_get_last_error_string()); 140 | 141 | qb_leave(); 142 | return; 143 | } 144 | 145 | rc = deltacloud_get_instance_by_id(&api, instance_id, &instance); 146 | deltacloud_instance_destroy(&api, &instance); 147 | completion_func(data); 148 | } 149 | -------------------------------------------------------------------------------- /src/init-dbus.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010-2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #ifndef UPSTART_DBUS_H 23 | #define UPSTART_DBUS_H 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | int dbus_init(void); 35 | void dbus_fini(void); 36 | 37 | int init_job_start(const char * service, const char * instance); 38 | int init_job_stop(const char * service, const char * instance); 39 | int init_job_reload(const char * service, const char * instance); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif /* UPSTART_DBUS_H */ 46 | -------------------------------------------------------------------------------- /src/inst_ctrl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Steven Dake 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "config.h" 32 | 33 | #include "cape.h" 34 | #include "trans.h" 35 | #include "inst_ctrl.h" 36 | 37 | /* 38 | * Internal implementation 39 | */ 40 | static void instance_state_completion(char *state, char *address, void *data); 41 | 42 | static void my_instance_state_get(void *data) 43 | { 44 | struct assembly *assembly = (struct assembly *)data; 45 | instance_state_get(assembly->instance_id, instance_state_completion, data); 46 | } 47 | 48 | static void image_id_get_completion(char *image_id, void *data) 49 | { 50 | struct assembly *assembly = (struct assembly *)data; 51 | 52 | strcpy(assembly->image_id, image_id); 53 | } 54 | 55 | static void instance_create_completion(char *instance_id, void *data) 56 | { 57 | struct assembly *assembly = (struct assembly *)data; 58 | 59 | strcpy(assembly->instance_id, instance_id); 60 | } 61 | 62 | static void instance_destroy_completion(void *data) 63 | { 64 | struct assembly *assembly = (struct assembly *)data; 65 | 66 | assembly->instance_id[0] = '\0'; 67 | } 68 | 69 | static void instance_state_completion(char *state, char *address, void *data) 70 | { 71 | struct assembly *assembly = (struct assembly *)data; 72 | 73 | if (strcmp(state, "ACTIVE") == 0) { 74 | assembly->address = strdup(address); 75 | qb_util_stopwatch_stop(assembly->sw_instance_create); 76 | qb_log(LOG_INFO, "Instance '%s' with address '%s' changed to RUNNING in (%lld ms).", 77 | assembly->name, assembly->address, 78 | qb_util_stopwatch_us_elapsed_get(assembly->sw_instance_create) / 1000); 79 | qb_util_stopwatch_start(assembly->sw_instance_connected); 80 | transport_connect(assembly); 81 | } else { 82 | recover_state_set(&assembly->recover, RECOVER_STATE_UNKNOWN); 83 | qb_loop_timer_add(NULL, QB_LOOP_LOW, 84 | PENDING_TIMEOUT * QB_TIME_NS_IN_MSEC, assembly, 85 | my_instance_state_get, NULL); 86 | } 87 | } 88 | 89 | /* 90 | * External API 91 | */ 92 | int32_t instance_create(struct assembly *assembly) 93 | { 94 | qb_enter(); 95 | 96 | qb_util_stopwatch_start(assembly->sw_instance_create); 97 | image_id_get(assembly->name, image_id_get_completion, assembly); 98 | instance_create_from_image_id(assembly->image_id, instance_create_completion, assembly); 99 | qb_loop_job_add(NULL, QB_LOOP_LOW, assembly, my_instance_state_get); 100 | 101 | qb_leave(); 102 | 103 | return 0; 104 | } 105 | 106 | int instance_destroy(struct assembly *a) 107 | { 108 | qb_enter(); 109 | 110 | instance_destroy_by_instance_id(a->instance_id, 111 | instance_destroy_completion, a); 112 | 113 | qb_leave(); 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /src/inst_ctrl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Steven Dake 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #ifndef INST_CTRL_H_DEFINED 23 | #define INST_CTRL_H_DEFINED 24 | 25 | void instance_state_get(char *instance_id, 26 | void (*completion_func)(char *status, char *ip_addr, void *data), 27 | void *data); 28 | 29 | void image_id_get(char *image_name, 30 | void (*completion_func)(char *image_id, void *data), 31 | void *data); 32 | 33 | void instance_create_from_image_id(char *image_id, 34 | void (*completion_func)(char *instance_id, void *data), 35 | void *data); 36 | 37 | void instance_destroy_by_instance_id(char *instance_id, 38 | void (*completion_func)(void *data), 39 | void *data); 40 | 41 | #endif /* INST_CTRL_H_DEFINED */ 42 | -------------------------------------------------------------------------------- /src/mainloop.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Andrew Beekhof 3 | * Copyright (C) 2011 Angus Salkeldf 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2.1 of the License, or (at your option) any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | */ 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "mainloop.h" 28 | 29 | static int 30 | _poll_for_qmf_events(int32_t fd, int32_t revents, void *user_data) 31 | { 32 | mainloop_qmf_session_t *trig = (mainloop_qmf_session_t *)user_data; 33 | bool rerun = true; 34 | qb_loop_timer_handle th; 35 | 36 | if (trig->asession->nextEvent(trig->event, 37 | qpid::messaging::Duration::IMMEDIATE)) { 38 | 39 | rerun = trig->dispatch(&trig->event, trig->user_data); 40 | } 41 | if (rerun == 0) { 42 | free(trig); 43 | } 44 | } 45 | 46 | mainloop_qmf_session_t* 47 | mainloop_add_qmf_session(qmf::AgentSession *asession, 48 | bool (*dispatch)(qmf::AgentEvent *event, void* userdata), 49 | void* userdata) 50 | { 51 | mainloop_qmf_session_t *qmf_source; 52 | qmf::posix::EventNotifier *event_notifier; 53 | 54 | 55 | qmf_source = (mainloop_qmf_session_t *)calloc(1, sizeof(mainloop_qmf_session_t)); 56 | assert(qmf_source != NULL); 57 | 58 | qmf_source->dispatch = dispatch; 59 | qmf_source->user_data = userdata; 60 | qmf_source->asession = asession; 61 | event_notifier = new qmf::posix::EventNotifier(*asession); 62 | 63 | qb_loop_poll_add(NULL, QB_LOOP_MED, 64 | event_notifier->getHandle(), EPOLLIN, qmf_source, 65 | _poll_for_qmf_events); 66 | 67 | return qmf_source; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/mainloop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 Andrew Beekhof 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2.1 of the License, or (at your option) any later version. 8 | * 9 | * This software is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this library; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 | */ 18 | #ifndef MAINLOOP_H_DEFINED 19 | #define MAINLOOP_H_DEFINED 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | typedef struct mainloop_qmf_session_s 31 | { 32 | void *user_data; 33 | qmf::AgentEvent event; 34 | qmf::AgentSession *asession; 35 | bool (*dispatch)(qmf::AgentEvent *event, void* user_data); 36 | } mainloop_qmf_session_t; 37 | 38 | mainloop_qmf_session_t* 39 | mainloop_add_qmf_session(qmf::AgentSession *asession, 40 | bool (*dispatch)(qmf::AgentEvent *event, void* userdata), 41 | void* user_data); 42 | #endif 43 | 44 | #ifdef __cplusplus 45 | extern "C" { 46 | #endif 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif /* __cplusplus */ 51 | 52 | #endif /* MAINLOOP_H_DEFINED */ 53 | -------------------------------------------------------------------------------- /src/matahari.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010-2012 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #ifndef MATAHARI_H_DEFINED 22 | #define MATAHARI_H_DEFINED 23 | 24 | #include "qmf_multiplexer.h" 25 | #include "pcmk_pe.h" 26 | #include "trans.h" 27 | #include "cape.h" 28 | 29 | class Matahari { 30 | private: 31 | static const uint32_t HEARTBEAT_INIT = 1; 32 | static const uint32_t HEARTBEAT_NOT_RECEIVED = 2; 33 | static const uint32_t HEARTBEAT_OK = 3; 34 | static const uint32_t HEARTBEAT_SEQ_BAD = 4; 35 | std::string _name; 36 | std::string _uuid; 37 | uint32_t _hb_state; 38 | uint32_t _last_sequence; 39 | GTimer* _last_heartbeat; 40 | 41 | QmfObject _mh_serv; 42 | QmfObject _mh_rsc; 43 | QmfObject _mh_host; 44 | QmfMultiplexer *_mux; 45 | public: 46 | struct assembly* _node_access; 47 | 48 | qb_loop_timer_handle healthcheck_timer; 49 | void state_online_to_offline(void); 50 | void heartbeat_recv(uint32_t timestamp, uint32_t sequence); 51 | void check_state(void); 52 | void resource_action(struct pe_operation *op); 53 | uint32_t state_get(void) { return _node_access->recover.state; }; 54 | 55 | Matahari(); 56 | Matahari(struct assembly* na, QmfMultiplexer *m, 57 | std::string& name, std::string& uuid); 58 | ~Matahari(); 59 | }; 60 | #endif /* MATAHARI_H_DEFINED */ 61 | -------------------------------------------------------------------------------- /src/pcloudsh/.gitignore: -------------------------------------------------------------------------------- 1 | pcmkconfig.py 2 | -------------------------------------------------------------------------------- /src/pcloudsh/F14-x86_64-jeos-assembly.tdl: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/pcloudsh/F14-x86_64-jeos.tdl: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/pcloudsh/F15-x86_64-jeos-assembly.tdl: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/pcloudsh/F15-x86_64-jeos.tdl: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/pcloudsh/F16-x86_64-jeos-assembly.tdl: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/pcloudsh/F16-x86_64-jeos.tdl: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/pcloudsh/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010-2011 Red Hat, Inc. 2 | # 3 | # Authors: Angus Salkeld 4 | # 5 | # This file is part of pacemaker-cloud. 6 | # 7 | # pacemaker-cloud is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # pacemaker-cloud is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with pacemaker-cloud. If not, see . 19 | 20 | MAINTAINERCLEANFILES = Makefile.in 21 | 22 | rscsdir = $(datadir)/pacemaker-cloud/resource_templates 23 | rscs_DATA = resource_templates/dummy.xml \ 24 | resource_templates/httpd.xml \ 25 | resource_templates/aeolus-conductor.xml \ 26 | resource_templates/conductor-dbomatic.xml \ 27 | resource_templates/deltacloud-core.xml \ 28 | resource_templates/deltacloud-ec2-us-west-1.xml \ 29 | resource_templates/imagefactory.xml \ 30 | resource_templates/postgresql.xml \ 31 | resource_templates/condor.xml \ 32 | resource_templates/conductor-delayed_job.xml \ 33 | resource_templates/deltacloud-ec2-us-east-1.xml \ 34 | resource_templates/deltacloud-mock.xml \ 35 | resource_templates/ntpd.xml \ 36 | resource_templates/apache2.xml \ 37 | resource_templates/qpidd.xml \ 38 | resource_templates/mysqld.xml 39 | 40 | bin_SCRIPTS = pcloudsh vmlauncher 41 | 42 | pcloudshdir = $(pythondir)/pcloudsh 43 | pcloudsh_PYTHON = assembly.py deployable.py ifconfig.py cpe.py \ 44 | eventreceiver.py eventrunner.py jeos.py resource.py \ 45 | pcmkconfig.py __init__.py db_helper.py \ 46 | assembly_factory.py deployable_factory.py \ 47 | openstack_deployable.py openstack_assembly.py \ 48 | libvirt_deployable.py libvirt_assembly.py 49 | 50 | jeosdir = $(localstatedir)/lib/pacemaker-cloud/jeos/ 51 | jeos_DATA = F14-x86_64-jeos.tdl F14-x86_64-jeos-assembly.tdl \ 52 | F15-x86_64-jeos.tdl F16-x86_64-jeos.tdl \ 53 | F15-x86_64-jeos-assembly.tdl F16-x86_64-jeos-assembly.tdl \ 54 | rhel61-x86_64-jeos.tdl rhel61-x86_64-jeos-assembly.tdl \ 55 | U10-x86_64-jeos-assembly.tdl U10-x86_64-jeos.tdl 56 | 57 | assydir = $(localstatedir)/lib/pacemaker-cloud/assemblies 58 | assy_DATA = assy1.tdl assy1-F14.tdl assy1-F15.tdl assy1-F16.tdl assy1-U10.tdl \ 59 | assy-wordpress-mysql-F16.tdl assy-wordpress-F16.tdl 60 | 61 | keysdir = $(localstatedir)/lib/pacemaker-cloud/keys 62 | keys_DATA = keys/README 63 | 64 | EXTRA_DIST = $(rscs_DATA) $(jeos_DATA) $(assy_DATA) $(keys_DATA) $(bin_SCRIPTS) $(pcloudsh_PYTHON) 65 | 66 | sloccount: 67 | @echo -n "pcloudsh: " 68 | @sloccount $(pcloudsh_PYTHON) | grep Physical | cut --delimiter== --fields=2 69 | 70 | -------------------------------------------------------------------------------- /src/pcloudsh/U10-x86_64-jeos-assembly.tdl: -------------------------------------------------------------------------------- 1 | 35 | -------------------------------------------------------------------------------- /src/pcloudsh/U10-x86_64-jeos.tdl: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /src/pcloudsh/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdake/pacemaker-cloud/bbc3f96b4697f53133516ff51ba0e0a04ae9de51/src/pcloudsh/__init__.py -------------------------------------------------------------------------------- /src/pcloudsh/assembly_factory.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Steven Dake 5 | # Angus Salkeld 6 | # 7 | # This program is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU General Public License 9 | # as published by the Free Software Foundation; either version 2 10 | # of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | # 20 | import os 21 | 22 | from pcloudsh import assembly 23 | from pcloudsh import pcmkconfig 24 | from pcloudsh import db_helper 25 | 26 | have_mod = {'openstack': False, 'libvirt': False, 'aeolus': False, 'ovirt': False} 27 | try: 28 | from pcloudsh import openstack_assembly 29 | have_mod['openstack'] = True 30 | except: 31 | pass 32 | try: 33 | from pcloudsh import libvirt_assembly 34 | have_mod['libvirt'] = True 35 | except: 36 | pass 37 | #try: 38 | # from pcloudsh import aeolus_assembly 39 | # have_mod['aeolus'] = True 40 | #except: 41 | # pass 42 | #try: 43 | # from pcloudsh import ovirt_assembly 44 | # have_mod['ovirt'] = True 45 | #except: 46 | # pass 47 | 48 | class AssemblyFactory(db_helper.DbFactory): 49 | 50 | def __init__(self, logger): 51 | self.l = logger 52 | db_helper.DbFactory.__init__(self, 'db_assemblies.xml', 'assemblies', 'assembly') 53 | 54 | def create_instance(self, name, infrastructure=None): 55 | self.l.debug('creating %s as %s' % (name, infrastructure)) 56 | if infrastructure == None: 57 | return assembly.Assembly(self, name) 58 | if not have_mod[infrastructure]: 59 | self.l.error('cant load assembly %s (%s module missing)' % (name, infrastructure)) 60 | return None 61 | i = None 62 | if infrastructure == 'libvirt': 63 | i = libvirt_assembly.LibVirtAssembly(self, name) 64 | elif infrastructure == 'openstack': 65 | i = openstack_assembly.OpenstackAssembly(self, name) 66 | else: 67 | self.l.error('cant load assembly %s (module %s not supported)' % (name, infrastructure)) 68 | return None 69 | 70 | i.infrastructure = infrastructure 71 | return i 72 | 73 | def load(self): 74 | list = self.doc.xpathEval("/%s/%s" % (self.plural, self.singular)) 75 | for node in list: 76 | n = node.prop('name') 77 | i = node.prop('infrastructure') 78 | if i == None: 79 | i = 'libvirt' 80 | if n not in self.all: 81 | self.all[n] = self.create_instance(n, i) 82 | 83 | def clone(self, source, dest): 84 | source_assy = self.get(source) 85 | dest_assy = self.get(dest) 86 | if source_assy.uuid == '': 87 | print '*** The source assembly does not exist in the system \"%s\"' % source 88 | return 89 | dest_assy.clone_from(source_assy) 90 | dest_assy.clean_xml('%s/assemblies/%s.xml' % (self.conf.dbdir, dest_assy.name)) 91 | dest_assy.save() 92 | 93 | def create(self, name, source): 94 | dest_assy = self.get(name) 95 | if not os.access('%s/assemblies/%s.tdl' % (self.conf.dbdir, name), os.R_OK): 96 | print '*** Please provide %s/assemblies/%s.tdl to customize your assembly' % (self.conf.dbdir, name) 97 | return 98 | 99 | jeos_source = self.get("%s-jeos" % source) 100 | jeos_source.jeos_name = source 101 | if not os.access('%s/jeos/%s-jeos.xml' % (self.conf.dbdir, jeos_source.jeos_name), os.R_OK): 102 | print '*** Please create the \"%s\" jeos first' % source 103 | return 104 | 105 | if dest_assy.clone_from(jeos_source) == 0: 106 | os.system ("oz-customize -d3 %s/assemblies/%s.tdl %s/assemblies/%s.xml" % 107 | (self.conf.dbdir, dest_assy.name, self.conf.dbdir, dest_assy.name)) 108 | dest_assy.clean_xml('%s/assemblies/%s.xml' % (self.conf.dbdir, dest_assy.name)) 109 | dest_assy.save() 110 | else: 111 | self.delete_instance(name) 112 | 113 | def register(self, name, infrastructure, dep_name, username): 114 | if not have_mod[infrastructure]: 115 | self.l.error('cant register %s as %s module not available' % (name, infrastructure)) 116 | return 117 | 118 | # reload with the correct class 119 | self.all[name].save() 120 | del self.all[name] 121 | a = self.create_instance(name, infrastructure) 122 | a.username = username 123 | a.deployment = dep_name 124 | self.all[name] = a 125 | a.save() 126 | if infrastructure == 'openstack': 127 | a.register_with_openstack(username) 128 | 129 | def delete(self, name): 130 | self.get(name).delete() 131 | self.delete_instance(name) 132 | 133 | -------------------------------------------------------------------------------- /src/pcloudsh/assy-wordpress-F16.tdl: -------------------------------------------------------------------------------- 1 | 31 | -------------------------------------------------------------------------------- /src/pcloudsh/assy-wordpress-mysql-F16.tdl: -------------------------------------------------------------------------------- 1 | 81 | -------------------------------------------------------------------------------- /src/pcloudsh/assy1-F14.tdl: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/pcloudsh/assy1-F15.tdl: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/pcloudsh/assy1-F16.tdl: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/pcloudsh/assy1-U10.tdl: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/pcloudsh/assy1.tdl: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /src/pcloudsh/cpe.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Angus Salkeld 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | # 19 | import logging 20 | import cqpid 21 | import qmf2 22 | import sys 23 | import time 24 | 25 | class Cpe(object): 26 | 27 | def __init__(self, logger): 28 | 29 | self.cpe_obj = None 30 | self.conn = cqpid.Connection('localhost:49000') 31 | self.conn.open() 32 | self.session = qmf2.ConsoleSession(self.conn) 33 | self.session.setAgentFilter('[]') 34 | self.session.open() 35 | self.l = logger 36 | 37 | attempts = 0 38 | while self.cpe_obj is None: 39 | agents = self.session.getAgents() 40 | for a in agents: 41 | self.l.debug('agent: %s' % str(a)) 42 | if 'pacemakercloud.org' in a.getVendor(): 43 | result = a.query("{class:cpe, package:'org.pacemakercloud'}") 44 | if len(result) >= 1: 45 | self.cpe_obj = result[0] 46 | 47 | if self.cpe_obj is None: 48 | attempts = attempts + 1 49 | if attempts > 50: 50 | print '*** Could not find cped agent...' 51 | sys.exit(3) 52 | else: 53 | time.sleep(0.1) 54 | 55 | def __del__(self): 56 | self.session.close() 57 | self.conn.close() 58 | 59 | def deployable_start(self, name, uuid, monitor): 60 | result = None 61 | if self.cpe_obj: 62 | try: 63 | result = self.cpe_obj.deployable_start(name, uuid, monitor) 64 | except: 65 | return 1 66 | 67 | for k,v in result.items(): 68 | return v 69 | else: 70 | return 1 71 | 72 | def deployable_reload(self, name, uuid, monitor): 73 | result = None 74 | if self.cpe_obj: 75 | try: 76 | result = self.cpe_obj.deployable_reload(name, uuid, monitor) 77 | except: 78 | return 1 79 | 80 | for k,v in result.items(): 81 | return v 82 | else: 83 | return 1 84 | 85 | def deployable_stop(self, name, uuid, monitor): 86 | result = None 87 | if self.cpe_obj: 88 | try: 89 | result = self.cpe_obj.deployable_stop(name, uuid, monitor) 90 | except: 91 | return 1 92 | 93 | for k,v in result.items(): 94 | return v 95 | else: 96 | return 1 97 | -------------------------------------------------------------------------------- /src/pcloudsh/db_helper.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Angus Salkeld 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | # 19 | import os 20 | import libxml2 21 | 22 | from pcloudsh import pcmkconfig 23 | 24 | class DbFactory(object): 25 | 26 | def __init__(self, filename, plural, singular): 27 | self.conf = pcmkconfig.Config() 28 | self.plural = plural 29 | self.singular = singular 30 | self.xml_file = '%s/%s' % (self.conf.dbdir, filename) 31 | it_exists = os.access(self.xml_file, os.R_OK) 32 | libxml2.keepBlanksDefault(False) 33 | 34 | try: 35 | if it_exists: 36 | self.doc = libxml2.parseFile(self.xml_file) 37 | except: 38 | it_exists = False 39 | 40 | if not it_exists: 41 | self.doc = libxml2.newDoc("1.0") 42 | self.root_node = self.doc.newChild(None, plural, None) 43 | self.root_node.setProp('pcmkc-version', self.conf.version) 44 | else: 45 | self.root_node = self.doc.getRootElement() 46 | 47 | _ver = self.root_node.prop('pcmkc-version') 48 | if not _ver == self.conf.version: 49 | _msg = '*** warning xml and program version mismatch' 50 | print '%s \"%s\" != \"%s\"' % (_msg, _ver, self.conf.version) 51 | 52 | self.all = {} 53 | self.load() 54 | 55 | def load(self): 56 | list = self.doc.xpathEval("/%s/%s" % (self.plural, self.singular)) 57 | for node in list: 58 | n = node.prop('name') 59 | if n not in self.all: 60 | self.all[n] = self.create_instance(n) 61 | 62 | def root_get(self): 63 | return self.root_node 64 | 65 | def save(self): 66 | self.doc.saveFormatFile(self.xml_file, format=1) 67 | 68 | def all_get(self): 69 | return self.all.values() 70 | 71 | def exists(self, name): 72 | if name in self.all: 73 | return True 74 | else: 75 | return False 76 | 77 | def get(self, name): 78 | if name in self.all: 79 | return self.all[name] 80 | 81 | self.all[name] = self.create_instance(name) 82 | return self.all[name] 83 | 84 | def create_instance(self, name): 85 | raise 86 | 87 | def delete_instance(self, name): 88 | node_list = self.doc.xpathEval("/%s/%s[@name='%s']" % (self.plural, self.singular, name)) 89 | if len(node_list) == 0: 90 | print '*** %s %s does not exist.' % (self.singular, name) 91 | return 92 | first_node = node_list[0] 93 | first_node.unlinkNode() 94 | del self.all[name] 95 | self.save() 96 | -------------------------------------------------------------------------------- /src/pcloudsh/deployable_factory.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Steven Dake 5 | # Angus Salkeld 6 | # 7 | # This program is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU General Public License 9 | # as published by the Free Software Foundation; either version 2 10 | # of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | # 20 | import os 21 | import time 22 | import libxml2 23 | import exceptions 24 | 25 | from pcloudsh import deployable 26 | from pcloudsh import pcmkconfig 27 | from pcloudsh import db_helper 28 | 29 | have_mod = {'openstack': False, 'libvirt': False, 'aeolus': False, 'ovirt': False} 30 | try: 31 | from pcloudsh import openstack_deployable 32 | have_mod['openstack'] = True 33 | except: 34 | pass 35 | try: 36 | from pcloudsh import libvirt_deployable 37 | have_mod['libvirt'] = True 38 | except: 39 | pass 40 | #try: 41 | # from pcloudsh import aeolus_deployable 42 | # have_mod['aeolus'] = True 43 | #except: 44 | # pass 45 | #try: 46 | # from pcloudsh import ovirt_deployable 47 | # have_mod['ovirt'] = True 48 | #except: 49 | # pass 50 | 51 | class DeployableFactory(db_helper.DbFactory): 52 | 53 | def __init__(self, logger): 54 | self.l = logger 55 | db_helper.DbFactory.__init__(self, 'db_deployable.xml', 'deployables', 'deployable') 56 | 57 | def create_instance(self, name, infrastructure, username): 58 | i = None 59 | 60 | if not have_mod[infrastructure]: 61 | self.l.error('cant load deployable %s (%s module missing)' % (name, infrastructure)) 62 | return None 63 | 64 | if infrastructure == 'libvirt': 65 | i = libvirt_deployable.LibVirtDeployable(self, name, username) 66 | elif infrastructure == 'openstack': 67 | i = openstack_deployable.OpenstackDeployable(self, name, username) 68 | else: 69 | self.l.error('cant load deployable %s (module %s not supported)' % (name, infrastructure)) 70 | 71 | return i 72 | 73 | def get(self, name, infrastructure='libvirt', username='root'): 74 | if name in self.all: 75 | return self.all[name] 76 | 77 | self.all[name] = self.create_instance(name, infrastructure, username) 78 | return self.all[name] 79 | 80 | def load(self): 81 | list = self.doc.xpathEval("/%s/%s" % (self.plural, self.singular)) 82 | for node in list: 83 | n = node.prop('name') 84 | i = node.prop('infrastructure') 85 | if i == None: 86 | i = 'libvirt' 87 | u = node.prop('username') 88 | if u == None: 89 | u = 'nobody' 90 | if n not in self.all: 91 | self.all[n] = self.create_instance(n, i, u) 92 | 93 | def delete(self, name): 94 | if name in self.all: 95 | self.all[name].delete() 96 | self.delete_instance(name) 97 | 98 | def create(self, name, infrastructure, username, monitor): 99 | d = self.get(name, infrastructure, username) 100 | d.monitor = monitor 101 | if d.create(): 102 | d.save() 103 | else: 104 | d.delete() 105 | self.delete_instance(name) 106 | -------------------------------------------------------------------------------- /src/pcloudsh/eventreceiver.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Angus Salkeld 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | # 19 | import os 20 | import sys 21 | import qmf2 22 | from pcloudsh import pcmkconfig 23 | 24 | class EventReceiver(qmf2.ConsoleHandler): 25 | 26 | def __init__(self, session): 27 | qmf2.ConsoleHandler.__init__(self, session) 28 | self.conf = pcmkconfig.Config() 29 | 30 | def eventRaised(self, agent, data, timestamp, severity): 31 | props = data.getProperties() 32 | reason = props['reason'] 33 | state = props['state'] 34 | 35 | service = props.get('service','') 36 | assembly = props.get('assembly','') 37 | deployable = props.get('deployable','') 38 | 39 | if sys.stdout.isatty(): 40 | ACTIVE = "\x1b[1;37;42mACTIVE\x1b[0m" 41 | RECOVERING ="\x1b[30;43mRECOVERING\x1b[0m" 42 | FAILED = "\x1b[01;37;41mFAILED\x1b[0m" 43 | else: 44 | ACTIVE = "ACTIVE" 45 | RECOVERING ="RECOVERING" 46 | FAILED = "FAILED" 47 | 48 | event_desc = { 49 | 'All good': 50 | 'The assembly [%(assembly)s] in deployable [%(deployable)s] is %(ACTIVE)s.', 51 | 'Started OK': 52 | 'The resource [%(service)s] in assembly [%(assembly)s] in deployable [%(deployable)s] is %(ACTIVE)s.', 53 | 'monitor failed': 54 | 'The resource [%(service)s] in assembly [%(assembly)s] in deployable [%(deployable)s] %(FAILED)s.', 55 | 'all assemblies active': 56 | 'The deployable [%(deployable)s] is %(ACTIVE)s.', 57 | 'Not reachable': 58 | 'The assembly [%(assembly)s] in deployable [%(deployable)s] %(FAILED)s.', 59 | 'change in assembly state': 60 | 'The deployable [%(deployable)s] is %(RECOVERING)s.', 61 | 'escalating service failure': 62 | 'A service recovery escalation terminated assembly [%(assembly)s] in deployable [%(deployable)s].', 63 | 'assembly failure escalated to deployable': 64 | 'An assembly recovery escalation terminated deployable [%(deployable)s].' 65 | } 66 | 67 | print event_desc.get(reason,'') % locals() 68 | 69 | # Run helper script in case IPs have changed 70 | if reason == 'all assemblies active': 71 | script = '%s/%s.sh' % (self.conf.dbdir, deployable) 72 | if os.access(script, os.R_OK): 73 | os.system('%s %s' % (script, state)) 74 | -------------------------------------------------------------------------------- /src/pcloudsh/eventrunner.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Angus Salkeld 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | # 19 | import cqpid 20 | import qmf2 21 | import threading 22 | from pcloudsh import eventreceiver 23 | 24 | class EventRunner(threading.Thread): 25 | 26 | def __init__(self): 27 | threading.Thread.__init__(self) 28 | 29 | self.connection = cqpid.Connection('localhost:49000', '') 30 | self.connection.open() 31 | 32 | self.session = qmf2.ConsoleSession(self.connection) 33 | self.session.open() 34 | self.session.setAgentFilter("[eq, _vendor, [quote, 'pacemakercloud.org']]") 35 | 36 | self.receiver = eventreceiver.EventReceiver(self.session) 37 | 38 | def run(self): 39 | self.receiver.run() 40 | -------------------------------------------------------------------------------- /src/pcloudsh/ifconfig.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Angus Salkeld 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | # 19 | import socket 20 | import fcntl 21 | import struct 22 | 23 | class Ifconfig(object): 24 | def __init__(self, ifname): 25 | 26 | self.ifreq = {} 27 | self.ifreq['ifname'] = ifname 28 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 29 | try: 30 | self.ifreq['addr'] = self._ifinfo(sock, 0x8915, ifname) # SIOCGIFADDR 31 | self.ifreq['brdaddr'] = self._ifinfo(sock, 0x8919, ifname) # SIOCGIFBRDADDR 32 | self.ifreq['netmask'] = self._ifinfo(sock, 0x891b, ifname) # SIOCGIFNETMASK 33 | self.ifreq['hwaddr'] = self._ifinfo(sock, 0x8927, ifname) # SIOCSIFHWADDR 34 | except: 35 | pass 36 | sock.close() 37 | 38 | def _ifinfo(self, sock, addr, ifname): 39 | iface = struct.pack('256s', ifname[:15]) 40 | info = fcntl.ioctl(sock.fileno(), addr, iface) 41 | if addr == 0x8927: 42 | hwaddr = [] 43 | for char in info[18:24]: 44 | hwaddr.append(hex(ord(char))[2:]) 45 | return ':'.join(hwaddr) 46 | else: 47 | return socket.inet_ntoa(info[20:24]) 48 | 49 | def __str__(self): 50 | return str(self.ifreq) 51 | 52 | def addr_get(self): 53 | return self.ifreq['addr'] 54 | 55 | def broadcast_get(self): 56 | return self.ifreq['brdaddr'] 57 | 58 | def netmask_get(self): 59 | return self.ifreq['netmask'] 60 | 61 | def hwaddr_get(self): 62 | return self.ifreq['hwaddr'] 63 | 64 | if __name__ == '__main__': 65 | info = Ifconfig('virbr0') 66 | print info 67 | 68 | print 'IP addr is %s' % info.addr_get() 69 | -------------------------------------------------------------------------------- /src/pcloudsh/keys/README: -------------------------------------------------------------------------------- 1 | These keys are available to ssh into the assemblies. Do not delete and 2 | keep them secure. 3 | -------------------------------------------------------------------------------- /src/pcloudsh/libvirt_assembly.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Steven Dake 5 | # Angus Salkeld 6 | # 7 | # This program is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU General Public License 9 | # as published by the Free Software Foundation; either version 2 10 | # of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | # 20 | import os 21 | import logging 22 | import libxml2 23 | import exceptions 24 | 25 | import libvirt 26 | 27 | from pcloudsh import assembly 28 | 29 | class LibVirtAssembly(assembly.Assembly): 30 | 31 | def __init__(self, factory, name): 32 | assembly.Assembly.__init__(self, factory, name) 33 | 34 | def start(self): 35 | self.l.info('starting virt:%s:%s' % (self.deployment, self.name)) 36 | libvirt_xml = libxml2.parseFile('/var/lib/pacemaker-cloud/assemblies/%s.xml' % self.name) 37 | libvirt_doc = libvirt_xml.serialize(None, 1) 38 | try: 39 | c = libvirt.open("qemu:///system") 40 | libvirt_dom = c.createXML(libvirt_doc, 0) 41 | self.l.info('started %s' % (self.name)) 42 | except libvirt.libvirtError as e: 43 | self.l.exception(e) 44 | finally: 45 | c.close() 46 | 47 | def stop(self): 48 | try: 49 | c = libvirt.open("qemu:///system") 50 | ass = c.lookupByName(self.name) 51 | ass.destroy() 52 | except libvirt.libvirtError as e: 53 | if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: 54 | # already stopped 55 | pass 56 | else: 57 | self.l.exception(e) 58 | finally: 59 | c.close() 60 | 61 | def status(self): 62 | st = 'Undefined' 63 | try: 64 | c = libvirt.open("qemu:///system") 65 | ass = c.lookupByName(self.name) 66 | if ass.isActive(): 67 | st = 'running' 68 | else: 69 | st = 'stopped' 70 | except libvirt.libvirtError as e: 71 | if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: 72 | st = 'finished' 73 | else: 74 | self.l.exception(e) 75 | finally: 76 | c.close() 77 | 78 | return st 79 | 80 | -------------------------------------------------------------------------------- /src/pcloudsh/libvirt_deployable.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Steven Dake 5 | # Angus Salkeld 6 | # 7 | # This program is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU General Public License 9 | # as published by the Free Software Foundation; either version 2 10 | # of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | # 20 | import os 21 | import logging 22 | import libxml2 23 | import exceptions 24 | 25 | import libvirt 26 | 27 | from pcloudsh import deployable 28 | 29 | class LibVirtDeployable(deployable.Deployable): 30 | def __init__(self, factory, name, username): 31 | self.infrastructure = 'libvirt' 32 | self.username = username 33 | deployable.Deployable.__init__(self, factory, name) 34 | 35 | def status(self): 36 | try: 37 | c = libvirt.open("qemu:///system") 38 | except: 39 | self.l.exception('*** couldn\'t connect to libvirt') 40 | 41 | name_list = self.factory.doc.xpathEval("/deployables/deployable[@name='%s']/assembly" % self.name) 42 | print ' %-12s %-12s' % ('Assembly', 'Status') 43 | print '------------------------' 44 | for a in name_list: 45 | an = a.prop('name') 46 | try: 47 | ass = c.lookupByName(an) 48 | if ass.isActive(): 49 | print " %-12s %-12s" % (an, 'Running') 50 | else: 51 | print " %-12s %-12s" % (an, 'Stopped') 52 | except libvirt.libvirtError as e: 53 | if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: 54 | print " %-12s %-12s" % (an, 'Undefined') 55 | else: 56 | print " %-12s %-12s" % (an, 'Error') 57 | try: 58 | c.close() 59 | except: 60 | self.l.exception('*** couldn\'t disconnect from libvirt') 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/pcloudsh/openstack_deployable.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Angus Salkeld 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | # 19 | import os 20 | import time 21 | import libxml2 22 | import exceptions 23 | import uuid 24 | import subprocess 25 | import shutil 26 | from pwd import getpwnam 27 | 28 | from nova import flags 29 | from nova import log 30 | from nova import exception 31 | from nova import utils 32 | from nova.auth import manager 33 | 34 | from pcloudsh import pcmkconfig 35 | from pcloudsh import deployable 36 | from pcloudsh import assembly 37 | from pcloudsh import assembly_factory 38 | 39 | FLAGS = flags.FLAGS 40 | FLAGS.logging_context_format_string = ' %(levelname)s %(message)s' 41 | FLAGS.logging_default_format_string = ' %(levelname)s %(message)s' 42 | FLAGS.logging_debug_format_suffix = ' [%(filename)s:%(lineno)d]' 43 | log.setup() 44 | 45 | class OpenstackDeployable(deployable.Deployable): 46 | def __init__(self, factory, name, username): 47 | self.infrastructure = 'openstack' 48 | self.username = username 49 | 50 | deployable.Deployable.__init__(self, factory, name) 51 | 52 | # TODO flagfile 53 | FLAGS.state_path = '/var/lib/nova' 54 | FLAGS.lock_path = '/var/lib/nova/tmp' 55 | FLAGS.credentials_template = '/usr/share/nova/novarc.template' 56 | FLAGS.sql_connection = 'mysql://nova:nova@localhost/nova' 57 | self.conf.load_novarc(name) 58 | 59 | def create(self): 60 | nova_manager = manager.AuthManager() 61 | uid = 0 62 | gid = 0 63 | try: 64 | user_info = getpwnam(self.username) 65 | uid = user_info[2] 66 | gid = user_info[3] 67 | except KeyError as ex: 68 | print ex 69 | return False 70 | 71 | proj_exists = True 72 | try: 73 | projs = nova_manager.get_projects(self.username) 74 | if not self.name in projs: 75 | proj_exists = False 76 | except: 77 | proj_exists = False 78 | 79 | try: 80 | if not proj_exists: 81 | nova_manager.create_project(self.name, self.username, 82 | 'Project %s created by pcloudsh' % (self.name)) 83 | except (exception.UserNotFound, exception.ProjectExists) as ex: 84 | print ex 85 | return False 86 | 87 | os.mkdir(os.path.join(self.conf.dbdir, self.name)) 88 | zipfilename = os.path.join(self.conf.dbdir, self.name, 'nova.zip') 89 | try: 90 | zip_data = nova_manager.get_credentials(self.username, self.name) 91 | with open(zipfilename, 'w') as f: 92 | f.write(zip_data) 93 | except (exception.UserNotFound, exception.ProjectNotFound) as ex: 94 | print ex 95 | return False 96 | except db.api.NoMoreNetworks: 97 | print ('*** No more networks available. If this is a new ' 98 | 'installation, you need\nto call something like this:\n\n' 99 | ' nova-manage network create pvt 10.0.0.0/8 10 64\n\n') 100 | return False 101 | except exception.ProcessExecutionError, e: 102 | print e 103 | print ("*** The above error may show that the certificate db has " 104 | "not been created.\nPlease create a database by running " 105 | "a nova-api server on this host.") 106 | return False 107 | 108 | os.chmod(zipfilename, 0600) 109 | os.chown(zipfilename, uid, gid) 110 | novacreds = os.path.join(self.conf.dbdir, self.name, 'novacreds') 111 | os.mkdir(novacreds) 112 | os.system('unzip %s -d %s' % (zipfilename, novacreds)) 113 | os.system('ssh-keygen -f %s' % os.path.join(novacreds, 'nova_key')) 114 | 115 | self.conf.load_novarc(self.name) 116 | 117 | cwd = os.getcwd() 118 | os.chdir(novacreds) 119 | os.system('euca-add-keypair nova_key > nova_key.priv') 120 | os.chdir(cwd) 121 | 122 | for fn in os.listdir(novacreds): 123 | if 'nova' in fn: 124 | os.chown(os.path.join(novacreds, fn), uid, gid) 125 | os.chmod(os.path.join(novacreds, fn), 0600) 126 | 127 | return True 128 | 129 | def delete(self): 130 | nova_manager = manager.AuthManager() 131 | if os.access(os.path.join(self.conf.dbdir, self.name), os.R_OK): 132 | shutil.rmtree(os.path.join(self.conf.dbdir, self.name)) 133 | print ' deleted nova project key and environment' 134 | try: 135 | nova_manager.delete_project(self.name) 136 | print ' deleted nova project' 137 | except exception.ProjectNotFound as ex: 138 | print ex 139 | 140 | 141 | -------------------------------------------------------------------------------- /src/pcloudsh/pcmkconfig.py.in: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Angus Salkeld 5 | # 6 | # This program is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU General Public License 8 | # as published by the Free Software Foundation; either version 2 9 | # of the License, or (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program; if not, see . 18 | # 19 | import os 20 | import os.path 21 | import string 22 | import subprocess 23 | 24 | 25 | class Config(object): 26 | def __init__(self): 27 | self.version = '@VERSION@' 28 | self.prefix = '@prefix@' 29 | self.localstatedir = '@localstatedir@' 30 | self.datarootdir = string.replace('@datarootdir@', '${prefix}', self.prefix) 31 | self.dbdir = '%s/lib/pacemaker-cloud' % (self.localstatedir) 32 | self.resource_templatesdir = '%s/pacemaker-cloud/resource_templates' % (self.datarootdir) 33 | 34 | def load_novarc(self, dep_name): 35 | 36 | novarc_path = os.path.join(self.dbdir, dep_name, 'novacreds', 'novarc') 37 | if not os.access(novarc_path, os.R_OK): 38 | return 39 | 40 | output = subprocess.check_output('source %s && env | egrep \"NOVA_|EC2_|S3_|EUCALYPTUS_\"' % novarc_path, 41 | stderr=subprocess.STDOUT, 42 | shell=True) 43 | 44 | for line in output.split(): 45 | (n, v) = line.split('=') 46 | os.environ[n] = str(v) 47 | -------------------------------------------------------------------------------- /src/pcloudsh/resource.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2011 Red Hat, Inc. 3 | # 4 | # Author: Steven Dake 5 | # Angus Salkeld 6 | # 7 | # This program is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU General Public License 9 | # as published by the Free Software Foundation; either version 2 10 | # of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, see . 19 | # 20 | import os 21 | import libxml2 22 | import exceptions 23 | from pcloudsh import pcmkconfig 24 | 25 | class Resource(object): 26 | 27 | def __init__(self, factory): 28 | self.conf = pcmkconfig.Config() 29 | self.factory = factory 30 | self.name = '' 31 | self.type = 'http' 32 | self.klass = 'lsb' 33 | self.provider = 'heartbeat' 34 | self.monitor_interval = '60s' 35 | self.escalation_failures = 'INFINITY' 36 | self.escalation_period = 'INFINITY' 37 | self.xml_node = None 38 | 39 | def load_from_xml(self, xml): 40 | self.xml_node = xml 41 | self.name = xml.prop('name') 42 | self.monitor_interval = xml.prop('monitor_interval') 43 | self.type = xml.prop('type') 44 | self.klass = xml.prop('class') 45 | self.provider = xml.prop('provider') 46 | if xml.hasProp('escalation_failures'): 47 | self.escalation_failures = xml.prop('escalation_failures') 48 | if xml.hasProp('escalation_period'): 49 | self.escalation_period = xml.prop('escalation_period') 50 | 51 | self.params = {} 52 | if xml.children == None: 53 | return 54 | 55 | for ps in xml.children: 56 | if ps.name != 'parameters': 57 | continue 58 | for p in ps.children: 59 | if p.name != 'parameter': 60 | continue 61 | self.params[p.prop('name')] = p.prop('value') 62 | 63 | def save(self): 64 | if self.xml_node is None: 65 | nd = libxml2.parseFile('%s/%s.xml' % (self.conf.resource_templatesdir, self.type)) 66 | n = nd.getRootElement() 67 | n.newProp('name', self.name) 68 | n.newProp('escalation_period', self.escalation_period) 69 | n.newProp('escalation_failures', self.escalation_failures) 70 | self.factory.root_get().addChild(n) 71 | self.xml_node = n 72 | else: 73 | self.xml_node.setProp('name', self.name) 74 | self.xml_node.setProp('type', self.type) 75 | self.xml_node.setProp('class', self.klass) 76 | self.xml_node.setProp('provider', self.provider) 77 | self.xml_node.setProp('monitor_interval', self.monitor_interval) 78 | self.xml_node.setProp('escalation_period', self.escalation_period) 79 | self.xml_node.setProp('escalation_failures', self.escalation_failures) 80 | 81 | def delete(self): 82 | if self.xml_node != None: 83 | self.xml_node.unlinkNode() 84 | self.xml_node = None 85 | 86 | def __str__(self): 87 | return '%s_%s_%s' % (self.name, self.type, self.monitor_interval) 88 | 89 | class ResourceFactory(object): 90 | 91 | def __init__(self, assembly_node): 92 | self.conf = pcmkconfig.Config() 93 | self.all = {} 94 | 95 | self.root_node = None 96 | if assembly_node.children != None: 97 | for n in assembly_node.children: 98 | if n.name == 'resources': 99 | self.root_node = n 100 | 101 | if self.root_node is None: 102 | self.root_node = assembly_node.newChild(None, "resources", None) 103 | 104 | if self.root_node.children != None: 105 | for r in self.root_node.children: 106 | if r.name == 'resource': 107 | n = r.prop('name') 108 | if n not in self.all: 109 | self.all[n] = Resource(self) 110 | self.all[n].load_from_xml(r) 111 | 112 | def root_get(self): 113 | return self.root_node 114 | 115 | def template_exists(self, template): 116 | tn = '%s/%s.xml' % (self.conf.resource_templatesdir, template) 117 | return os.access(tn, os.R_OK) 118 | 119 | def exists(self, name): 120 | if name in self.all: 121 | return True 122 | else: 123 | return False 124 | 125 | def get(self, name): 126 | if name in self.all: 127 | return self.all[name] 128 | 129 | a = Resource(self) 130 | a.name = name 131 | self.all[name] = a 132 | return a 133 | 134 | def delete(self, name): 135 | if name in self.all: 136 | self.all[name].delete() 137 | del self.all[name] 138 | 139 | def save(self): 140 | pass 141 | 142 | def all_get(self): 143 | return self.all.values() 144 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/aeolus-conductor.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/apache2.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/condor.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/conductor-dbomatic.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/conductor-delayed_job.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/deltacloud-core.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/deltacloud-ec2-us-east-1.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/deltacloud-ec2-us-west-1.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/deltacloud-mock.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/dummy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/httpd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/imagefactory.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/mysqld.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/ntpd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/postgresql.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/resource_templates/qpidd.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/pcloudsh/rhel61-x86_64-jeos-assembly.tdl: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/pcloudsh/rhel61-x86_64-jeos.tdl: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /src/pcmk_pe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #ifndef _PCMK_PE_H_ 23 | #define _PCMK_PE_H_ 24 | 25 | #include 26 | #include 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #define PE_CRM_VERSION "3.0.5" 36 | #define PE_DEFAULT_TIMEOUT 10000 37 | 38 | enum ocf_exitcode { 39 | OCF_PENDING = -1, 40 | OCF_OK = 0, 41 | OCF_UNKNOWN_ERROR = 1, 42 | OCF_INVALID_PARAM = 2, 43 | OCF_UNIMPLEMENT_FEATURE = 3, 44 | OCF_INSUFFICIENT_PRIV = 4, 45 | OCF_NOT_INSTALLED = 5, 46 | OCF_NOT_CONFIGURED = 6, 47 | OCF_NOT_RUNNING = 7, 48 | OCF_RUNNING_MASTER = 8, 49 | OCF_FAILED_MASTER = 9, 50 | }; 51 | 52 | struct pe_operation { 53 | char *hostname; 54 | char *node_uuid; 55 | char *method; 56 | char *rname; 57 | char *rclass; 58 | char *rprovider; 59 | char *rtype; 60 | qb_map_t *params; 61 | char *op_digest; 62 | uint32_t timeout; 63 | uint32_t times_executed; 64 | uint32_t interval; 65 | uint32_t target_outcome; 66 | void *user_data; 67 | void *graph; 68 | void *action; 69 | void *resource; 70 | uint32_t graph_id; 71 | uint32_t action_id; 72 | uint32_t refcount; 73 | qb_util_stopwatch_t *time_execed; 74 | }; 75 | 76 | typedef void (*pe_resource_execute_t)(struct pe_operation *op); 77 | typedef void (*pe_transition_completed_t)(void* user_data, int32_t result); 78 | 79 | enum ocf_exitcode pe_resource_ocf_exitcode_get(struct pe_operation *op, 80 | int lsb_exitcode); 81 | const char* pe_resource_reason_get(enum ocf_exitcode exitcode); 82 | int pe_resource_is_hard_error(enum ocf_exitcode ec); 83 | 84 | void pe_resource_completed(struct pe_operation *op, uint32_t return_code); 85 | void pe_resource_ref(struct pe_operation *op); 86 | void pe_resource_unref(struct pe_operation *op); 87 | 88 | int32_t pe_process_state(xmlDocPtr doc, 89 | pe_resource_execute_t exec_fn, 90 | pe_transition_completed_t done_fn, 91 | void *user_data, 92 | int debug); 93 | 94 | int32_t pe_is_busy_processing(void); 95 | 96 | void pe_log_init(int log_tag, int loglevel); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif /* _PCMK_PE_H_ */ 103 | -------------------------------------------------------------------------------- /src/qmf_agent.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #include 22 | #include "qmf_agent.h" 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace std; 28 | using namespace qmf; 29 | 30 | 31 | QmfAgent::QmfAgent(Agent& a) 32 | { 33 | _agent = a; 34 | } 35 | 36 | void QmfAgent::add(QmfObject *o) 37 | { 38 | _objects.push_back(o); 39 | o->agent_set(this); 40 | } 41 | 42 | QmfAgent::~QmfAgent() 43 | { 44 | QmfAsyncRequest *ar; 45 | qpid::types::Variant::Map empty_args; 46 | 47 | map::iterator call; 48 | for (call = _outstanding_calls.begin(); 49 | call != _outstanding_calls.end(); call++) { 50 | ar = call->second; 51 | ar->obj->method_response(ar, empty_args, QmfObject::RPC_CANCELLED); 52 | } 53 | 54 | for (list::iterator obj = _objects.begin(); 55 | obj != _objects.end(); ++obj) { 56 | (*obj)->disconnect(); 57 | } 58 | } 59 | 60 | void 61 | QmfAgent::call_method_async(QmfAsyncRequest *ar, 62 | qmf::Data *data) 63 | { 64 | uint32_t cid; 65 | qpid::types::Variant::Map in_args; 66 | Schema s = _agent.getSchema(data->getSchemaId()); 67 | 68 | for (int i = 0; i < s.getMethodCount(); i++) { 69 | SchemaMethod sm = s.getMethod(i); 70 | 71 | if (sm.getName() != ar->method) { 72 | continue; 73 | } 74 | for (int g = 0; g < sm.getArgumentCount(); g++) { 75 | SchemaProperty sp = sm.getArgument(g); 76 | if (sp.getDirection() != DIR_OUT) { 77 | in_args[sp.getName()] = ar->args[sp.getName()]; 78 | } 79 | } 80 | break; 81 | } 82 | if (ar->args.size() != in_args.size()) { 83 | string removed; 84 | bool first = true; 85 | 86 | for (qpid::types::Variant::Map::iterator it = ar->args.begin(); 87 | it != ar->args.end(); it++) { 88 | string n = it->first; 89 | if (in_args.find(n) == in_args.end()) { 90 | if (!first) { 91 | removed += ", "; 92 | } 93 | removed += n; 94 | first = false; 95 | } 96 | } 97 | 98 | qb_log(LOG_TRACE, 99 | "Schema requires we remove %d args (%s) from method %s", 100 | ar->args.size() - in_args.size(), 101 | removed.c_str(), ar->method.c_str()); 102 | } 103 | cid = _agent.callMethodAsync(ar->method, in_args, data->getAddr()); 104 | _outstanding_calls[cid] = ar; 105 | } 106 | 107 | void 108 | QmfAgent::process_event(qmf::ConsoleEvent &event) 109 | { 110 | list::iterator iter; 111 | QmfAsyncRequest *ar; 112 | 113 | if (event.getType() == CONSOLE_METHOD_RESPONSE || 114 | event.getType() == CONSOLE_EXCEPTION) { 115 | ar = _outstanding_calls[event.getCorrelator()]; 116 | if (ar) { 117 | ar->obj->process_event(event, ar); 118 | _outstanding_calls.erase(event.getCorrelator()); 119 | } else { 120 | qb_log(LOG_WARNING, "unknown request"); 121 | } 122 | return; 123 | } 124 | for (list::iterator it = _objects.begin(); 125 | it != _objects.end(); ++it) { 126 | (*it)->process_event(event, NULL); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/qmf_agent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #ifndef QMF_AGENT_DEFINED 22 | #define QMF_AGENT_DEFINED 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include "qmf_object.h" 31 | 32 | class QmfAgent { 33 | private: 34 | qmf::Agent _agent; 35 | std::list _objects; 36 | std::map _outstanding_calls; 37 | 38 | public: 39 | QmfAgent(qmf::Agent& agent); 40 | ~QmfAgent(); 41 | void add(QmfObject *o); 42 | 43 | void process_event(qmf::ConsoleEvent &event); 44 | void call_method_async(QmfAsyncRequest *req, 45 | qmf::Data *data); 46 | }; 47 | 48 | #endif /* QMF_AGENT_DEFINED */ 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/qmf_job.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #ifndef QMF_JOB_H_DEFINED 22 | #define QMF_JOB_H_DEFINED 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | class QmfObject; 32 | 33 | class QmfAsyncRequest { 34 | private: 35 | uint32_t ref_count; 36 | public: 37 | enum job_state { 38 | JOB_INIT, 39 | JOB_SCHEDULED, 40 | JOB_RUNNING, 41 | JOB_COMPLETED, 42 | }; 43 | enum job_state state; 44 | QmfObject *obj; 45 | qpid::types::Variant::Map args; 46 | std::string method; 47 | void *user_data; 48 | uint32_t timeout; 49 | GTimer* time_queued; 50 | GTimer* time_execed; 51 | 52 | void ref() { ref_count++; }; 53 | void unref() { 54 | ref_count--; 55 | if (ref_count == 0) { 56 | delete this; 57 | } 58 | }; 59 | 60 | QmfAsyncRequest() : ref_count(1), state(JOB_INIT) { 61 | time_execed = g_timer_new(); 62 | time_queued = g_timer_new(); 63 | }; 64 | ~QmfAsyncRequest() { 65 | g_timer_destroy(time_execed); 66 | g_timer_destroy(time_queued); 67 | }; 68 | void log(int rc); 69 | }; 70 | 71 | #endif /* QMF_JOB_H_DEFINED */ 72 | -------------------------------------------------------------------------------- /src/qmf_multiplexer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #include "config.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | #include "qmf_agent.h" 35 | #include "qmf_multiplexer.h" 36 | 37 | using namespace std; 38 | using namespace qmf; 39 | 40 | bool 41 | QmfMultiplexer::process_events(void) 42 | { 43 | uint32_t rc = 0; 44 | ConsoleEvent event; 45 | QmfAgent *qa; 46 | map::iterator iter; 47 | 48 | while (session->nextEvent(event, qpid::messaging::Duration::IMMEDIATE)) { 49 | Agent a = event.getAgent(); 50 | if (event.getType() == CONSOLE_AGENT_ADD) { 51 | for (list::iterator it = _objects.begin(); 52 | it != _objects.end(); ++it) { 53 | if ((*it)->connect(a)) { 54 | qa = _agents[a.getName()]; 55 | qb_log(LOG_DEBUG, "connecting to %s", 56 | a.getName().c_str()); 57 | if (qa == NULL) { 58 | qa = new QmfAgent(a); 59 | _agents[a.getName()] = qa; 60 | } 61 | if (qa) { 62 | qa->add(*it); 63 | } 64 | } else { 65 | qb_log(LOG_DEBUG, "not connecting to %s", 66 | a.getName().c_str()); 67 | } 68 | } 69 | } else if (event.getType() == CONSOLE_AGENT_DEL) { 70 | qa = _agents[a.getName()]; 71 | _agents.erase(a.getName()); 72 | delete qa; 73 | } else { 74 | qa = _agents[a.getName()]; 75 | if (qa) { 76 | qa->process_event(event); 77 | } 78 | } 79 | } 80 | return true; 81 | } 82 | 83 | static int 84 | _poll_for_qmf_events(int32_t fd, int32_t revents, void *data) 85 | { 86 | QmfMultiplexer *m = (QmfMultiplexer *)data; 87 | qb_loop_timer_handle timer_handle; 88 | 89 | if (revents & POLLIN) { 90 | m->process_events(); 91 | } 92 | } 93 | 94 | void 95 | QmfMultiplexer::qmf_object_add(QmfObject *qc) 96 | { 97 | _objects.push_back(qc); 98 | } 99 | 100 | void 101 | QmfMultiplexer::start(void) 102 | { 103 | qb_loop_timer_handle timer_handle; 104 | int fd; 105 | qmf::posix::EventNotifier *event_notifier; 106 | 107 | connection = new qpid::messaging::Connection(_url, ""); 108 | connection->open(); 109 | 110 | session = new ConsoleSession(*connection, "max-agent-age:1"); 111 | session->setAgentFilter(_filter); 112 | session->open(); 113 | 114 | event_notifier = new qmf::posix::EventNotifier(*session); 115 | 116 | qb_log(LOG_DEBUG, "session to %s open [filter:%s", 117 | _url.c_str(), _filter.c_str()); 118 | 119 | qb_loop_poll_add(NULL, QB_LOOP_MED, event_notifier->getHandle(), 120 | POLLIN, this, _poll_for_qmf_events); 121 | } 122 | 123 | -------------------------------------------------------------------------------- /src/qmf_multiplexer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #ifndef QMF_MULTIPLEXER_H_DEFINED 22 | #define QMF_MULTIPLEXER_H_DEFINED 23 | 24 | #include "qmf_agent.h" 25 | #include "qmf_object.h" 26 | 27 | class QmfMultiplexer { 28 | private: 29 | qpid::messaging::Connection *connection; 30 | qmf::ConsoleSession *session; 31 | 32 | std::string _url; 33 | std::string _filter; 34 | 35 | std::list _objects; 36 | std::map _agents; 37 | public: 38 | QmfMultiplexer() {}; 39 | ~QmfMultiplexer() {}; 40 | void qmf_object_add(QmfObject *qc); 41 | void url_set(std::string s) { _url = s; }; 42 | void filter_set(std::string s) { _filter = s; }; 43 | 44 | bool process_events(void); 45 | void start(void); 46 | }; 47 | #endif /* QMF_MULTIPLEXER_H_DEFINED */ 48 | -------------------------------------------------------------------------------- /src/qmf_object.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #ifndef QMF_OBJECT_DEFINED 22 | #define QMF_OBJECT_DEFINED 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "qmf_job.h" 32 | 33 | class QmfAgent; 34 | 35 | class QmfObject { 36 | private: 37 | bool _connected; 38 | qmf::Data _qmf_data; 39 | QmfAgent * _qa; 40 | 41 | std::string _agent_name; 42 | std::string _query; 43 | std::string _prop_name; 44 | std::string _prop_value; 45 | 46 | std::list _dead_agents; 47 | std::list _pending_jobs; 48 | public: 49 | enum rpc_result { 50 | RPC_OK, 51 | RPC_TIMEOUT, 52 | RPC_NOT_CONNECTED, 53 | RPC_CANCELLED, 54 | RPC_EXCEPTION, 55 | }; 56 | typedef void (method_response_fn)(QmfAsyncRequest* ar, 57 | qpid::types::Variant::Map out_args, 58 | enum rpc_result rc); 59 | method_response_fn* _method_response_fn; 60 | 61 | typedef void (event_fn)(qmf::ConsoleEvent& e, 62 | void *user_data); 63 | event_fn* _event_fn; 64 | void* _event_user_data; 65 | 66 | typedef void (connection_event_fn)(void *user_data); 67 | connection_event_fn* _connection_event_fn; 68 | void* _connection_event_user_data; 69 | 70 | QmfObject() : _connected(false), _method_response_fn(NULL), 71 | _connection_event_fn(NULL), _event_fn(NULL) {}; 72 | ~QmfObject() {}; 73 | 74 | bool is_connected(void) { return _connected; }; 75 | bool connect(qmf::Agent &a); 76 | void disconnect(void); 77 | void agent_set(QmfAgent *a) {_qa = a;}; 78 | 79 | void query_set(std::string q) { _query = q; }; 80 | void prop_set(std::string n, std::string v) { 81 | _prop_name = n; 82 | _prop_value = v; 83 | }; 84 | std::string& agent_name_get(void) { return _agent_name; }; 85 | 86 | qmf::ConsoleEvent method_call(std::string method, 87 | qpid::types::Variant::Map in_args); 88 | void method_call_async(std::string method, 89 | qpid::types::Variant::Map in_args, 90 | void *user_data, 91 | uint32_t timeout); 92 | void method_response_handler_set(QmfObject::method_response_fn* fn) { 93 | _method_response_fn = fn; 94 | }; 95 | void event_handler_set(QmfObject::event_fn* fn, void *user_data) { 96 | _event_fn = fn; 97 | _event_user_data = user_data; 98 | }; 99 | void connection_event_handler_set(QmfObject::connection_event_fn* fn, 100 | void *user_data) { 101 | _connection_event_fn = fn; 102 | _connection_event_user_data = user_data; 103 | }; 104 | void method_response(QmfAsyncRequest* ar, 105 | qpid::types::Variant::Map out_args, 106 | enum rpc_result rc) { 107 | g_timer_stop(ar->time_execed); 108 | ar->state = QmfAsyncRequest::JOB_COMPLETED; 109 | if (rc != RPC_OK) { 110 | ar->log(rc); 111 | } 112 | (_method_response_fn)(ar, out_args, rc); 113 | }; 114 | void process_event(qmf::ConsoleEvent &event, QmfAsyncRequest *req); 115 | 116 | void run_pending_calls(void); 117 | }; 118 | 119 | #endif /* QMF_OBJECT_DEFINED */ 120 | -------------------------------------------------------------------------------- /src/recover.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #include "pcmk_pe.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "cape.h" 32 | #include "trans.h" 33 | 34 | void 35 | recover_init(struct recover* r, 36 | const char * escalation_failures, 37 | const char * escalation_period, 38 | recover_restart_fn_t recover_restart, 39 | recover_escalate_fn_t recover_escalate, 40 | recover_state_changing_fn_t recover_state_changing) 41 | { 42 | long val; 43 | char *endptr; 44 | 45 | qb_enter(); 46 | 47 | if (escalation_failures == NULL) { 48 | r->num_failures = -1; 49 | } else { 50 | val = strtol(escalation_failures, &endptr, 10); 51 | if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || 52 | (errno != 0 && val == 0) || 53 | (endptr == escalation_failures)) { 54 | r->num_failures = -1; 55 | } else { 56 | r->num_failures = val; 57 | } 58 | } 59 | 60 | if (escalation_period == NULL) { 61 | r->failure_period = -1; 62 | } else { 63 | val = strtol(escalation_period, &endptr, 10); 64 | if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || 65 | (errno != 0 && val == 0) || 66 | (endptr == escalation_period)) { 67 | r->failure_period = -1; 68 | } else { 69 | r->failure_period = val; 70 | } 71 | } 72 | 73 | r->restart = recover_restart; 74 | r->escalate = recover_escalate; 75 | r->state_changing = recover_state_changing; 76 | r->state = RECOVER_STATE_UNKNOWN; 77 | 78 | r->sw = NULL; 79 | if (r->failure_period > 0 && r->num_failures > 0) { 80 | r->sw = qb_util_stopwatch_create(); 81 | qb_util_stopwatch_split_ctl(r->sw, 82 | r->num_failures, 83 | QB_UTIL_SW_OVERWRITE); 84 | } 85 | 86 | qb_leave(); 87 | } 88 | 89 | void 90 | recover_state_set(struct recover* r, enum recover_state state) 91 | { 92 | int escalating = QB_FALSE; 93 | 94 | if (r->state == state) { 95 | return; 96 | } 97 | 98 | if (r->state_changing) { 99 | r->state_changing(r->instance, r->state, state); 100 | } 101 | r->state = state; 102 | 103 | if (r->state != RECOVER_STATE_FAILED) { 104 | return; 105 | } 106 | 107 | qb_enter(); 108 | 109 | if (r->num_failures > 0 && r->failure_period > 0) { 110 | uint64_t diff; 111 | float p; 112 | int last; 113 | qb_util_stopwatch_split(r->sw); 114 | 115 | last = qb_util_stopwatch_split_last(r->sw); 116 | qb_log(LOG_TRACE, "split number %d/%d", last+1, r->num_failures); 117 | if (last >= r->num_failures - 1) { 118 | diff = qb_util_stopwatch_time_split_get(r->sw, last, 119 | last - (r->num_failures - 1)); 120 | p = diff; 121 | p /= QB_TIME_US_IN_SEC; 122 | qb_log(LOG_TRACE, "split time %f/%d", p, r->failure_period); 123 | if (p <= r->failure_period) { 124 | escalating = QB_TRUE; 125 | qb_util_stopwatch_start(r->sw); 126 | } 127 | } 128 | } 129 | if (escalating) { 130 | r->escalate(r->instance); 131 | } else { 132 | r->restart(r->instance); 133 | } 134 | qb_leave(); 135 | } 136 | 137 | -------------------------------------------------------------------------------- /src/schema.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/trans.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Steven Dake 5 | * Angus Salkeld 6 | * 7 | * This file is part of pacemaker-cloud. 8 | * 9 | * pacemaker-cloud is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * pacemaker-cloud is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more detransportils. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with pacemaker-cloud. If not, see . 21 | */ 22 | #ifndef TRANS_H_DEFINED 23 | #define TRANS_H_DEFINED 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | #include "pcmk_pe.h" 29 | #include "cape.h" 30 | 31 | void transport_resource_action(struct assembly *a, 32 | struct resource *resource, 33 | struct pe_operation *op); 34 | 35 | void *transport_connect(struct assembly *a); 36 | 37 | void transport_disconnect(struct assembly *a); 38 | 39 | void transport_del(void *transport); 40 | 41 | void 42 | transport_execute(void *transport, 43 | void (*completion_func)(void *data, int rc), 44 | void (*timeout_func)(void *data), 45 | void *data, 46 | uint64_t timeout_msec, 47 | char *format, ...); 48 | 49 | /* *INDENT-OFF* */ 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | /* *INDENT-ON* */ 54 | 55 | #endif /* TRANS_H_DEFINED */ 56 | -------------------------------------------------------------------------------- /src/trans_cim.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Author: Zane Bitter 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #include "config.h" 23 | 24 | #include "trans.h" 25 | #include "cim_service.h" 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | 34 | 35 | typedef struct { 36 | void *transport; 37 | const char *service; 38 | int (*action_func)(void *, const char *); 39 | struct pe_operation *op; 40 | } cim_action_t; 41 | 42 | 43 | void * 44 | transport_connect(struct assembly *a) 45 | { 46 | qb_enter(); 47 | 48 | assert(a != NULL); 49 | 50 | if (!a->transport) { 51 | a->transport = cim_service_connect(a->address); 52 | } 53 | 54 | qb_leave(); 55 | 56 | return a->transport; 57 | } 58 | 59 | void 60 | transport_disconnect(struct assembly *a) 61 | { 62 | qb_enter(); 63 | 64 | assert(a != NULL); 65 | cim_service_disconnect(a->transport); 66 | 67 | qb_leave(); 68 | } 69 | 70 | static void 71 | perform_action(void *data) 72 | { 73 | enum ocf_exitcode result; 74 | cim_action_t *action = data; 75 | 76 | qb_enter(); 77 | 78 | assert(action != NULL); 79 | assert(action->action_func != NULL); 80 | 81 | result = action->action_func(action->transport, action->service); 82 | 83 | resource_action_completed(action->op, result); 84 | 85 | pe_resource_unref(action->op); 86 | free(data); 87 | 88 | qb_leave(); 89 | } 90 | 91 | void 92 | transport_resource_action(struct assembly *a, 93 | struct resource *resource, 94 | struct pe_operation *op) 95 | { 96 | int32_t result = -1; 97 | cim_action_t *action; 98 | 99 | qb_enter(); 100 | 101 | assert(a != NULL); 102 | assert(op != NULL); 103 | 104 | pe_resource_ref(op); 105 | 106 | action = malloc(sizeof(*action)); 107 | if (!action) { 108 | qb_log(LOG_ERR, "Failed to allocate resource action"); 109 | goto done; 110 | } 111 | 112 | action->transport = a->transport; 113 | action->op = op; 114 | action->service = op->rtype; 115 | 116 | // TODO handle OCF resources 117 | assert(strcmp(op->rclass, "lsb") == 0); 118 | 119 | if (strcmp(op->method, "monitor") == 0) { 120 | action->action_func = cim_service_started; 121 | } else { 122 | if (strcmp(op->method, "start") == 0) { 123 | action->action_func = cim_service_start; 124 | } else if (strcmp(op->method, "stop") == 0) { 125 | action->action_func = cim_service_stop; 126 | } else { 127 | assert(0); 128 | goto done; 129 | } 130 | } 131 | 132 | result = qb_loop_job_add(NULL, QB_LOOP_LOW, action, &perform_action); 133 | 134 | done: 135 | if (result) { 136 | recover_state_set(&a->recover, RECOVER_STATE_FAILED); 137 | pe_resource_unref(action->op); 138 | free(action); 139 | } 140 | qb_leave(); 141 | } 142 | 143 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.test 3 | f14-cpe-test 4 | cpe-tool2 5 | pe_test 6 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Red Hat, Inc. 2 | # 3 | # Authors: Angus Salkeld 4 | # 5 | # This file is part of pacemaker-cloud. 6 | # 7 | # pacemaker-cloud is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # pacemaker-cloud is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Lesser General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with pacemaker-cloud. If not, see . 19 | 20 | MAINTAINERCLEANFILES = Makefile.in 21 | AM_CFLAGS = -Wall 22 | 23 | noinst_PROGRAMS = cpe-tool2 pe_test 24 | 25 | cpe_tool2_SOURCES = cpe-tool2.c ../src/libinit.c 26 | cpe_tool2_CPPFLAGS = $(dbus_glib_1_CFLAGS) 27 | cpe_tool2_LDFLAGS = $(dbus_glib_1_LIBS) $(libqb_LIBS) 28 | 29 | pe_test_SOURCES = pe_test.c 30 | pe_test_CPPFLAGS = -Wall $(glib_CFLAGS) $(libxml2_CFLAGS) $(pcmk_CFLAGS) 31 | pe_test_LDADD = $(pcmk_LIBS) $(glib_LIBS) $(libxml2_LIBS) 32 | 33 | 34 | if HAVE_CHECK 35 | 36 | TESTS = recover.test basic.test escalation.test reconfig.test 37 | check_PROGRAMS = recover.test basic.test escalation.test reconfig.test 38 | 39 | recover_test_SOURCES = check_recover.c ../src/recover.c 40 | recover_test_CPPFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/src $(libqb_CFLAGS) \ 41 | $(glib_CFLAGS) $(libxml2_CFLAGS) 42 | recover_test_LDADD = @CHECK_LIBS@ $(libqb_LIBS) 43 | 44 | basic_test_SOURCES = check_basic.c ../src/pcmk_pe.c ../src/recover.c ../src/cape.c \ 45 | ../src/capeadmin.c 46 | basic_test_CPPFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/src $(libqb_CFLAGS) \ 47 | $(glib_CFLAGS) $(libxml2_CFLAGS) $(pcmk_CFLAGS) \ 48 | $(libxslt_CFLAGS) $(uuid_CFLAGS) 49 | basic_test_LDADD = @CHECK_LIBS@ $(libqb_LIBS) $(glib_LIBS) $(libxml2_LIBS) \ 50 | $(pcmk_LIBS) $(libxslt_LIBS) $(uuid_LIBS) 51 | 52 | escalation_test_SOURCES = check_escalation.c ../src/pcmk_pe.c ../src/recover.c \ 53 | ../src/cape.c ../src/capeadmin.c 54 | escalation_test_CPPFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/src $(libqb_CFLAGS) \ 55 | $(glib_CFLAGS) $(libxml2_CFLAGS) $(pcmk_CFLAGS) \ 56 | $(libxslt_CFLAGS) $(uuid_CFLAGS) 57 | escalation_test_LDADD = @CHECK_LIBS@ $(libqb_LIBS) $(glib_LIBS) $(libxml2_LIBS) \ 58 | $(pcmk_LIBS) $(libxslt_LIBS) $(uuid_LIBS) 59 | 60 | reconfig_test_SOURCES = check_reconfig.c ../src/pcmk_pe.c ../src/recover.c \ 61 | ../src/cape.c ../src/capeadmin.c 62 | reconfig_test_CPPFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/src $(libqb_CFLAGS) \ 63 | $(glib_CFLAGS) $(libxml2_CFLAGS) $(pcmk_CFLAGS) \ 64 | $(libxslt_CFLAGS) $(uuid_CFLAGS) 65 | reconfig_test_LDADD = @CHECK_LIBS@ $(libqb_LIBS) $(glib_LIBS) $(libxml2_LIBS) \ 66 | $(pcmk_LIBS) $(libxslt_LIBS) $(uuid_LIBS) 67 | 68 | 69 | endif 70 | 71 | if HAVE_SIM_SCALE 72 | noinst_PROGRAMS += sim-cape-recovery sim-cape-sshd-master sim-cape-sshd-dummy 73 | 74 | sim_cape_recovery_SOURCES = ../src/caped.c ../src/capeadmin.c ../src/recover.c ../src/cape.c ../src/pcmk_pe.c sim_recovery.c 75 | 76 | sim_cape_recovery_CPPFLAGS = @CHECK_CFLAGS@ -I$(top_srcdir)/src $(libqb_CFLAGS) \ 77 | $(glib_CFLAGS) $(libxml2_CFLAGS) $(pcmk_CFLAGS) \ 78 | $(libxslt_CFLAGS) $(uuid_CFLAGS) 79 | 80 | sim_cape_recovery_LDADD = @CHECK_LIBS@ $(libqb_LIBS) $(glib_LIBS) $(libxml2_LIBS) \ 81 | $(pcmk_LIBS) $(libxslt_LIBS) $(uuid_LIBS) 82 | 83 | 84 | sim_cape_sshd_master_SOURCES = ../src/caped.c ../src/capeadmin.c ../src/recover.c ../src/cape.c ../src/trans_ssh.c ../src/pcmk_pe.c sim_deltacloud_master.c 85 | 86 | sim_cape_sshd_master_CPPFLAGS = $(libqb_CFLAGS) $(glib_CFLAGS) $(libxml2_CFLAGS) \ 87 | $(pcmk_CFLAGS) $(libxslt_CFLAGS) $(uuid_LIBS) $(libdeltacloud_LIBS) \ 88 | $(libssh2_CFLAGS) -DSCALE_MASTER 89 | 90 | sim_cape_sshd_master_LDFLAGS = $(libqb_LIBS) $(glib_LIBS) $(libxml2_LIBS) \ 91 | $(pcmk_LIBS) $(libxslt_LIBS) $(uuid_LIBS) $(libdeltacloud_LIBS) \ 92 | $(libssh2_LIBS) 93 | 94 | sim_cape_sshd_dummy_SOURCES = ../src/caped.c ../src/capeadmin.c ../src/recover.c ../src/cape.c ../src/trans_ssh.c ../src/pcmk_pe.c sim_deltacloud_dummy.c 95 | 96 | sim_cape_sshd_dummy_CPPFLAGS = $(libqb_CFLAGS) $(glib_CFLAGS) $(libxml2_CFLAGS) \ 97 | $(pcmk_CFLAGS) $(libxslt_CFLAGS) $(uuid_LIBS) $(libdeltacloud_LIBS) \ 98 | $(libssh2_CFLAGS) -DSCALE_DUMMY 99 | 100 | sim_cape_sshd_dummy_LDFLAGS = $(libqb_LIBS) $(glib_LIBS) $(libxml2_LIBS) \ 101 | $(pcmk_LIBS) $(libxslt_LIBS) $(uuid_LIBS) $(libdeltacloud_LIBS) \ 102 | $(libssh2_LIBS) 103 | endif 104 | 105 | clean-generic: 106 | $(AM_V_GEN)rm -f *.log 107 | -------------------------------------------------------------------------------- /tests/check_recover.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "cape.h" 28 | 29 | static int num_restarts; 30 | static int num_escalations; 31 | 32 | static void 33 | _restart_cb(void* inst) 34 | { 35 | num_restarts++; 36 | qb_log(LOG_TRACE, "restart %d", num_restarts); 37 | } 38 | 39 | static void 40 | _escalate_cb(void* inst) 41 | { 42 | num_escalations++; 43 | qb_log(LOG_TRACE, "escalate %d", num_escalations); 44 | } 45 | 46 | 47 | START_TEST(test_recover) 48 | { 49 | struct recover r; 50 | 51 | recover_init(&r, "3", "1", _restart_cb, _escalate_cb, NULL); 52 | r.instance = &r; 53 | 54 | num_restarts = 0; 55 | num_escalations = 0; 56 | 57 | recover_state_set(&r, RECOVER_STATE_RUNNING); 58 | recover_state_set(&r, RECOVER_STATE_FAILED); 59 | recover_state_set(&r, RECOVER_STATE_RUNNING); 60 | recover_state_set(&r, RECOVER_STATE_FAILED); 61 | recover_state_set(&r, RECOVER_STATE_RUNNING); 62 | recover_state_set(&r, RECOVER_STATE_FAILED); 63 | ck_assert_int_eq(num_restarts, 2); 64 | ck_assert_int_eq(num_escalations, 1); 65 | 66 | /* after an escalation we start again */ 67 | num_restarts = 0; 68 | num_escalations = 0; 69 | 70 | recover_state_set(&r, RECOVER_STATE_RUNNING); 71 | recover_state_set(&r, RECOVER_STATE_FAILED); 72 | recover_state_set(&r, RECOVER_STATE_RUNNING); 73 | recover_state_set(&r, RECOVER_STATE_FAILED); 74 | ck_assert_int_eq(num_escalations, 0); 75 | recover_state_set(&r, RECOVER_STATE_RUNNING); 76 | recover_state_set(&r, RECOVER_STATE_FAILED); 77 | qb_log(LOG_DEBUG, "escalate here"); 78 | ck_assert_int_eq(num_restarts, 2); 79 | ck_assert_int_eq(num_escalations, 1); 80 | 81 | num_restarts = 0; 82 | num_escalations = 0; 83 | 84 | usleep(300000); 85 | /* it should only count from the first failure 86 | * after the escalation 87 | * (so below) 88 | */ 89 | recover_state_set(&r, RECOVER_STATE_RUNNING); 90 | recover_state_set(&r, RECOVER_STATE_FAILED); 91 | ck_assert_int_eq(num_restarts, 1); 92 | ck_assert_int_eq(num_escalations, 0); 93 | usleep(600000); 94 | 95 | recover_state_set(&r, RECOVER_STATE_RUNNING); 96 | recover_state_set(&r, RECOVER_STATE_FAILED); 97 | ck_assert_int_eq(num_restarts, 2); 98 | ck_assert_int_eq(num_escalations, 0); 99 | usleep(600000); 100 | 101 | recover_state_set(&r, RECOVER_STATE_RUNNING); 102 | recover_state_set(&r, RECOVER_STATE_FAILED); 103 | /* no escalation as it's been over a second */ 104 | ck_assert_int_eq(num_restarts, 3); 105 | ck_assert_int_eq(num_escalations, 0); 106 | 107 | usleep(300000); 108 | 109 | recover_state_set(&r, RECOVER_STATE_RUNNING); 110 | recover_state_set(&r, RECOVER_STATE_FAILED); 111 | ck_assert_int_eq(num_restarts, 3); 112 | ck_assert_int_eq(num_escalations, 1); 113 | 114 | recover_state_set(&r, RECOVER_STATE_RUNNING); 115 | recover_state_set(&r, RECOVER_STATE_FAILED); 116 | ck_assert_int_eq(num_restarts, 4); 117 | ck_assert_int_eq(num_escalations, 1); 118 | } 119 | END_TEST 120 | 121 | static Suite * 122 | recover_suite(void) 123 | { 124 | TCase *tc; 125 | Suite *s = suite_create("recover"); 126 | 127 | tc = tcase_create("recover"); 128 | tcase_add_test(tc, test_recover); 129 | suite_add_tcase(s, tc); 130 | 131 | return s; 132 | } 133 | 134 | int32_t main(void) 135 | { 136 | int32_t number_failed; 137 | 138 | Suite *s = recover_suite(); 139 | SRunner *sr = srunner_create(s); 140 | 141 | qb_log_init("check", LOG_USER, LOG_EMERG); 142 | qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE); 143 | qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, 144 | QB_LOG_FILTER_FILE, "*", LOG_TRACE); 145 | qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); 146 | qb_log_format_set(QB_LOG_STDERR, "[%6p] %f:%l %b"); 147 | 148 | srunner_run_all(sr, CK_VERBOSE); 149 | number_failed = srunner_ntests_failed(sr); 150 | srunner_free(sr); 151 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 152 | } 153 | -------------------------------------------------------------------------------- /tests/conductor/README: -------------------------------------------------------------------------------- 1 | run: Start a server simulating the conductor REST API 2 | cpe-rest: Initiate communication with the CPE REST API 3 | -------------------------------------------------------------------------------- /tests/conductor/conductor.rb: -------------------------------------------------------------------------------- 1 | require 'rexml/document' 2 | include REXML 3 | require 'rack/request' 4 | require 'rack/response' 5 | require 'pp' 6 | 7 | module Rack 8 | class Conductor 9 | def call(env) 10 | #puts PP.pp(env) 11 | 12 | # The request object only auto parses form data into .params 13 | # but we'll use it as if provides some simple and handy 14 | # wrapping of various http headers. 15 | req = Request.new(env) 16 | 17 | if req.path !~ /conductor\/api\/hooks\/?(\d+)?$/ 18 | return [404,{"Content-Type" => "text/html"},"not found"] 19 | end 20 | if req.post? && req.content_type != 'application/xml' 21 | return [415,{"Content-Type" => "text/html"}, "invalid Content-type"] 22 | end 23 | if req.post? 24 | return post(env) 25 | elsif req.get? 26 | return get(env) 27 | elsif req.delete? 28 | return delete(env) 29 | else 30 | return [501,{"Content-Type" => "text/html"},"method not supported"] 31 | end 32 | end 33 | 34 | # Return all hooks, or the specified hook. 35 | # The body will be the confirmation XML hook definition 36 | # generated and returned by the post method. 37 | def get(env) 38 | hook_id = env['REQUEST_PATH'].scan(/(\d+)/)[0].to_s 39 | if hook_id == '' 40 | hook_id = '1234' # just handle this one for now 41 | xml_response="\n" 42 | if ::File.exists?("hook."+hook_id) 43 | xml_response+=::File.open("hook."+hook_id, 'r').read 44 | end 45 | xml_response+="\n" 46 | return [200,{"Content-Type" => "application/xml"},xml_response] 47 | elsif hook_id == '1234' 48 | return [200,{"Content-Type" => "application/xml"}, 49 | ::File.open("hook."+hook_id, 'r').read] 50 | else 51 | return [404,{"Content-Type" => "text/html"},"not found"] 52 | end 53 | end 54 | 55 | # Remove the hook file if present, 56 | # or return 404 otherwise. 57 | def delete(env) 58 | hook_id = env['REQUEST_PATH'].scan(/(\d+)/)[0].to_s 59 | if !::File.exists?("hook."+hook_id) 60 | return [404,{"Content-Type" => "text/html"},"not found"] 61 | end 62 | ::File.delete("hook."+hook_id) 63 | return [204,{"Content-Type" => "text/html"},""] 64 | end 65 | 66 | # Parse the XML from the CPE agent which contains the hook URL. 67 | # Return this as confirmation in the XML body, and also set 68 | # the 'Location' header to which the CPE will communicate. 69 | def post(env) 70 | post_body = env['rack.input'].read 71 | 72 | begin 73 | doc = Document.new post_body 74 | cpe_uri = doc.elements["*/uri"] 75 | if cpe_uri.nil? 76 | raise 'missing uri element' 77 | else 78 | cpe_uri = cpe_uri.get_text.to_s 79 | end 80 | cpe_ver = doc.elements["*/version"] 81 | if cpe_ver.nil? 82 | raise 'missing version element' 83 | else 84 | cpe_ver = cpe_ver.get_text.to_s 85 | end 86 | rescue Exception => error 87 | return [400,{"Content-Type" => "text/plain"}, error.to_s] 88 | end 89 | 90 | if Integer(cpe_ver) != 1 91 | return [501,{"Content-Type" => "text/html"},"version not supported"] 92 | end 93 | 94 | hook_id = 1234.to_s # We currently only support a single cpe agent 95 | 96 | xml_response = "" 97 | xml_response += "\n" 98 | xml_response += " " + cpe_uri + "\n" 99 | xml_response += " " + cpe_ver + "\n" 100 | xml_response += "\n" 101 | 102 | # Record the hook for lookup later 103 | ::File.open("hook."+hook_id, 'w') {|f| f.write(xml_response) } 104 | 105 | location = env['REQUEST_URI'] + '/' + hook_id; 106 | 107 | return [201,{"Content-Type" => "application/xml", 108 | "Location" => location}, 109 | xml_response] 110 | 111 | # TODO: Populate the cped with a test deployment using: 112 | # Call ./cpe-rest test_started 1234 113 | end 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /tests/conductor/config.ru: -------------------------------------------------------------------------------- 1 | require 'rack' 2 | 3 | require 'conductor' 4 | 5 | run Rack::Conductor.new 6 | -------------------------------------------------------------------------------- /tests/conductor/cpe-rest: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'rubygems' 4 | require 'time' 5 | require 'restclient' 6 | require "rexml/document" 7 | include REXML 8 | 9 | def usage(why = nil) 10 | puts "failed: #{why}" if why 11 | puts "usage: cpe-rest [test_started|list] uuid" 12 | exit(1) 13 | end 14 | 15 | # TODO: add tests for other states: 16 | # Starting, Restarting, Started, Failed, Stopping, Stopped, Isolating, Isolated 17 | # Also and actions: 18 | # Start, Restart, Stop, Isolate 19 | # 'list' maps to a GET request to give full internal state (in xml format) 20 | # All other actions/states are xml format POSTS. 21 | POSSIBLE_VERBS = ['test_started', 'list'] 22 | 23 | # TODO: make this host:port configurable 24 | BASE_URL = 'http://localhost:8888/pacemaker-cloud/api' 25 | 26 | if POSSIBLE_VERBS.include? ARGV.first 27 | @verb = ARGV.shift 28 | else 29 | usage("invalid action '#{ARGV.first}") 30 | end 31 | 32 | @uuid = ARGV.shift 33 | 34 | usage("invalid uuid '#{@uuid}") if @uuid == nil && @verb != 'list' 35 | 36 | # Return a deployment xml element 37 | def deployment(id, instances, state) 38 | _dep = Element.new "deployment" 39 | _dep.attributes["id"] = id 40 | 41 | _state = _dep.add_element "state" 42 | _state.text = state 43 | 44 | _instances = _dep.add_element "instances" 45 | (1..instances).each { |i| _instances.add_element "instance", {"id"=>i} } 46 | 47 | return _dep 48 | end 49 | 50 | # Return an XML doc base for an event 51 | def event() 52 | doc = Document.new "" 53 | 54 | _dt = doc.root.add_element "datetime" 55 | _dt.text = Time.now.utc.iso8601 56 | 57 | return doc 58 | end 59 | 60 | def post(xml) 61 | begin 62 | # NB the to_s is required below or else the POST will be form_encoded? 63 | response = RestClient.post(BASE_URL, xml.to_s, :content_type => 'application/xml'){|response, request, result, &block| 64 | case response.code 65 | when 400..599 66 | print "Request failed ", response.code, ': ', response.to_str 67 | end 68 | } 69 | rescue Errno::EPIPE, RestClient::ServerBrokeConnection 70 | print "The server terminated the request\n" 71 | rescue Errno::ECONNREFUSED 72 | print "The server could not be found\n" 73 | end 74 | 75 | end 76 | 77 | if @verb == 'test_started' 78 | doc = event() 79 | 80 | # Create a deployment with between 1 and 3000 instances 81 | doc.root.add_element deployment(@uuid, rand(3000), 'STARTED') 82 | 83 | #doc.write( $stdout, 2 ) 84 | 85 | post(doc) 86 | 87 | # TODO: Verify the output from RestClient.get BASE_URL 88 | # correlates with the xml we sent above 89 | 90 | elsif @verb == 'list' 91 | print RestClient.get BASE_URL 92 | end 93 | -------------------------------------------------------------------------------- /tests/conductor/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # One can specify where this conductor API emulator will listen. 4 | # To tell cped to connect here, use its -C option, which can be 5 | # specified for the installed service by adding the following to 6 | # /etc/sysconfig/pacemaker-cloud 7 | # cped_opts="-C 13000" 8 | 9 | if [ "$1" = "--help" ]; then 10 | echo "$0 [-p PORT]" >&2 11 | exit 12 | fi 13 | 14 | if [ "$1" = "-p" ] && [ $(($2)) -gt 0 ]; then 15 | CONDUCTOR_PORT=$2 16 | shift; shift 17 | else 18 | CONDUCTOR_PORT=13000 19 | fi 20 | 21 | rm -f hook.* # remove any preexisting hooks 22 | rackup -p $CONDUCTOR_PORT config.ru 23 | -------------------------------------------------------------------------------- /tests/cpe-tool2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010-2011 Red Hat, Inc. 3 | * 4 | * Authors: Angus Salkeld 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "init-dbus.h" 28 | 29 | int 30 | main (int argc, char **argv) 31 | { 32 | (void)g_main_loop_new (NULL, FALSE); 33 | 34 | qb_log_init("cpe-tool", LOG_USER, LOG_DEBUG); 35 | dbus_init(); 36 | 37 | init_job_start("dped", "123-456-aaa"); 38 | sleep(5); 39 | init_job_stop("dped", "123-456-aaa"); 40 | 41 | dbus_fini(); 42 | return 0; 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /tests/pe_test.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2004 Andrew Beekhof 4 | * 5 | * This program is free software; you can redistribute it and/or 6 | * modify it under the terms of the GNU General Public 7 | * License as published by the Free Software Foundation; either 8 | * version 2 of the License, or (at your option) any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public 16 | * License along with this library; if not, write to the Free Software 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "config.h" 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | extern xmlNode * do_calculations(pe_working_set_t *data_set, 31 | xmlNode *xml_input, ha_time_t *now); 32 | extern void cleanup_alloc_calculations(pe_working_set_t *data_set); 33 | extern xmlNode* get_object_root(const char *object_type, xmlNode *the_root); 34 | 35 | static struct crm_option long_options[] = { 36 | /* Top-level Options */ 37 | {"help", 0, 0, '?', "This text"}, 38 | {"version", 0, 0, '$', "Version information" }, 39 | {"verbose", 0, 0, 'V', "Increase debug output\n"}, 40 | {"xml-file", 1, 0, 'x', "Retrieve XML from the named file"}, 41 | {0, 0, 0, 0} 42 | }; 43 | 44 | int 45 | main(int argc, char **argv) 46 | { 47 | xmlNode * cib_object = NULL; 48 | int argerr = 0; 49 | int flag; 50 | 51 | char *msg_buffer = NULL; 52 | pe_working_set_t data_set; 53 | const char *xml_file = NULL; 54 | 55 | /* disable glib's fancy allocators that can't be free'd */ 56 | GMemVTable vtable; 57 | 58 | vtable.malloc = malloc; 59 | vtable.realloc = realloc; 60 | vtable.free = free; 61 | vtable.calloc = calloc; 62 | vtable.try_malloc = malloc; 63 | vtable.try_realloc = realloc; 64 | 65 | g_mem_set_vtable(&vtable); 66 | 67 | crm_log_init_quiet(NULL, LOG_CRIT, FALSE, FALSE, argc, argv); 68 | crm_set_options("V?$G:x:", "[-?Vv] -[x] {other options}", long_options, 69 | "Calculate the cluster's response to the supplied cluster state\n"); 70 | 71 | while (1) { 72 | int option_index = 0; 73 | flag = crm_get_option(argc, argv, &option_index); 74 | if (flag == -1) 75 | break; 76 | 77 | switch(flag) { 78 | case 'x': 79 | xml_file = optarg; 80 | break; 81 | case 'V': 82 | cl_log_enable_stderr(TRUE); 83 | alter_debug(DEBUG_INC); 84 | break; 85 | case '$': 86 | case '?': 87 | crm_help(flag, 0); 88 | break; 89 | default: 90 | fprintf(stderr, "Option -%c is not yet supported\n", flag); 91 | ++argerr; 92 | break; 93 | } 94 | } 95 | 96 | if (optind < argc) { 97 | printf("non-option ARGV-elements: "); 98 | while (optind < argc) { 99 | printf("%s ", argv[optind++]); 100 | } 101 | printf("\n"); 102 | } 103 | 104 | if (optind > argc) { 105 | ++argerr; 106 | } 107 | 108 | if (argerr) { 109 | crm_err("%d errors in option parsing", argerr); 110 | crm_help('?', 1); 111 | } 112 | 113 | update_all_trace_data(); /* again, so we see which trace points got updated */ 114 | 115 | if (xml_file != NULL) { 116 | cib_object = filename2xml(xml_file); 117 | } 118 | 119 | if (cib_object == NULL && xml_file) { 120 | fprintf(stderr, "Could not parse configuration input from: %s\n", xml_file); 121 | return 4; 122 | 123 | } else if (cib_object == NULL) { 124 | fprintf(stderr, "No configuration specified\n"); 125 | crm_help('?', 1); 126 | } 127 | 128 | if (get_object_root(XML_CIB_TAG_STATUS, cib_object) == NULL) { 129 | create_xml_node(cib_object, XML_CIB_TAG_STATUS); 130 | } 131 | 132 | if (cli_config_update(&cib_object, NULL, FALSE) == FALSE) { 133 | free_xml(cib_object); 134 | return -1 /*cib_STALE*/; 135 | } 136 | 137 | if (validate_xml(cib_object, NULL, FALSE) != TRUE) { 138 | free_xml(cib_object); 139 | return /*cib_dtd_validation*/ -1; 140 | } 141 | 142 | set_working_set_defaults(&data_set); 143 | do_calculations(&data_set, cib_object, NULL); 144 | 145 | msg_buffer = dump_xml_formatted(data_set.graph); 146 | fprintf(stdout, "%s\n", msg_buffer); 147 | fflush(stdout); 148 | 149 | crm_free(msg_buffer); 150 | cleanup_alloc_calculations(&data_set); 151 | crm_log_deinit(); 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /tests/sim_recovery.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Red Hat, Inc. 3 | * 4 | * Authors: Steven Dake 5 | * 6 | * This file is part of pacemaker-cloud. 7 | * 8 | * pacemaker-cloud is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * pacemaker-cloud is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with pacemaker-cloud. If not, see . 20 | */ 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include "cape.h" 29 | #include "trans.h" 30 | 31 | #define FAILURE_PERCENT 90 32 | 33 | void transport_resource_action(struct assembly *a, 34 | struct resource *resource, 35 | struct pe_operation *op) 36 | { 37 | qb_enter(); 38 | 39 | if (strcmp(op->method, "monitor") == 0 && op->interval > 0) { 40 | if ((random() % 100) < FAILURE_PERCENT) { 41 | resource_action_completed(op, OCF_NOT_RUNNING); 42 | } else { 43 | resource_action_completed(op, op->target_outcome); 44 | } 45 | } else { 46 | resource_action_completed(op, op->target_outcome); 47 | } 48 | 49 | qb_leave(); 50 | 51 | return; 52 | } 53 | 54 | void *transport_connect(struct assembly *a) 55 | { 56 | qb_enter(); 57 | 58 | qb_leave(); 59 | 60 | return NULL; 61 | } 62 | 63 | void transport_disconnect(struct assembly *a) 64 | { 65 | qb_enter(); 66 | 67 | qb_leave(); 68 | } 69 | 70 | void transport_del(void *transport); 71 | 72 | int32_t instance_create(struct assembly *assembly) 73 | { 74 | qb_enter(); 75 | 76 | recover_state_set(&assembly->recover, RECOVER_STATE_UNKNOWN); 77 | 78 | recover_state_set(&assembly->recover, RECOVER_STATE_RUNNING); 79 | 80 | qb_leave(); 81 | return 0; 82 | } 83 | 84 | int instance_destroy(struct assembly *a) 85 | { 86 | qb_enter(); 87 | qb_leave(); 88 | 89 | return 0; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /tests/t_F16_x86_64_1.tdl: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /tests/templates/f14.ks: -------------------------------------------------------------------------------- 1 | #platform=x86, AMD64, or Intel EM64T 2 | #version=DEVEL 3 | # Install OS instead of upgrade 4 | install 5 | # Firewall configuration 6 | firewall --disabled 7 | # Use CDROM installation media 8 | cdrom 9 | # Root password 10 | rootpw --iscrypted $1$g7wJsgcU$gWTT/UE1AhXF86UB8GuuF/ 11 | # Network information 12 | network @NETWORK@ 13 | # System authorization information 14 | auth --useshadow --passalgo=md5 15 | # Use text mode install 16 | text 17 | # System keyboard 18 | keyboard us 19 | # System language 20 | lang en_US 21 | # SELinux configuration 22 | selinux --disabled 23 | # Do not configure the X Window System 24 | skipx 25 | # Installation logging level 26 | logging --level=info 27 | # Reboot after installation 28 | reboot 29 | # System timezone 30 | timezone America/New_York 31 | # System bootloader configuration 32 | bootloader --append="console=tty0 console=ttyS0,115200" --location=mbr 33 | # Clear the Master Boot Record 34 | zerombr 35 | # Partition clearing information 36 | clearpart --all --drives=vda 37 | # Disk partitioning information 38 | part /boot --fstype="ext4" --ondisk=vda --size=200 39 | part pv.2 --grow --ondisk=vda --size=1 40 | volgroup VolGroup00 --pesize=32768 pv.2 41 | logvol swap --fstype swap --name=LogVol01 --vgname=VolGroup00 --size=768 --grow --maxsize=1536 42 | logvol / --fstype ext4 --name=LogVol00 --vgname=VolGroup00 --size=1024 --grow 43 | 44 | %post 45 | %end 46 | 47 | %packages 48 | @hardware-support 49 | #matahari 50 | #httpd 51 | 52 | %end 53 | 54 | -------------------------------------------------------------------------------- /tests/templates/f14.tdl: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /tests/templates/rhel6.ks: -------------------------------------------------------------------------------- 1 | install 2 | text 3 | key --skip 4 | keyboard us 5 | lang en_US.UTF-8 6 | skipx 7 | network @NETWORK@ 8 | rootpw --iscrypted $1$g7wJsgcU$gWTT/UE1AhXF86UB8GuuF/ 9 | firewall --disabled 10 | authconfig --enableshadow --enablemd5 11 | selinux --permissive 12 | timezone --utc America/New_York 13 | bootloader --location=mbr --append="console=tty0 console=ttyS0,115200" 14 | zerombr yes 15 | clearpart --all 16 | 17 | part /boot --fstype ext4 --size=200 18 | part pv.2 --grow --size=1 19 | volgroup VolGroup00 --pesize=32768 pv.2 20 | logvol swap --fstype swap --name=LogVol01 --vgname=VolGroup00 --size=768 --grow --maxsize=1536 21 | logvol / --fstype ext4 --name=LogVol00 --vgname=VolGroup00 --size=1024 --grow 22 | reboot 23 | 24 | %packages 25 | @core 26 | @base 27 | matahari 28 | httpd 29 | %post 30 | -------------------------------------------------------------------------------- /tests/templates/rhel6.tdl: -------------------------------------------------------------------------------- 1 | 13 | --------------------------------------------------------------------------------