| 1 | = Setup PVE Development Environment = |
| 2 | |
| 3 | 1. Install Debian 'jessie' |
| 4 | 2. Configure pvetest repository in apt sources.list |
| 5 | |
| 6 | deb http://download.proxmox.com/debian jessie pvetest |
| 7 | |
| 8 | 3. Add our repository key with apt-key: |
| 9 | |
| 10 | wget -O- "http://download.proxmox.com/debian/key.asc" | apt-key add - |
| 11 | |
| 12 | 4. make sure you have a read IP address for your hostname in /etc/hosts |
| 13 | (using 127.0.1.1 will not work) |
| 14 | |
| 15 | 5. run: apt-get update |
| 16 | 6. run: apt-get dist-upgrade |
| 17 | 7. run: apt-get install proxmox-ve-3.10.0 |
| 18 | |
| 19 | You should now have a working Proxmox VE installation. |
| 20 | |
| 21 | = Install build prerequisites for development environment = |
| 22 | |
| 23 | apt-get -y install build-essential git-core debhelper autotools-dev \ |
| 24 | autogen dh-autoreconf dkms doxygen check pkg-config groff quilt dpatch \ |
| 25 | automake autoconf libtool lintian libdevel-cycle-perl libjson-perl \ |
| 26 | libcommon-sense-perl liblinux-inotify2-perl libio-stringy-perl \ |
| 27 | libstring-shellquote-perl dh-systemd rpm2cpio libsqlite3-dev sqlite3 \ |
| 28 | libglib2.0-dev librrd-dev librrds-perl rrdcached libdigest-hmac-perl \ |
| 29 | libxml-parser-perl gdb libcrypt-openssl-random-perl \ |
| 30 | libcrypt-openssl-rsa-perl libnet-ldap-perl libauthen-pam-perl \ |
| 31 | libjson-xs-perl libterm-readline-gnu-perl oathtool libmime-base32-perl \ |
| 32 | liboath0 libpci-dev texi2html libsdl1.2-dev libgnutls28-dev \ |
| 33 | libspice-protocol-dev xfslibs-dev libnuma-dev libaio-dev \ |
| 34 | pve-libspice-server-dev libusbredirparser-dev glusterfs-common \ |
| 35 | libusb-1.0-0-dev librbd-dev libpopt-dev iproute bridge-utils numactl \ |
| 36 | glusterfs-common ceph-common python-ceph libgoogle-perftools4 \ |
| 37 | libfile-chdir-perl lvm2 glusterfs-client liblockfile-simple-perl \ |
| 38 | libsystemd-daemon-dev libreadline-gplv2-dev libio-multiplex-perl \ |
| 39 | libnetfilter-log-dev libipset3 ipset socat libsasl2-dev libogg-dev \ |
| 40 | python-pyparsing libfilesys-df-perl libcrypt-ssleay-perl \ |
| 41 | libfile-readbackwards-perl libanyevent-perl libanyevent-http-perl \ |
| 42 | unzip liblocale-po-perl vlan ifenslave-2.6 libfile-sync-perl cstream \ |
| 43 | lzop dtach apt-transport-https hdparm gdisk parted ttf-dejavu-core \ |
| 44 | liblzma-dev dosfstools mtools libxen-dev libfuse-dev libcorosync-pve-dev \ |
| 45 | libqb-dev libapparmor-dev docbook2x libcap-dev dh-apparmor libcgmanager-dev \ |
| 46 | graphviz libseccomp-dev libglib-perl libgtk3-perl libnss3-dev libdlm-dev \ |
| 47 | libudev-dev |
| 48 | |
| 49 | = Compile PVE packages from Source = |
| 50 | |
| 51 | Download and install the following git modules in order from top to bottom: |
| 52 | |
| 53 | # git clone git://git.proxmox.com/git/<PACKAGE.git> |
| 54 | |
| 55 | You currently need the following packages: |
| 56 | |
| 57 | libqb.git |
| 58 | corosync-pve.git |
| 59 | pve-common.git |
| 60 | pve-cluster.git |
| 61 | lvm.git |
| 62 | pve-access-control.git |
| 63 | pve-storage.git |
| 64 | pve-qemu-kvm.git |
| 65 | qemu-server.git |
| 66 | vncterm.git |
| 67 | spiceterm.git |
| 68 | #vzquota.git |
| 69 | #vzctl.git |
| 70 | #fence-agents-pve.git |
| 71 | #resource-agents-pve.git |
| 72 | pve-manager.git |
| 73 | #pve-kernel-3.10.0.git |
| 74 | libiscsi.git |
| 75 | #gfs2-utils.git |
| 76 | ksm-control-daemon.git |
| 77 | pve-container.git |
| 78 | pve-firewall.git |
| 79 | pve-kernel.git |
| 80 | |
| 81 | Most packages can be installed with 'make dinstall' command. |
| 82 | |
| 83 | 4. Reboot the system. |
| 84 | 5. Learn to use the quilt patch scripts. |
| 85 | 6. Happy coding. |
| 86 | |
| 87 | There is an experimental package containing the API documentation |
| 88 | as ExtJS application: |
| 89 | |
| 90 | pve2-api-doc.git |
| 91 | |
| 92 | You can view the source code at: |
| 93 | |
| 94 | https://git.proxmox.com |
| 95 | |
| 96 | |
| 97 | = REST vs. SOAP = |
| 98 | |
| 99 | We decided to change our SOAP API (1.X) and use a REST like API. The |
| 100 | concept is described in [1] (Resource Oriented Architecture |
| 101 | (ROA)). The main advantage is that we are able to remove a lot of code |
| 102 | (the whole SOAP stack) to reduce software complexity. |
| 103 | |
| 104 | We also moved away from server side content generation. Instead we use |
| 105 | the ExtJS Rich Internet Application Framework |
| 106 | (http://www.sencha.com). |
| 107 | |
| 108 | That framework, like any other AJAX toolkit, can talk directly to the |
| 109 | REST API using JSON. So we were able to remove the server side |
| 110 | template toolkit completely. |
| 111 | |
| 112 | = JSON and JSON Schema = |
| 113 | |
| 114 | We use JSON as data format, because it is simple and parse-able by any |
| 115 | web browser. |
| 116 | |
| 117 | Additionally, we use JSON Schema [2] to formally describe our API. So |
| 118 | we can automatically generate the whole API Documentation, and we can |
| 119 | verify all parameters and return values. |
| 120 | |
| 121 | A great side effect was that we are able to use JSON Schema to |
| 122 | produce command line argument parsers automatically. In fact, the REST |
| 123 | API and the command line tools use the same code. |
| 124 | |
| 125 | Object linkage is done using the JSON Hyper Schema (links property). |
| 126 | |
| 127 | A small utility called 'pvesh' exposes the whole REST API on the command |
| 128 | line. |
| 129 | |
| 130 | So here is a summary of the advantage: |
| 131 | |
| 132 | - easy, human readable data format (native web browser format) |
| 133 | - automatic parameter verification (we can also verify return values) |
| 134 | - automatic generation of API documentation |
| 135 | - easy way to create command line tools (using same API). |
| 136 | |
| 137 | = API Implementation (PVE::RESTHandler) = |
| 138 | |
| 139 | All classes exposing methods on the API use PVE::RESTHandler as base class. |
| 140 | |
| 141 | use base qw(PVE::RESTHandler); |
| 142 | |
| 143 | To expose methods, one needs to call register_method(): |
| 144 | |
| 145 | __PACKAGE__->register_method ($schema); |
| 146 | |
| 147 | Where $schema is a PVE method schema as described in |
| 148 | PVE::JSONSchema. It includes a description of parameters and return |
| 149 | values, and a reference to the actual code |
| 150 | |
| 151 | __PACKAGE__->register_method ({ |
| 152 | name => 'echo', |
| 153 | path => 'echo', |
| 154 | method => 'GET', |
| 155 | description => "simple return value of parameter 'text'", |
| 156 | parameters => { |
| 157 | additionalProperties => 0, |
| 158 | properties => { |
| 159 | text => { |
| 160 | type => 'string', |
| 161 | } |
| 162 | }, |
| 163 | }, |
| 164 | returns => { |
| 165 | type => 'string', |
| 166 | }, |
| 167 | code => sub { |
| 168 | my ($conn, $resp, $param) = @_; |
| 169 | |
| 170 | return $param->{text}; |
| 171 | } |
| 172 | }); |
| 173 | |
| 174 | The 'name' property is only used if you want to call the method |
| 175 | directly from Perl. You can do that using: |
| 176 | |
| 177 | print __PACKAGE__->echo({ text => "a test" }); |
| 178 | |
| 179 | We use Perl's AUTOLOAD feature to implement this. Note: You need to |
| 180 | pass parameters a HASH reference. |
| 181 | |
| 182 | There is a special helper method called cli_handler(). This is used by |
| 183 | the CLIHandler Class for command line tools, where you want to pass |
| 184 | arguments as array of strings. This uses Getopt::Long to parse parameters. |
| 185 | |
| 186 | There is a second way to map names to methods - using the 'path' |
| 187 | property. And you can register subclasses. That way you can set up a |
| 188 | filesystem like hierarchy to access methods. |
| 189 | |
| 190 | Here is an example: |
| 191 | ---------------------------- |
| 192 | package C1; |
| 193 | |
| 194 | __PACKAGE__->register_method ({ |
| 195 | subclass => "C2", |
| 196 | path => 'sub2', |
| 197 | }); |
| 198 | |
| 199 | |
| 200 | __PACKAGE__->register_method ({ |
| 201 | name => 'list1', |
| 202 | path => 'index', |
| 203 | method => 'GET', |
| 204 | ... |
| 205 | }); |
| 206 | |
| 207 | package C2; |
| 208 | |
| 209 | __PACKAGE__->register_method ({ |
| 210 | name => 'list2', |
| 211 | path => 'index', |
| 212 | method => 'GET', |
| 213 | ... |
| 214 | }); |
| 215 | ------------------------------- |
| 216 | |
| 217 | The utily method find_handler (in PVE::RESTHandler) can be use to do |
| 218 | 'path' related method lookups. |
| 219 | |
| 220 | C1->find_handler('GET', "/index") => C1::list1 |
| 221 | C1->find_handler('GET', "/sub2/index") => C2::list2 |
| 222 | |
| 223 | The HTTP server use the URL (a path) to find the corresponding method. |
| 224 | |
| 225 | |
| 226 | = References = |
| 227 | |
| 228 | [1] RESTful Web Services |
| 229 | Web services for the real world |
| 230 | |
| 231 | By |
| 232 | Leonard Richardson, Sam Ruby |
| 233 | Publisher: |
| 234 | O'Reilly Media |
| 235 | Released: |
| 236 | May 2007 |
| 237 | |
| 238 | [2] JSON Schema links: http://json-schema.org/ |