/extensions/OpenStackManager/special/SpecialNovaVolume.php

https://github.com/ChuguluGames/mediawiki-svn · PHP · 524 lines · 425 code · 46 blank · 53 comment · 35 complexity · e374f578b1f2aec65ca1ba04bc96665a MD5 · raw file

  1. <?php
  2. class SpecialNovaVolume extends SpecialNova {
  3. /**
  4. * @var OpenStackNovaController
  5. */
  6. var $adminNova, $userNova;
  7. /**
  8. * @var OpenStackNovaUser
  9. */
  10. var $userLDAP;
  11. function __construct() {
  12. parent::__construct( 'NovaVolume' );
  13. }
  14. function execute( $par ) {
  15. global $wgRequest, $wgUser;
  16. global $wgOpenStackManagerNovaAdminKeys;
  17. if ( ! $wgUser->isLoggedIn() ) {
  18. $this->notLoggedIn();
  19. return true;
  20. }
  21. $this->userLDAP = new OpenStackNovaUser();
  22. if ( ! $this->userLDAP->exists() ) {
  23. $this->noCredentials();
  24. return true;
  25. }
  26. $project = $wgRequest->getVal( 'project' );
  27. $userCredentials = $this->userLDAP->getCredentials( $project );
  28. $this->userNova = new OpenStackNovaController( $userCredentials );
  29. $adminCredentials = $wgOpenStackManagerNovaAdminKeys;
  30. $this->adminNova = new OpenStackNovaController( $adminCredentials );
  31. $action = $wgRequest->getVal( 'action' );
  32. if ( $action == "create" ) {
  33. if ( ! $this->userLDAP->inProject( $project ) ) {
  34. $this->notInProject();
  35. return true;
  36. }
  37. $this->createVolume();
  38. } elseif ( $action == "delete" ) {
  39. if ( ! $this->userLDAP->inProject( $project ) ) {
  40. $this->notInProject();
  41. return true;
  42. }
  43. $this->deleteVolume();
  44. } elseif ( $action == "attach" ) {
  45. if ( ! $this->userLDAP->inProject( $project ) ) {
  46. $this->notInProject();
  47. return true;
  48. }
  49. $this->attachVolume();
  50. } elseif ( $action == "detach" ) {
  51. if ( ! $this->userLDAP->inProject( $project ) ) {
  52. $this->notInProject();
  53. return true;
  54. }
  55. $this->detachVolume();
  56. } else {
  57. $this->listVolumes();
  58. }
  59. }
  60. /**
  61. * @return bool
  62. */
  63. function createVolume() {
  64. global $wgRequest, $wgOut;
  65. $this->setHeaders();
  66. $wgOut->setPagetitle( wfMsg( 'openstackmanager-createvolume' ) );
  67. $project = $wgRequest->getText( 'project' );
  68. if ( ! $this->userLDAP->inRole( 'sysadmin', $project ) ) {
  69. $this->notInRole( 'sysadmin' );
  70. return false;
  71. }
  72. $volumeInfo = array();
  73. $volumeInfo['volumename'] = array(
  74. 'type' => 'text',
  75. 'label-message' => 'openstackmanager-volumename',
  76. 'validation-callback' => array( $this, 'validateText' ),
  77. 'default' => '',
  78. 'section' => 'volume/info',
  79. 'name' => 'volumename',
  80. );
  81. $volumeInfo['volumedescription'] = array(
  82. 'type' => 'text',
  83. 'label-message' => 'openstackmanager-volumedescription',
  84. 'default' => '',
  85. 'section' => 'volume/info',
  86. 'name' => 'volumedescription',
  87. );
  88. # Availability zone names can't be translated. Get the keys, and make an array
  89. # where the name points to itself as a value
  90. $availabilityZones = $this->adminNova->getAvailabilityZones();
  91. $availabilityZone_keys = array();
  92. foreach ( array_keys( $availabilityZones ) as $availabilityZone_key ) {
  93. $availabilityZone_keys["$availabilityZone_key"] = $availabilityZone_key;
  94. }
  95. $volumeInfo['availabilityZone'] = array(
  96. 'type' => 'select',
  97. 'section' => 'volume/info',
  98. 'options' => $availabilityZone_keys,
  99. 'label-message' => 'openstackmanager-availabilityzone',
  100. 'name' => 'availabilityZone',
  101. );
  102. $volumeInfo['volumeSize'] = array(
  103. 'type' => 'int',
  104. 'section' => 'volume/info',
  105. 'label-message' => 'openstackmanager-volumesize',
  106. 'name' => 'volumeSize',
  107. );
  108. $volumeInfo['project'] = array(
  109. 'type' => 'hidden',
  110. 'default' => $project,
  111. 'name' => 'project',
  112. );
  113. $volumeInfo['action'] = array(
  114. 'type' => 'hidden',
  115. 'default' => 'create',
  116. 'name' => 'action',
  117. );
  118. $volumeForm = new SpecialNovaVolumeForm( $volumeInfo, 'openstackmanager-novavolume' );
  119. $volumeForm->setTitle( SpecialPage::getTitleFor( 'NovaVolume' ) );
  120. $volumeForm->setSubmitID( 'openstackmanager-novavolume-createvolumesubmit' );
  121. $volumeForm->setSubmitCallback( array( $this, 'tryCreateSubmit' ) );
  122. $volumeForm->show();
  123. return true;
  124. }
  125. /**
  126. * @return bool
  127. */
  128. function deleteVolume() {
  129. global $wgOut, $wgRequest;
  130. $this->setHeaders();
  131. $wgOut->setPagetitle( wfMsg( 'openstackmanager-deletevolume' ) );
  132. $project = $wgRequest->getText( 'project' );
  133. if ( ! $this->userLDAP->inRole( 'sysadmin', $project ) ) {
  134. $this->notInRole( 'sysadmin' );
  135. return false;
  136. }
  137. $volumeid = $wgRequest->getText( 'volumeid' );
  138. if ( ! $wgRequest->wasPosted() ) {
  139. $wgOut->addWikiMsg( 'openstackmanager-deletevolumequestion', $volumeid );
  140. }
  141. $volumeInfo = array();
  142. $volumeInfo['volumeid'] = array(
  143. 'type' => 'hidden',
  144. 'default' => $volumeid,
  145. 'name' => 'volumeid',
  146. );
  147. $volumeInfo['project'] = array(
  148. 'type' => 'hidden',
  149. 'default' => $project,
  150. 'name' => 'project',
  151. );
  152. $volumeInfo['action'] = array(
  153. 'type' => 'hidden',
  154. 'default' => 'delete',
  155. 'name' => 'action',
  156. );
  157. $volumeForm = new SpecialNovaVolumeForm( $volumeInfo, 'openstackmanager-novavolume' );
  158. $volumeForm->setTitle( SpecialPage::getTitleFor( 'NovaVolume' ) );
  159. $volumeForm->setSubmitID( 'novavolume-form-deletevolumesubmit' );
  160. $volumeForm->setSubmitCallback( array( $this, 'tryDeleteSubmit' ) );
  161. $volumeForm->show();
  162. return true;
  163. }
  164. /**
  165. * @return bool
  166. */
  167. function attachVolume() {
  168. global $wgRequest, $wgOut;
  169. $this->setHeaders();
  170. $wgOut->setPagetitle( wfMsg( 'openstackmanager-attachvolume' ) );
  171. $project = $wgRequest->getText( 'project' );
  172. if ( ! $this->userLDAP->inRole( 'sysadmin', $project ) ) {
  173. $this->notInRole( 'sysadmin' );
  174. return false;
  175. }
  176. $instances = $this->userNova->getInstances();
  177. $instance_keys = array();
  178. foreach ( $instances as $instance ) {
  179. if ( $instance->getOwner() == $project ) {
  180. $instancename = $instance->getInstanceName();
  181. $instanceid = $instance->getInstanceId();
  182. $instance_keys["$instancename"] = $instanceid;
  183. }
  184. }
  185. $volumeInfo = array();
  186. $volumeInfo['volumeinfo'] = array(
  187. 'type' => 'info',
  188. 'label-message' => 'openstackmanager-volumename',
  189. 'default' => $wgRequest->getText( 'volumeid' ),
  190. 'section' => 'volume/info',
  191. 'name' => 'volumeinfo',
  192. );
  193. $volumeInfo['volumeid'] = array(
  194. 'type' => 'hidden',
  195. 'default' => $wgRequest->getText( 'volumeid' ),
  196. 'name' => 'volumeid',
  197. );
  198. $volumeInfo['volumedescription'] = array(
  199. 'type' => 'info',
  200. 'label-message' => 'openstackmanager-volumedescription',
  201. 'section' => 'volume/info',
  202. 'name' => 'volumedescription',
  203. );
  204. $volumeInfo['instanceid'] = array(
  205. 'type' => 'select',
  206. 'label-message' => 'openstackmanager-instancename',
  207. 'options' => $instance_keys,
  208. 'section' => 'volume/info',
  209. 'name' => 'instanceid',
  210. );
  211. $volumeInfo['device'] = array(
  212. 'type' => 'select',
  213. 'label-message' => 'openstackmanager-device',
  214. 'options' => $this->getDrives(),
  215. 'section' => 'volume/info',
  216. 'name' => 'device',
  217. );
  218. $volumeInfo['project'] = array(
  219. 'type' => 'hidden',
  220. 'default' => $project,
  221. 'name' => 'project',
  222. );
  223. $volumeInfo['action'] = array(
  224. 'type' => 'hidden',
  225. 'default' => 'attach',
  226. 'name' => 'action',
  227. );
  228. $volumeForm = new SpecialNovaVolumeForm( $volumeInfo, 'openstackmanager-novavolume' );
  229. $volumeForm->setTitle( SpecialPage::getTitleFor( 'NovaVolume' ) );
  230. $volumeForm->setSubmitID( 'novavolume-form-attachvolumesubmit' );
  231. $volumeForm->setSubmitCallback( array( $this, 'tryAttachSubmit' ) );
  232. $volumeForm->show();
  233. return true;
  234. }
  235. /**
  236. * @return bool
  237. */
  238. function detachVolume() {
  239. global $wgRequest, $wgOut;
  240. $this->setHeaders();
  241. $wgOut->setPagetitle( wfMsg( 'openstackmanager-detachvolume' ) );
  242. $project = $wgRequest->getText( 'project' );
  243. if ( ! $this->userLDAP->inRole( 'sysadmin', $project ) ) {
  244. $this->notInRole( 'sysadmin' );
  245. return false;
  246. }
  247. $volumeInfo = array();
  248. $volumeInfo['volumeinfo'] = array(
  249. 'type' => 'info',
  250. 'label-message' => 'openstackmanager-volumename',
  251. 'default' => $wgRequest->getText( 'volumeid' ),
  252. 'section' => 'volume/info',
  253. 'name' => 'volumeinfo',
  254. );
  255. $volumeInfo['force'] = array(
  256. 'type' => 'toggle',
  257. 'label-message' => 'openstackmanager-forcedetachment',
  258. 'help-message' => 'openstackmanager-forcedetachmenthelp',
  259. 'section' => 'volume/info',
  260. 'name' => 'volumeinfo',
  261. );
  262. $volumeInfo['volumeid'] = array(
  263. 'type' => 'hidden',
  264. 'default' => $wgRequest->getText( 'volumeid' ),
  265. 'name' => 'volumeid',
  266. );
  267. $volumeInfo['project'] = array(
  268. 'type' => 'hidden',
  269. 'default' => $project,
  270. 'name' => 'project',
  271. );
  272. $volumeInfo['action'] = array(
  273. 'type' => 'hidden',
  274. 'default' => 'detach',
  275. 'name' => 'action',
  276. );
  277. $volumeForm = new SpecialNovaVolumeForm( $volumeInfo, 'openstackmanager-novavolume' );
  278. $volumeForm->setTitle( SpecialPage::getTitleFor( 'NovaVolume' ) );
  279. $volumeForm->setSubmitID( 'novavolume-form-detachvolumesubmit' );
  280. $volumeForm->setSubmitCallback( array( $this, 'tryDetachSubmit' ) );
  281. $volumeForm->show();
  282. return true;
  283. }
  284. /**
  285. * @return void
  286. */
  287. function listVolumes() {
  288. global $wgOut;
  289. $this->setHeaders();
  290. $wgOut->setPagetitle( wfMsg( 'openstackmanager-volumelist' ) );
  291. $userProjects = $this->userLDAP->getProjects();
  292. $sk = $wgOut->getSkin();
  293. $out = '';
  294. $volumes = $this->adminNova->getVolumes();
  295. $header = Html::element( 'th', array(), wfMsg( 'openstackmanager-volumename' ) );
  296. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeid' ) );
  297. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumedescription' ) );
  298. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumestate' ) );
  299. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeattachmentinstance' ) );
  300. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeattachmentdevice' ) );
  301. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeattachmentstatus' ) );
  302. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumesize' ) );
  303. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumedeleteonvolumedelete' ) );
  304. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-availabilityzone' ) );
  305. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumecreationtime' ) );
  306. $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-actions' ) );
  307. $projectArr = array();
  308. foreach ( $volumes as $volume ) {
  309. $project = $volume->getOwner();
  310. if ( ! in_array( $project, $userProjects ) ) {
  311. continue;
  312. }
  313. $volumeOut = Html::element( 'td', array(), $volume->getVolumeName() );
  314. $volumeId = $volume->getVolumeId();
  315. $volumeId = htmlentities( $volumeId );
  316. $title = Title::newFromText( $volumeId, NS_NOVA_RESOURCE );
  317. $volumeIdLink = $sk->link( $title, $volumeId );
  318. $volumeOut .= Html::rawElement( 'td', array(), $volumeIdLink );
  319. $volumeOut .= Html::element( 'td', array(), $volume->getVolumeDescription() );
  320. $volumeOut .= Html::element( 'td', array(), $volume->getVolumeStatus() );
  321. $volumeOut .= Html::element( 'td', array(), $volume->getAttachedInstanceId() );
  322. $volumeOut .= Html::element( 'td', array(), $volume->getAttachedDevice() );
  323. $volumeOut .= Html::element( 'td', array(), $volume->getAttachmentStatus() );
  324. $volumeOut .= Html::element( 'td', array(), $volume->getVolumeSize() );
  325. $volumeOut .= Html::element( 'td', array(), $volume->deleteOnInstanceDeletion() );
  326. $volumeOut .= Html::element( 'td', array(), $volume->getVolumeAvailabilityZone() );
  327. $volumeOut .= Html::element( 'td', array(), $volume->getVolumeCreationTime() );
  328. $msg = wfMsgHtml( 'openstackmanager-delete' );
  329. $link = $sk->link( $this->getTitle(), $msg, array(),
  330. array( 'action' => 'delete',
  331. 'project' => $project,
  332. 'volumeid' => $volume->getVolumeId() ) );
  333. $actions = Html::rawElement( 'li', array(), $link );
  334. #$msg = wfMsgHtml( 'openstackmanager-rename' );
  335. #$actions .= $sk->link( $this->getTitle(), $msg, array(),
  336. # array( 'action' => 'rename',
  337. # 'project' => $project,
  338. # 'volumeid' => $volume->getVolumeId() ) );
  339. $msg = wfMsgHtml( 'openstackmanager-attach' );
  340. $link = $sk->link( $this->getTitle(), $msg, array(),
  341. array( 'action' => 'attach',
  342. 'project' => $project,
  343. 'volumeid' => $volume->getVolumeId() ) );
  344. $actions .= Html::rawElement( 'li', array(), $link );
  345. $msg = wfMsgHtml( 'openstackmanager-detach' );
  346. $link = $sk->link( $this->getTitle(), $msg, array(),
  347. array( 'action' => 'detach',
  348. 'project' => $project,
  349. 'volumeid' => $volume->getVolumeId() ) );
  350. $actions .= Html::rawElement( 'li', array(), $link );
  351. $actions = Html::rawElement( 'ul', array(), $actions );
  352. $volumeOut .= Html::rawElement( 'td', array(), $actions );
  353. if ( isset( $projectArr["$project"] ) ) {
  354. $projectArr["$project"] .= Html::rawElement( 'tr', array(), $volumeOut );
  355. } else {
  356. $projectArr["$project"] = Html::rawElement( 'tr', array(), $volumeOut );
  357. }
  358. }
  359. foreach ( $userProjects as $project ) {
  360. $out .= Html::element( 'h2', array(), $project );
  361. $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-createvolume' ), array(),
  362. array( 'action' => 'create', 'project' => $project ) );
  363. if ( isset( $projectArr["$project"] ) ) {
  364. $projectOut = $header;
  365. $projectOut .= $projectArr["$project"];
  366. $out .= Html::rawElement( 'table',
  367. array( 'id' => 'novavolumelist', 'class' => 'wikitable sortable collapsible' ), $projectOut );
  368. }
  369. }
  370. $wgOut->addHTML( $out );
  371. }
  372. /**
  373. * @param $formData
  374. * @param string $entryPoint
  375. * @return bool
  376. */
  377. function tryCreateSubmit( $formData, $entryPoint = 'internal' ) {
  378. global $wgOut;
  379. $volume = $this->userNova->createVolume( $formData['availabilityZone'], $formData['volumeSize'], $formData['volumename'], $formData['volumedescription'] );
  380. if ( $volume ) {
  381. $wgOut->addWikiMsg( 'openstackmanager-createdvolume', $volume->getVolumeID() );
  382. } else {
  383. $wgOut->addWikiMsg( 'openstackmanager-createevolumefailed' );
  384. }
  385. $sk = $wgOut->getSkin();
  386. $out = '<br />';
  387. $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-backvolumelist' ) );
  388. $wgOut->addHTML( $out );
  389. return true;
  390. }
  391. /**
  392. * @param $formData
  393. * @param string $entryPoint
  394. * @return bool
  395. */
  396. function tryDeleteSubmit( $formData, $entryPoint = 'internal' ) {
  397. global $wgOut;
  398. $volume = $this->adminNova->getVolume( $formData['volumeid'] );
  399. if ( ! $volume ) {
  400. $wgOut->addWikiMsg( 'openstackmanager-nonexistantvolume' );
  401. return true;
  402. }
  403. $volumeid = $volume->getVolumeId();
  404. $success = $this->userNova->deleteVolume( $volumeid );
  405. if ( $success ) {
  406. $wgOut->addWikiMsg( 'openstackmanager-deletedvolume', $volumeid );
  407. } else {
  408. $wgOut->addWikiMsg( 'openstackmanager-deletevolumefailed' );
  409. }
  410. $sk = $wgOut->getSkin();
  411. $out = '<br />';
  412. $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-backvolumelist' ) );
  413. $wgOut->addHTML( $out );
  414. return true;
  415. }
  416. /**
  417. * @param $formData
  418. * @param string $entryPoint
  419. * @return bool
  420. */
  421. function tryAttachSubmit( $formData, $entryPoint = 'internal' ) {
  422. global $wgOut;
  423. $success = $this->userNova->attachVolume( $formData['volumeid'], $formData['instanceid'], $formData['device'] );
  424. if ( $success ) {
  425. $wgOut->addWikiMsg( 'openstackmanager-attachedvolume' );
  426. } else {
  427. $wgOut->addWikiMsg( 'openstackmanager-attachvolumefailed' );
  428. }
  429. $sk = $wgOut->getSkin();
  430. $out = '<br />';
  431. $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-backvolumelist' ) );
  432. $wgOut->addHTML( $out );
  433. return true;
  434. }
  435. /**
  436. * @param $formData
  437. * @param string $entryPoint
  438. * @return bool
  439. */
  440. function tryDetachSubmit( $formData, $entryPoint = 'internal' ) {
  441. global $wgOut;
  442. if ( isset( $formData['force'] ) && $formData['force'] ) {
  443. $force = true;
  444. } else {
  445. $force = false;
  446. }
  447. $success = $this->userNova->detachVolume( $formData['volumeid'], $force );
  448. if ( $success ) {
  449. $wgOut->addWikiMsg( 'openstackmanager-detachedvolume' );
  450. } else {
  451. $wgOut->addWikiMsg( 'openstackmanager-detachvolumefailed' );
  452. }
  453. $sk = $wgOut->getSkin();
  454. $out = '<br />';
  455. $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-backvolumelist' ) );
  456. $wgOut->addHTML( $out );
  457. return true;
  458. }
  459. /**
  460. * Return an array of drive devices
  461. *
  462. * @return string
  463. */
  464. function getDrives() {
  465. $drives = array();
  466. foreach ( range('a', 'z') as $letter ) {
  467. $drive = '/dev/vd' . $letter;
  468. $drives["$drive"] = $drive;
  469. }
  470. foreach ( range('a', 'z') as $letter ) {
  471. $drive = '/dev/vda' . $letter;
  472. $drives["$drive"] = $drive;
  473. }
  474. return $drives;
  475. }
  476. }
  477. class SpecialNovaVolumeForm extends HTMLForm {
  478. }