From 95f3cb50cedd942a1cc0fbf158dd8f4727ee7e6a Mon Sep 17 00:00:00 2001 From: root Date: Fri, 8 Jan 2016 01:36:34 -0500 Subject: [PATCH] Module upgrade to 3.1 --- README.md | 16 +- ajax_graph.php | 101 ++++++++ form/proxmox_vm.tform.php | 126 ++++++++++ form/proxmox_vm_informations.tform.php | 113 +++++++++ lib/lang/ca.lng | 8 + lib/lang/ca_proxmox_vm.lng | 44 ++++ lib/lang/ca_proxmox_vm_list.lng | 13 ++ lib/lang/en.lng | 8 + lib/lang/en_proxmox_vm.lng | 44 ++++ lib/lang/en_proxmox_vm_list.lng | 13 ++ lib/lang/fr.lng | 8 + lib/lang/fr_proxmox_vm.lng | 44 ++++ lib/lang/fr_proxmox_vm_list.lng | 13 ++ lib/module.conf.php | 41 ++++ lib/pve2_api.class.php | 308 +++++++++++++++++++++++++ list/proxmox_vm.list.php | 102 ++++++++ misc/vm_proxmox.sql | 23 ++ proxmox_action.php | 83 +++++++ proxmox_vm_del.php | 53 +++++ proxmox_vm_edit.php | 103 +++++++++ proxmox_vm_informations.php | 129 +++++++++++ proxmox_vm_list.php | 23 ++ templates/proxmox_vm_edit.htm | 37 +++ templates/proxmox_vm_graphiques.htm | 72 ++++++ templates/proxmox_vm_informations.htm | 78 +++++++ templates/proxmox_vm_list.htm | 61 +++++ 26 files changed, 1663 insertions(+), 1 deletion(-) create mode 100755 ajax_graph.php create mode 100755 form/proxmox_vm.tform.php create mode 100755 form/proxmox_vm_informations.tform.php create mode 100755 lib/lang/ca.lng create mode 100755 lib/lang/ca_proxmox_vm.lng create mode 100755 lib/lang/ca_proxmox_vm_list.lng create mode 100755 lib/lang/en.lng create mode 100755 lib/lang/en_proxmox_vm.lng create mode 100755 lib/lang/en_proxmox_vm_list.lng create mode 100755 lib/lang/fr.lng create mode 100755 lib/lang/fr_proxmox_vm.lng create mode 100755 lib/lang/fr_proxmox_vm_list.lng create mode 100755 lib/module.conf.php create mode 100755 lib/pve2_api.class.php create mode 100755 list/proxmox_vm.list.php create mode 100644 misc/vm_proxmox.sql create mode 100755 proxmox_action.php create mode 100755 proxmox_vm_del.php create mode 100755 proxmox_vm_edit.php create mode 100755 proxmox_vm_informations.php create mode 100755 proxmox_vm_list.php create mode 100755 templates/proxmox_vm_edit.htm create mode 100644 templates/proxmox_vm_graphiques.htm create mode 100644 templates/proxmox_vm_informations.htm create mode 100755 templates/proxmox_vm_list.htm diff --git a/README.md b/README.md index b5f6744..999f2f9 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ - ISPConfig 3.1 - Mysql database (same as ISPconfig) - Proxmox Virtual Environement +- Firewall permission ## Features - Manage your VPS : @@ -28,7 +29,7 @@ - Admin display : - Per client assignation -## TODO +## ToDo - Admin function : - Snapshot (add / remove) - Networks : Enable / Disable, Vlan, rate limit @@ -37,6 +38,19 @@ - Event log - Vps consol integration +## How To implement this module +- Create Proxmox user for ISPConfig communication with PVEVMUser right + - Assign VMs to this user +- Deploy the module into your ISPConfig setup -> /usr/local/ispconfig/interface/web +- Configure the module with your Proxmox user -> /usr/local/ispconfig/interface/lib/config.inc.local.php + - $conf["pve_username"] = 'username'; + - $conf["pve_password"] = 'password'; + - $conf["pve_link"] = 'hostname / ip of your cluster head'; + - $conf["pve_realm"] = 'realm'; +- Create MySQL table for this module -> misc/vm_proxmox.sql + + + # License Copyright (c) 2016, Oricom Internet All rights reserved. diff --git a/ajax_graph.php b/ajax_graph.php new file mode 100755 index 0000000..d0dfba1 --- /dev/null +++ b/ajax_graph.php @@ -0,0 +1,101 @@ +auth->check_module_permissions('proxmox'); + +$prox_id = $app->functions->intval($_REQUEST['vm']); +$condition = $_REQUEST['periode']; +$vm_pvesvr = $_REQUEST['vm_pvesvr']; + +if($_POST) +{ + // Vérification Apartenance VM (user vs admin) + $client_group_id = $app->functions->intval($_SESSION["s"]["user"]["default_group"]); + + if($_SESSION["s"]["user"]["typ"] != 'admin' && !$app->auth->has_clients($_SESSION['s']['user']['userid'])) + { + $vm = $app->db->queryOneRecord("SELECT vm_containers, vm_id FROM proxmox_vm WHERE id = $prox_id AND sys_groupid = $client_group_id"); + } + else + { + $vm = $app->db->queryOneRecord("SELECT vm_containers, vm_id FROM proxmox_vm WHERE id = $prox_id"); + } + + $vm_containers = $vm['vm_containers']; + $vm_id = $app->functions->intval($vm['vm_id']); + + + if(isset($vm_pvesvr) && isset($vm_id) && isset($vm_containers)) + { + $pve2 = new PVE2_API($conf["pve_link"], $conf["pve_username"], $conf["pve_realm"], $conf["pve_password"]); + + if ($pve2) { + if ($pve2->login()) { + switch ($condition) + { + case 'ah' : + $params = "&timeframe=hour&cf=AVERAGE"; + break; + case 'mh' : + $params = "&timeframe=hour&cf=MAX"; + break; + case 'ad' : + $params = "&timeframe=day&cf=AVERAGE"; + break; + case 'md' : + $params = "&timeframe=day&cf=MAX"; + break; + case 'aw' : + $params = "&timeframe=week&cf=AVERAGE"; + break; + case 'mw' : + $params = "&timeframe=week&cf=MAX"; + break; + case 'am' : + $params = "&timeframe=month&cf=AVERAGE"; + break; + case 'mm' : + $params = "&timeframe=month&cf=MAX"; + break; + case 'ay' : + $params = "&timeframe=year&cf=AVERAGE"; + break; + case 'my' : + $params = "&timeframe=year&cf=MAX"; + break; + } + + if( isset($params) ) + { + $graphs['cpu'] = $pve2->get("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/rrd?ds=cpu{$params}"); + $graphs['memory'] = $pve2->get("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/rrd?ds=mem,maxmem{$params}"); + $graphs['network'] = $pve2->get("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/rrd?ds=netin,netout{$params}"); + $graphs['disk'] = $pve2->get("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/rrd?ds=diskread,diskwrite{$params}"); + + $retour['CPU'] = base64_encode(utf8_decode($graphs['cpu']['image'])); + $retour['MEM'] = base64_encode(utf8_decode($graphs['memory']['image'])); + $retour['NET'] = base64_encode(utf8_decode($graphs['network']['image'])); + $retour['HDD'] = base64_encode(utf8_decode($graphs['disk']['image'])); + } + + echo json_encode($retour); + + + } else { + echo "Login to Proxmox Host failed.\n"; + exit; + } + } else { + echo "Could not create PVE2_API object.\n"; + exit; + } + } +} + + +?> diff --git a/form/proxmox_vm.tform.php b/form/proxmox_vm.tform.php new file mode 100755 index 0000000..f7573b3 --- /dev/null +++ b/form/proxmox_vm.tform.php @@ -0,0 +1,126 @@ + 0 id must match with id of current user +$form["auth_preset"]["groupid"] = 0; // 0 = default groupid of the user, > 0 id must match with groupid of current user +$form["auth_preset"]["perm_user"] = 'riud'; //r = read, i = insert, u = update, d = delete +$form["auth_preset"]["perm_group"] = 'riud'; //r = read, i = insert, u = update, d = delete +$form["auth_preset"]["perm_other"] = ''; //r = read, i = insert, u = update, d = delete + + +$form["tabs"]['proxmox_vm'] = array ( + 'title' => "Assignation", + 'width' => 100, + 'template' => "templates/proxmox_vm_edit.htm", + 'fields' => array ( + //################################# + // Begin Datatable fields + //################################# + 'server_id' => array ( + 'datatype' => 'INTEGER', + 'default' => 1, + 'value' => 1, + ), + 'vm_id' => array ( + 'datatype' => 'INTEGER', + 'formtype' => 'TEXT', + 'default' => '', + 'value' => '', + 'separator' => '', + 'width' => '30', + 'maxlength' => '255', + 'rows' => '', + 'cols' => '', + 'searchable' => 2 + ), + 'vm_containers' => array ( + 'datatype' => 'VARCHAR', + 'formtype' => 'SELECT', + 'default' => '', + 'value' => array('qemu' => 'qemu', 'lxc' => 'lxc'), + 'separator' => '', + 'width' => '30', + 'maxlength' => '255', + 'rows' => '', + 'cols' => '', + 'searchable' => 2 + ), + 'vm_name' => array ( + 'datatype' => 'VARCHAR', + 'formtype' => 'TEXT', + 'default' => '', + 'value' => '', + 'separator' => '', + 'width' => '30', + 'maxlength' => '255', + 'rows' => '', + 'cols' => '', + 'searchable' => 2 + ), + 'vm_description' => array ( + 'datatype' => 'TEXT', + 'formtype' => 'TEXTAREA', + 'default' => '', + 'value' => '', + 'separator' => '', + 'width' => '', + 'maxlength' => '', + 'rows' => '10', + 'cols' => '30' + ), + //################################# + // ENDE Datatable fields + //################################# + ) +); + + +?> diff --git a/form/proxmox_vm_informations.tform.php b/form/proxmox_vm_informations.tform.php new file mode 100755 index 0000000..9fbf92c --- /dev/null +++ b/form/proxmox_vm_informations.tform.php @@ -0,0 +1,113 @@ + 0 id must match with id of current user +$form["auth_preset"]["groupid"] = 0; // 0 = default groupid of the user, > 0 id must match with groupid of current user +$form["auth_preset"]["perm_user"] = 'riud'; //r = read, i = insert, u = update, d = delete +$form["auth_preset"]["perm_group"] = 'riud'; //r = read, i = insert, u = update, d = delete +$form["auth_preset"]["perm_other"] = ''; //r = read, i = insert, u = update, d = delete + +$form["tabs"]['informations'] = array ( + 'title' => "Informations", // Need to translate with variable + 'width' => 100, + 'template' => "templates/proxmox_vm_informations.htm", + 'fields' => array ( + //################################# + // Begin Datatable fields + //################################# + 'id' => array ( + 'datatype' => 'INTEGER', + 'formtype' => 'TEXT', + 'default' => '', + 'value' => '', + 'separator' => '', + 'width' => '30', + 'maxlength' => '255', + 'rows' => '', + 'cols' => '', + 'searchable' => 2 + ), + //################################# + // ENDE Datatable fields + //################################# + ) +); + +$form["tabs"]['graphics'] = array ( + 'title' => "Graphics", // Need to translate with variable + 'width' => 100, + 'template' => "templates/proxmox_vm_graphiques.htm", + 'readonly' => false, + /* + 'fields' => array ( + //################################# + // Begin Datatable fields + //################################# + 'id' => array ( + 'datatype' => 'INTEGER', + 'formtype' => 'TEXT', + 'default' => '', + 'value' => '', + 'separator' => '', + 'width' => '30', + 'maxlength' => '255', + 'rows' => '', + 'cols' => '', + 'searchable' => 2 + ), + + //################################# + // ENDE Datatable fields + //################################# + )*/ +); + +?> diff --git a/lib/lang/ca.lng b/lib/lang/ca.lng new file mode 100755 index 0000000..923411f --- /dev/null +++ b/lib/lang/ca.lng @@ -0,0 +1,8 @@ + diff --git a/lib/lang/ca_proxmox_vm.lng b/lib/lang/ca_proxmox_vm.lng new file mode 100755 index 0000000..6229814 --- /dev/null +++ b/lib/lang/ca_proxmox_vm.lng @@ -0,0 +1,44 @@ + diff --git a/lib/lang/ca_proxmox_vm_list.lng b/lib/lang/ca_proxmox_vm_list.lng new file mode 100755 index 0000000..4446a0a --- /dev/null +++ b/lib/lang/ca_proxmox_vm_list.lng @@ -0,0 +1,13 @@ + diff --git a/lib/lang/en.lng b/lib/lang/en.lng new file mode 100755 index 0000000..f442443 --- /dev/null +++ b/lib/lang/en.lng @@ -0,0 +1,8 @@ + diff --git a/lib/lang/en_proxmox_vm.lng b/lib/lang/en_proxmox_vm.lng new file mode 100755 index 0000000..6e4e4f9 --- /dev/null +++ b/lib/lang/en_proxmox_vm.lng @@ -0,0 +1,44 @@ + diff --git a/lib/lang/en_proxmox_vm_list.lng b/lib/lang/en_proxmox_vm_list.lng new file mode 100755 index 0000000..c50ca74 --- /dev/null +++ b/lib/lang/en_proxmox_vm_list.lng @@ -0,0 +1,13 @@ + diff --git a/lib/lang/fr.lng b/lib/lang/fr.lng new file mode 100755 index 0000000..923411f --- /dev/null +++ b/lib/lang/fr.lng @@ -0,0 +1,8 @@ + diff --git a/lib/lang/fr_proxmox_vm.lng b/lib/lang/fr_proxmox_vm.lng new file mode 100755 index 0000000..7c7edca --- /dev/null +++ b/lib/lang/fr_proxmox_vm.lng @@ -0,0 +1,44 @@ + diff --git a/lib/lang/fr_proxmox_vm_list.lng b/lib/lang/fr_proxmox_vm_list.lng new file mode 100755 index 0000000..4446a0a --- /dev/null +++ b/lib/lang/fr_proxmox_vm_list.lng @@ -0,0 +1,13 @@ + diff --git a/lib/module.conf.php b/lib/module.conf.php new file mode 100755 index 0000000..7c9edd3 --- /dev/null +++ b/lib/module.conf.php @@ -0,0 +1,41 @@ +auth->get_user_id(); + +$module['name'] = 'proxmox'; +$module['title'] = 'top_menu_vm'; +$module['template'] = 'module.tpl.htm'; +$module['startpage'] = 'proxmox/proxmox_vm_list.php'; +$module['tab_width'] = '60'; +$module['order'] = '90'; + + +//**** Templates menu +$items = array(); + +if($_SESSION["s"]["user"]["typ"] == 'admin') { + $items[] = array( 'title' => 'Assignation', + 'target' => 'content', + 'link' => 'proxmox/proxmox_vm_edit.php', + 'html_id' => 'proxmox_vm_list'); +} + + +if($_SESSION["s"]["user"]["typ"] == 'admin') { + $items[] = array( 'title' => 'Virtuals servers', + 'target' => 'content', + 'link' => 'proxmox/proxmox_vm_list.php', + 'html_id' => 'proxmox_vm_list'); +} + + +if(count($items)) +{ + $module['nav'][] = array( 'title' => 'VPS', + 'open' => 1, + 'items' => $items); +} + + + +?> diff --git a/lib/pve2_api.class.php b/lib/pve2_api.class.php new file mode 100755 index 0000000..2135b06 --- /dev/null +++ b/lib/pve2_api.class.php @@ -0,0 +1,308 @@ + + 65535) { + throw new PVE2_Exception("Port must be an integer between 1 and 65535.", 6); + } + // Check that verify_ssl is boolean. + if (!is_bool($verify_ssl)) { + throw new PVE2_Exception("verify_ssl must be boolean.", 7); + } + $this->hostname = $hostname; + $this->username = $username; + $this->realm = $realm; + $this->password = $password; + $this->port = $port; + $this->verify_ssl = $verify_ssl; + } + /* + * bool login () + * Performs login to PVE Server using JSON API, and obtains Access Ticket. + */ + public function login () { + // Prepare login variables. + $login_postfields = array(); + $login_postfields['username'] = $this->username; + $login_postfields['password'] = $this->password; + $login_postfields['realm'] = $this->realm; + $login_postfields_string = http_build_query($login_postfields); + unset($login_postfields); + // Perform login request. + $prox_ch = curl_init(); + curl_setopt($prox_ch, CURLOPT_URL, "https://{$this->hostname}:{$this->port}/api2/json/access/ticket"); + curl_setopt($prox_ch, CURLOPT_POST, true); + curl_setopt($prox_ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($prox_ch, CURLOPT_POSTFIELDS, $login_postfields_string); + curl_setopt($prox_ch, CURLOPT_SSL_VERIFYPEER, $this->verify_ssl); + $login_ticket = curl_exec($prox_ch); + $login_request_info = curl_getinfo($prox_ch); + curl_close($prox_ch); + unset($prox_ch); + unset($login_postfields_string); + if (!$login_ticket) { + // SSL negotiation failed or connection timed out + $this->login_ticket_timestamp = null; + return false; + } + $login_ticket_data = json_decode($login_ticket, true); + if ($login_ticket_data == null || $login_ticket_data['data'] == null) { + // Login failed. + // Just to be safe, set this to null again. + $this->login_ticket_timestamp = null; + if ($login_request_info['ssl_verify_result'] == 1) { + throw new PVE2_Exception("Invalid SSL cert on {$this->hostname} - check that the hostname is correct, and that it appears in the server certificate's SAN list. Alternatively set the verify_ssl flag to false if you are using internal self-signed certs (ensure you are aware of the security risks before doing so).", 4); + } + return false; + } else { + // Login success. + $this->login_ticket = $login_ticket_data['data']; + // We store a UNIX timestamp of when the ticket was generated here, + // so we can identify when we need a new one expiration-wise later + // on... + $this->login_ticket_timestamp = time(); + $this->reload_node_list(); + return true; + } + } + /* + * bool check_login_ticket () + * Checks if the login ticket is valid still, returns false if not. + * Method of checking is purely by age of ticket right now... + */ + protected function check_login_ticket () { + if ($this->login_ticket == null) { + // Just to be safe, set this to null again. + $this->login_ticket_timestamp = null; + return false; + } + if ($this->login_ticket_timestamp >= (time() + 7200)) { + // Reset login ticket object values. + $this->login_ticket = null; + $this->login_ticket_timestamp = null; + return false; + } else { + return true; + } + } + /* + * object action (string action_path, string http_method[, array put_post_parameters]) + * This method is responsible for the general cURL requests to the JSON API, + * and sits behind the abstraction layer methods get/put/post/delete etc. + */ + private function action ($action_path, $http_method, $put_post_parameters = null) { + // Check if we have a prefixed / on the path, if not add one. + if (substr($action_path, 0, 1) != "/") { + $action_path = "/".$action_path; + } + if (!$this->check_login_ticket()) { + throw new PVE2_Exception("Not logged into Proxmox host. No Login access ticket found or ticket expired.", 3); + } + // Prepare cURL resource. + $prox_ch = curl_init(); + curl_setopt($prox_ch, CURLOPT_URL, "https://{$this->hostname}:{$this->port}/api2/json{$action_path}"); + $put_post_http_headers = array(); + $put_post_http_headers[] = "CSRFPreventionToken: {$this->login_ticket['CSRFPreventionToken']}"; + // Lets decide what type of action we are taking... + switch ($http_method) { + case "GET": + // Nothing extra to do. + break; + case "PUT": + curl_setopt($prox_ch, CURLOPT_CUSTOMREQUEST, "PUT"); + // Set "POST" data. + $action_postfields_string = http_build_query($put_post_parameters); + curl_setopt($prox_ch, CURLOPT_POSTFIELDS, $action_postfields_string); + unset($action_postfields_string); + // Add required HTTP headers. + curl_setopt($prox_ch, CURLOPT_HTTPHEADER, $put_post_http_headers); + break; + case "POST": + curl_setopt($prox_ch, CURLOPT_POST, true); + // Set POST data. + $action_postfields_string = http_build_query($put_post_parameters); + curl_setopt($prox_ch, CURLOPT_POSTFIELDS, $action_postfields_string); + unset($action_postfields_string); + // Add required HTTP headers. + curl_setopt($prox_ch, CURLOPT_HTTPHEADER, $put_post_http_headers); + break; + case "DELETE": + curl_setopt($prox_ch, CURLOPT_CUSTOMREQUEST, "DELETE"); + // No "POST" data required, the delete destination is specified in the URL. + // Add required HTTP headers. + curl_setopt($prox_ch, CURLOPT_HTTPHEADER, $put_post_http_headers); + break; + default: + throw new PVE2_Exception("Error - Invalid HTTP Method specified.", 5); + return false; + } + curl_setopt($prox_ch, CURLOPT_HEADER, true); + curl_setopt($prox_ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($prox_ch, CURLOPT_COOKIE, "PVEAuthCookie=".$this->login_ticket['ticket']); + curl_setopt($prox_ch, CURLOPT_SSL_VERIFYPEER, false); + $action_response = curl_exec($prox_ch); + curl_close($prox_ch); + unset($prox_ch); + $split_action_response = explode("\r\n\r\n", $action_response, 2); + $header_response = $split_action_response[0]; + $body_response = $split_action_response[1]; + $action_response_array = json_decode($body_response, true); + $action_response_export = var_export($action_response_array, true); + error_log("----------------------------------------------\n" . + "FULL RESPONSE:\n\n{$action_response}\n\nEND FULL RESPONSE\n\n" . + "Headers:\n\n{$header_response}\n\nEnd Headers\n\n" . + "Data:\n\n{$body_response}\n\nEnd Data\n\n" . + "RESPONSE ARRAY:\n\n{$action_response_export}\n\nEND RESPONSE ARRAY\n" . + "----------------------------------------------"); + unset($action_response); + unset($action_response_export); + // Parse response, confirm HTTP response code etc. + $split_headers = explode("\r\n", $header_response); + if (substr($split_headers[0], 0, 9) == "HTTP/1.1 ") { + $split_http_response_line = explode(" ", $split_headers[0]); + if ($split_http_response_line[1] == "200") { + if ($http_method == "PUT") { + return true; + } else { + return $action_response_array['data']; + } + } else { + error_log("This API Request Failed.\n" . + "HTTP Response - {$split_http_response_line[1]}\n" . + "HTTP Error - {$split_headers[0]}"); + return false; + } + } else { + error_log("Error - Invalid HTTP Response.\n" . var_export($split_headers, true)); + return false; + } + if (!empty($action_response_array['data'])) { + return $action_response_array['data']; + } else { + error_log("\$action_response_array['data'] is empty. Returning false.\n" . + var_export($action_response_array['data'], true)); + return false; + } + } + /* + * array reload_node_list () + * Returns the list of node names as provided by /api2/json/nodes. + * We need this for future get/post/put/delete calls. + * ie. $this->get("nodes/XXX/status"); where XXX is one of the values from this return array. + */ + public function reload_node_list () { + $node_list = $this->get("/nodes"); + if (count($node_list) > 0) { + $nodes_array = array(); + foreach ($node_list as $node) { + $nodes_array[] = $node['node']; + } + $this->cluster_node_list = $nodes_array; + return true; + } else { + error_log(" Empty list of nodes returned in this cluster."); + return false; + } + } + /* + * array get_node_list () + * + */ + public function get_node_list () { + // We run this if we haven't queried for cluster nodes as yet, and cache it in the object. + if ($this->cluster_node_list == null) { + if ($this->reload_node_list() === false) { + return false; + } + } + return $this->cluster_node_list; + } + + /* + * bool|int get_next_vmid () + * Get Last VMID from a Cluster or a Node + * returns a VMID, or false if not found. + */ + public function get_next_vmid () { + $vmid = $this->get("/cluster/nextid"); + if ($vmid == null) { + return false; + } else { + return $vmid; + } + } + /* + * bool|string get_version () + * Return the version and minor revision of Proxmox Server + */ + public function get_version () { + $version = $this->get("/version"); + if ($version == null) { + return false; + } else { + return $version['version']; + } + } + /* + * object/array? get (string action_path) + */ + public function get ($action_path) { + return $this->action($action_path, "GET"); + } + /* + * bool put (string action_path, array parameters) + */ + public function put ($action_path, $parameters) { + return $this->action($action_path, "PUT", $parameters); + } + /* + * bool post (string action_path, array parameters) + */ + public function post ($action_path, $parameters) { + return $this->action($action_path, "POST", $parameters); + } + /* + * bool delete (string action_path) + */ + public function delete ($action_path) { + return $this->action($action_path, "DELETE"); + } + // Logout not required, PVEAuthCookie tokens have a 2 hour lifetime. +} +?> \ No newline at end of file diff --git a/list/proxmox_vm.list.php b/list/proxmox_vm.list.php new file mode 100755 index 0000000..bac5c22 --- /dev/null +++ b/list/proxmox_vm.list.php @@ -0,0 +1,102 @@ + "id", + 'datatype' => "INTEGER", + 'formtype' => "TEXT", + 'op' => "=", + 'prefix' => "", + 'suffix' => "", + 'width' => "", + 'value' => ""); + +if($_SESSION['s']['user']['typ'] == 'admin') { + $liste["item"][] = array( 'field' => "sys_groupid", + 'datatype' => "INTEGER", + 'formtype' => "SELECT", + 'op' => "=", + 'prefix' => "", + 'suffix' => "", + 'datasource' => array ( 'type' => 'SQL', + //'querystring' => 'SELECT groupid, name FROM sys_group WHERE groupid != 1 ORDER BY name', + 'querystring' => "SELECT sys_group.groupid,CONCAT(IF(client.company_name != '', CONCAT(client.company_name, ' :: '), ''), IF(client.contact_firstname != '', CONCAT(client.contact_firstname, ' '), ''), client.contact_name, ' (', client.username, IF(client.customer_no != '', CONCAT(', ', client.customer_no), ''), ')') as name FROM sys_group, client WHERE sys_group.groupid != 1 AND sys_group.client_id = client.client_id ORDER BY client.company_name, client.contact_name", + 'keyfield'=> 'groupid', + 'valuefield'=> 'name' + ), + 'width' => "", + 'value' => ""); + + + $liste["item"][] = array( 'field' => "vm_id", + 'datatype' => "INTEGER", + 'formtype' => "TEXT", + 'op' => "like", + 'prefix' => "%", + 'suffix' => "%", + 'width' => "", + 'value' => ""); + +} + + $liste["item"][] = array( 'field' => "vm_name", + 'datatype' => "VARCHAR", + 'formtype' => "TEXT", + 'op' => "like", + 'prefix' => "%", + 'suffix' => "%", + 'width' => "", + 'value' => ""); + + $liste["item"][] = array( 'field' => "vm_description", + 'datatype' => "VARCHAR", + 'formtype' => "TEXT", + 'op' => "like", + 'prefix' => "%", + 'suffix' => "%", + 'width' => "", + 'value' => ""); + +?> + diff --git a/misc/vm_proxmox.sql b/misc/vm_proxmox.sql new file mode 100644 index 0000000..c4ab157 --- /dev/null +++ b/misc/vm_proxmox.sql @@ -0,0 +1,23 @@ +-- +-- Table structure for table `proxmox_vm` +-- + +DROP TABLE IF EXISTS `proxmox_vm`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `proxmox_vm` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `sys_userid` int(11) NOT NULL DEFAULT '0', + `sys_groupid` int(11) NOT NULL DEFAULT '0', + `sys_perm_user` varchar(5) DEFAULT NULL, + `sys_perm_group` varchar(5) DEFAULT NULL, + `sys_perm_other` varchar(5) DEFAULT NULL, + `server_id` int(11) NOT NULL DEFAULT '1', + `vm_containers` varchar(45) NOT NULL, + `vm_name` varchar(100) NOT NULL, + `vm_id` int(11) NOT NULL, + `vm_description` text, + PRIMARY KEY (`id`), + UNIQUE KEY `prox_id_UNIQUE` (`id`) +) ENGINE=MYISAM DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; diff --git a/proxmox_action.php b/proxmox_action.php new file mode 100755 index 0000000..07557f9 --- /dev/null +++ b/proxmox_action.php @@ -0,0 +1,83 @@ +auth->check_module_permissions('proxmox'); + +$prox_id = $app->functions->intval($_REQUEST['id']); +$action = ( isset($_REQUEST['r']) && !empty($_REQUEST['r']) ? $_REQUEST['r'] : false ); +$vm_pvesvr = $_REQUEST['vm_pvesvr']; + +if(isset($prox_id) && !empty($prox_id)) +{ + $client_group_id = $app->functions->intval($_SESSION["s"]["user"]["default_group"]); + + if($_SESSION["s"]["user"]["typ"] != 'admin' && !$app->auth->has_clients($_SESSION['s']['user']['userid'])) { + $vm = $app->db->queryOneRecord("SELECT vm_containers, vm_id FROM proxmox_vm WHERE id = $prox_id AND sys_groupid = $client_group_id"); + } + else + { + $vm = $app->db->queryOneRecord("SELECT vm_containers, vm_id FROM proxmox_vm WHERE id = $prox_id"); + } + + + $vm_containers = $vm['vm_containers']; + $vm_id = $app->functions->intval($vm['vm_id']); + + if(isset($vm_pvesvr) && isset($vm_id) && isset($vm_containers)) + { + $pve2 = new PVE2_API($conf["pve_link"], $conf["pve_username"], $conf["pve_realm"], $conf["pve_password"]); + + if ($pve2) { + if ($pve2->login()) { + + switch ($action) + { + case 'start': + $vm_status = ( $pve2->post("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/status/start", array()) ? true : false ); + break; + case 'shutdown': + $vm_status = ( $pve2->post("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/status/shutdown", array()) ? true : false ); + break; + case 'reset': + $vm_status = ( $pve2->post("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/status/reset", array()) ? true : false ); + break; + case 'kill': + $vm_status = ( $pve2->post("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/status/stop", array()) ? true : false ); + break; + } + } else { + $vm_status = $app->error($app->tform->wordbook["vm_err_login"]); + exit; + } + } else { + $vm_status = $app->error($app->tform->wordbook["vm_err_api_obj"]); + exit; + } + } +} + + + +$app->uses('listform_actions'); +$app->listform_actions->onLoad(); + +?> diff --git a/proxmox_vm_del.php b/proxmox_vm_del.php new file mode 100755 index 0000000..e223b12 --- /dev/null +++ b/proxmox_vm_del.php @@ -0,0 +1,53 @@ +auth->check_module_permissions('proxmox'); + + + + +$app->uses("tform_actions"); +$app->tform_actions->onDelete(); + +?> diff --git a/proxmox_vm_edit.php b/proxmox_vm_edit.php new file mode 100755 index 0000000..26bf6db --- /dev/null +++ b/proxmox_vm_edit.php @@ -0,0 +1,103 @@ +auth->check_module_permissions('proxmox'); + +// Loading classes +$app->uses('tpl,tform,tform_actions'); +$app->load('tform_actions'); + + +class page_action extends tform_actions { + + function onShowNew() { + global $app, $conf; + + parent::onShowNew(); + } + + function onShowEnd() { + global $app, $conf; + + + if($_SESSION["s"]["user"]["typ"] == 'admin') { + // Getting Clients of the user + $sql = "SELECT sys_group.groupid, sys_group.name, CONCAT(IF(client.company_name != '', CONCAT(client.company_name, ' :: '), ''), client.contact_name, ' (', client.username, IF(client.customer_no != '', CONCAT(', ', client.customer_no), ''), ')') as contactname FROM sys_group, client WHERE sys_group.client_id = client.client_id AND sys_group.client_id > 0 ORDER BY client.company_name, client.contact_name, sys_group.name"; + + $clients = $app->db->queryAllRecords($sql); + $client_select = ''; + if($_SESSION["s"]["user"]["typ"] == 'admin') $client_select .= ""; + //$tmp_data_record = $app->tform->getDataRecord($this->id); + if(is_array($clients)) { + foreach( $clients as $client) { + $selected = @(is_array($this->dataRecord) && ($client["groupid"] == $this->dataRecord['client_group_id'] || $client["groupid"] == $this->dataRecord['sys_groupid']))?'SELECTED':''; + $client_select .= "\r\n"; + } + } + $app->tpl->setVar("client_group_id", $client_select); + + } + + parent::onShowEnd(); + } + + function onSubmit() { + global $app, $conf; + + parent::onSubmit(); + } + + + function onAfterInsert() { + global $app, $conf; + + if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) { + $client_group_id = $app->functions->intval($this->dataRecord["client_group_id"]); + $app->db->query("UPDATE proxmox_vm SET sys_groupid = $client_group_id, sys_perm_group = 'ru' WHERE id = ".$this->id); + } + if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) { + $client_group_id = $app->functions->intval($this->dataRecord["client_group_id"]); + $app->db->query("UPDATE proxmox_vm SET sys_groupid = $client_group_id, sys_perm_group = 'riud' WHERE id = ".$this->id); + } + + } + + + function onBeforeUpdate() { + global $app, $conf; + } + + function onAfterUpdate() { + global $app, $conf; + + if($_SESSION["s"]["user"]["typ"] == 'admin' && isset($this->dataRecord["client_group_id"])) { + $client_group_id = $app->functions->intval($this->dataRecord["client_group_id"]); + $app->db->query("UPDATE proxmox_vm SET sys_groupid = $client_group_id, sys_perm_group = 'ru' WHERE id = ".$this->id); + } + if($app->auth->has_clients($_SESSION['s']['user']['userid']) && isset($this->dataRecord["client_group_id"])) { + $client_group_id = $app->functions->intval($this->dataRecord["client_group_id"]); + $app->db->query("UPDATE proxmox_vm SET sys_groupid = $client_group_id, sys_perm_group = 'riud' WHERE id = ".$this->id); + } + + + } +} + +$page = new page_action; +$page->onLoad(); + +?> \ No newline at end of file diff --git a/proxmox_vm_informations.php b/proxmox_vm_informations.php new file mode 100755 index 0000000..f4a6204 --- /dev/null +++ b/proxmox_vm_informations.php @@ -0,0 +1,129 @@ +auth->check_module_permissions('proxmox'); + + +// Loading classes +$app->uses('tpl,tform,tform_actions'); +$app->load('tform'); + + +class page_action extends tform_actions { + + function onShowEnd() { + global $app, $conf; + + $vm_info['vm_id'] = $app->functions->intval($this->dataRecord['vm_id']); + + $pve2 = new PVE2_API($conf["pve_link"], $conf["pve_username"], $conf["pve_realm"], $conf["pve_password"]); + + if ($pve2) { + if ($pve2->login()) { + + $vm_id = $app->functions->intval($this->dataRecord['vm_id']); + $vm_containers = $this->dataRecord['vm_containers'] ; + + + $vm_temp = $pve2->get("/cluster/resources"); + $key = array_search($vm_id, array_column( $vm_temp , 'vmid')); + $vm_pvesvr = $vm_temp[$key]['node']; + + $app->tpl->setVar("vm_id", $vm_info['vm_id']); + $app->tpl->setVar("vm_pvesvr", $vm_pvesvr); + + switch($_REQUEST['next_tab']) + { + case 'graphics': + //DO SOMETHING HERE + break; + + case 'informations': + default: + $vm_status = $pve2->get("/nodes/{$vm_pvesvr}/{$vm_containers}/{$vm_id}/status/current"); + + if ($vm_status != false) + { + $app->tpl->setVar("vm_name", $vm_status['name']); + $app->tpl->setVar("vm_status", $vm_status['status']); + $app->tpl->setVar("vm_uptime", $app->functions->intval($vm_status['uptime'] / 60 ) ); + $app->tpl->setVar("vm_load", number_format( $vm_status['cpu'], 2 ) ); + $app->tpl->setVar("vm_cpu", $vm_status['cpus'] ); + $app->tpl->setVar("vm_mem", $app->functions->intval($vm_status['mem']/1024/1024 ) ); + $app->tpl->setVar("vm_maxmem", $app->functions->intval($vm_status['maxmem']/1024/1024 ) ); + $app->tpl->setVar("vm_maxhdd", $app->functions->intval($vm_status['maxdisk'] /1024 /1024 / 1024 ) ); + + $vm_percent_used = ($vm_status['mem'] * 100) / $vm_status['maxmem'] ; + $app->tpl->setVar("used_percentage", $app->functions->intval($vm_percent_used) ); + } + else + { + $app->error($app->tform->wordbook["vm_err_assignation"]); + } + break; + + } + + + + } else { + //print("Login to Proxmox Host failed.\n"); + $app->error($app->tform->wordbook["vm_err_login"]); + exit; + } + } else { + //print("Could not create PVE2_API object.\n"); + $app->error($app->tform->wordbook["vm_err_api_obj"]); + exit; + } + + parent::onShowEnd(); + } + + /* + function onSubmit() { + global $app, $conf; + + parent::onSubmit(); + } + + + + function onAfterInsert() { + global $app, $conf; + + } + + function onBeforeUpdate() { + global $app, $conf; + + } + + function onAfterUpdate() { + global $app, $conf; + + } + */ +} + + +$page = new page_action; +$page->onLoad(); + +?> diff --git a/proxmox_vm_list.php b/proxmox_vm_list.php new file mode 100755 index 0000000..addfb52 --- /dev/null +++ b/proxmox_vm_list.php @@ -0,0 +1,23 @@ +auth->check_module_permissions('proxmox'); + +$app->uses('listform_actions'); + +$app->listform_actions->onLoad(); + +?> diff --git a/templates/proxmox_vm_edit.htm b/templates/proxmox_vm_edit.htm new file mode 100755 index 0000000..9d00aaa --- /dev/null +++ b/templates/proxmox_vm_edit.htm @@ -0,0 +1,37 @@ + +

+ + + +
+ +
+
+ +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ + + +
+ + +
+ + diff --git a/templates/proxmox_vm_graphiques.htm b/templates/proxmox_vm_graphiques.htm new file mode 100644 index 0000000..89c88f4 --- /dev/null +++ b/templates/proxmox_vm_graphiques.htm @@ -0,0 +1,72 @@ + + + + +

+ +

{tmpl_var name="toolsarea_head_txt"}

+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ + + diff --git a/templates/proxmox_vm_informations.htm b/templates/proxmox_vm_informations.htm new file mode 100644 index 0000000..dab5aaa --- /dev/null +++ b/templates/proxmox_vm_informations.htm @@ -0,0 +1,78 @@ + + + + +

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{tmpl_var name='vm_id'}
{tmpl_var name='vm_pvesvr'}
{tmpl_var name='vm_name'}
{tmpl_var name='vm_status'}
{tmpl_var name='vm_load'}
{tmpl_var name='vm_uptime'} {tmpl_var name='vm_time_txt'}
{tmpl_var name='vm_cpu'}
+
+
+ {tmpl_var name='used'} {tmpl_var name='of_txt'} {tmpl_var name='soft'} +
+
+ ( {tmpl_var name='vm_mem'} / {tmpl_var name='vm_maxmem'} MB ) +
{tmpl_var name='vm_maxhdd'} GB
+
+ + + + + +
+
+ +
+
diff --git a/templates/proxmox_vm_list.htm b/templates/proxmox_vm_list.htm new file mode 100755 index 0000000..11daab8 --- /dev/null +++ b/templates/proxmox_vm_list.htm @@ -0,0 +1,61 @@ + +

+ +

{tmpl_var name="toolsarea_head_txt"}

+ + + + + + +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{tmpl_var name='search_limit'}
+ +
{tmpl_var name="sys_groupid"}{tmpl_var name="vm_id"}{tmpl_var name="vm_name"}{tmpl_var name="vm_description"} + + + + +
{tmpl_var name='globalsearch_noresults_text_txt'}
+
-- GitLab