Удаленное управление питанием сервера через Rack PDU
Удаленное управление питанием сервера через Rack PDU
Когда-то по работе возникла необходимость автоматизированного управления серверами в стойке дата-центра. Вопрос с контролем за питанием был решен через power-свич (Switched Rack PDU), который имел возможность удаленного управления по telnet. Для эмуляции действий пользователя я написал вот такой небольшой класс на PHP. Может быть пригодится кому-нибудь еще.
Комментариев в коде не очень много, так как все рисовалось под свои нужды, но все должно быть понятно и без подробных описаний. Для каждого действия сперва выясняется "ручная" последовательность нажатий клавиш в консоли, а затем она просто воспроизводится через сокеты.
Code (PHP) : Убрать нумерацию
- <?
- // Определение команд управления питанием. Подробности
- // по каждой команде читайте в документации к устройству
- define ("IMMEDIATE_ON", 1); // Немедленное включение порта
- define ("IMMEDIATE_OFF", 2); // Немедленное выключение порта
- define ("IMMEDIATE_REBOOT", 3); // Немедленная перезагрузка
- define ("DELAYED_ON", 4); // Отложенное включение порта
- define ("DELAYED_OFF", 5); // Отложенное выключение порта
- define ("DELAYED_REBOOT", 6); // Отложенная перезагрузка
- class telnet {
- var $host;
- var $port=23;
- var $timeout=30;
- var $login;
- var $password;
- var $connection;
- var $type;
- var $error;
- var $errormsg;
- define ("ESC", chr(27));
- // Получение списка и состояния всех портов power-свича
- public function Port_List() {
- $this->Get_Type();
- if ($this->telnet_login()) {
- $this->Put_Command("1");
- $this->Put_Command("2");
- if ($this->type==1) {
- $this->Put_Command("1");
- }
- $this->Put_Command("");
- $this->Put_Command(ESC,1);
- $this->Put_Command(ESC,1);
- if ($this->type==1) {
- $this->Put_Command(ESC,1);
- }
- $this->Put_Command("4");
- $data=$this->Get_Data();
- if ($data) {
- preg_match_all("/\n([0-9]+)\- (([- A-Za-z0-9\(\)]+ ){1,})".
- " {4,}([ONF]+)/",$data,$matches);
- if (count($matches[1])) {
- $tmp=Array();
- for ($i=0; $i<count($matches[1]); $i++) {
- $tmp[$matches[1][$i]]=Array(
- "name"=>trim($matches[2][$i]),
- "state"=>$matches[4][$i]
- );
- }
- return $tmp;
- }
- else {
- $this->error=777;
- $this->errormsg="Invalid data recived";
- return false;
- }
- }
- else {
- return false;
- }
- }
- else {
- return false;
- }
- }
- // Получение состояния отдельного порта свича
- public function Get_State($port) {
- $this->Get_Type();
- if ($this->telnet_login()) {
- $this->Put_Command("1");
- $this->Put_Command("2");
- if ($this->type==1) {
- $this->Put_Command("1");
- }
- $this->Put_Command("");
- $this->Put_Command(ESC,1);
- $this->Put_Command(ESC,1);
- if ($this->type==1) {
- $this->Put_Command(ESC,1);
- }
- $this->Put_Command("4");
- $data=$this->Get_Data();
- if ($data) {
- $pocket=Array();
- ereg("\n".$port."- (([A-Za-z0-9]+ ){1,}) +([A-Z]+)",$data,$pocket);
- if ($pocket[3]!="") {
- return $pocket[3];
- }
- else {
- $this->error=777;
- $this->errormsg="Invalid data recived";
- return false;
- }
- }
- else {
- return false;
- }
- }
- else {
- return false;
- }
- }
- // Изменения состояния (включение-выключение) порта
- public function Turn_Port($port,$action) {
- $this->Get_Type();
- if ($this->telnet_login()) {
- $this->Put_Command("1");
- $this->Put_Command("2");
- if ($this->type==1) {
- $this->Put_Command("1");
- }
- $this->Put_Command("");
- $this->Put_Command($port);
- $this->Put_Command($action);
- $this->Put_Command("YES\r\n");
- $this->Put_Command(ESC,1);
- $this->Put_Command(ESC,1);
- $this->Put_Command(ESC,1);
- $this->Put_Command(ESC,1);
- if ($this->type==1) {
- $this->Put_Command(ESC,1);
- }
- $this->Put_Command("4");
- $data=$this->Get_Data();
- if ($data) {
- return true;
- }
- else {
- return false;
- }
- }
- else {
- return false;
- }
- }
- // Получение времени аптайма свича
- public function Get_Uptime() {
- if ($this->telnet_login()) {
- $this->Put_Command("4");
- $data=$this->Get_Data();
- $pocket=Array();
- eregi("Up Time : ([0-9]+) Days? ([0-9]+) Hours?".
- " ([0-9]+) Minutes?",$data,$pocket);
- if (count($pocket)==4) {
- $tmp=Array();
- $tmp['days']=$pocket[1];
- $tmp['hours']=$pocket[2];
- $tmp['minutes']=$pocket[3];
- return $tmp;
- }
- else {
- $this->error=777;
- $this->errormsg="Invalid data recived";
- return false;
- }
- }
- else {
- return false;
- }
- }
- // Подключение по telnet
- private function telnet_login() {
- if ($this->host=="") {
- $this->error=777;
- $this->errormsg="Invalid host";
- return false;
- }
- if (intval($this->port)<=1) {
- $this->error=777;
- $this->errormsg="Invalid port";
- return false;
- }
- if (intval($this->timeout)<=1) {
- $this->error=777;
- $this->errormsg="Invalid timeout";
- return false;
- }
- $this->connection=@fsockopen($this->host, $this->port,
- $this->error, $this->errormsg, $this->timeout);
- if (!$this->connection) {
- return false;
- }
- fwrite($this->connection, $this->login."\r\n");
- fwrite($this->connection, $this->password."\r\n");
- return true;
- }
- // Получение данных по telnet
- private function Get_Data() {
- $data="";
- while (!feof($this->connection)) {
- $tmp=trim(fgets($this->connection,1000));
- $data.=$tmp."\n";
- }
- fclose($this->connection);
- if (trim($data)=="") {
- $this->error=777;
- $this->errormsg="Empty data recived. Please try again later";
- return false;
- }
- else {
- return $data;
- }
- }
- // Отправка данных по telnet
- private function Put_Command($cmd,$no_ret=0) {
- fwrite($this->connection, $cmd.($no_ret==0?"\r\n":""));
- }
- // Вспомогательная функция получения типа свича, т.к. у разных
- // моделей отличается меню управления
- private function Get_Type() {
- if ($this->telnet_login()) {
- $this->Put_Command("1");
- $this->Put_Command("2");
- $this->Put_Command("");
- $this->Put_Command(ESC,1);
- $this->Put_Command(ESC,1);
- $this->Put_Command("4");
- $data=$this->Get_Data();
- if ($data=="") {
- return false;
- }
- if (strpos($data,"Outlet Control/Configuration")) {
- $this->type=1;
- }
- else {
- $this->type=0;
- }
- return true;
- }
- else {
- return false;
- }
- }
- // ---------------------------
- }
- ?>
Пример использования скрипта. В нем удаленный сервер будет перезагружен путем отключения питания на свиче и включения его обратно через 5 секунд.
Code (PHP) : Убрать нумерацию
- <?
- $host='1.2.3.4'; // IP-адрес свича
- $login='login'; // Логин для подключения по telnet
- $password='password'; // Пароль для подключения по telnet
- $port=5; // Номер порта, который надо перезагрузить
- // Инициализация класса
- $telnet = new telnet;
- $telnet->host=$host;
- $telnet->login=$login;
- $telnet->password=$password;
- // Получить список и состояние портов свича
- if ($tmp=$telnet->Port_List()) {
- // Если запрошенный порт есть, то перезагрузить сервер по питанию
- if ($tmp[$port]['state']!="") {
- // Выключить питание
- if ($telnet->Turn_Port($port, IMMEDIATE_OFF)) {
- // Пауза 5 секунд
- sleep(5);
- // Включить питание
- if (!$telnet->Turn_Port($port, IMMEDIATE_ON)) {
- $error=$telnet->errormsg;
- }
- }
- else {
- $error=$telnet->errormsg;
- }
- }
- else {
- // Возможно, такого порта нет
- $error=$telnet->errormsg;
- }
- }
- else {
- // Невозможно проверить состояние портов
- $error=$telnet->errormsg;
- }
- ?>
Просмотров: 5385 | Комментариев: 0
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Комментариeв нет
Добавить комментарий
Заполните форму для добавления комментария