Index: trunk/extensions/OpenStackManager/special/SpecialNovaInstance.php |
— | — | @@ -338,7 +338,7 @@ |
339 | 339 | global $wgOut, $wgRequest; |
340 | 340 | |
341 | 341 | $this->setHeaders(); |
342 | | - $wgOut->setPagetitle( wfMsg( 'openstackmanager-deletedomain' ) ); |
| 342 | + $wgOut->setPagetitle( wfMsg( 'openstackmanager-deleteinstance' ) ); |
343 | 343 | |
344 | 344 | $project = $wgRequest->getText( 'project' ); |
345 | 345 | if ( ! $this->userLDAP->inRole( 'sysadmin', $project ) ) { |
— | — | @@ -427,12 +427,12 @@ |
428 | 428 | if ( ! in_array( $project, $userProjects ) ) { |
429 | 429 | continue; |
430 | 430 | } |
431 | | - $instanceName = $instance->getInstanceName(); |
432 | | - $instanceName = htmlentities( $instanceName ); |
433 | | - $title = Title::newFromText( $instanceName, NS_VM ); |
434 | | - $instanceNameLink = $sk->link( $title, $instanceName ); |
435 | | - $instanceOut = Html::rawElement( 'td', array(), $instanceNameLink ); |
436 | | - $instanceOut .= Html::element( 'td', array(), $instance->getInstanceId() ); |
| 431 | + $instanceOut = Html::element( 'td', array(), $instance->getInstanceName() ); |
| 432 | + $instanceId = $instance->getInstanceId(); |
| 433 | + $instanceId = htmlentities( $instanceId ); |
| 434 | + $title = Title::newFromText( $instanceId, NS_NOVA_RESOURCE ); |
| 435 | + $instanceIdLink = $sk->link( $title, $instanceId ); |
| 436 | + $instanceOut .= Html::rawElement( 'td', array(), $instanceIdLink ); |
437 | 437 | $instanceOut .= Html::element( 'td', array(), $instance->getInstanceState() ); |
438 | 438 | $instanceOut .= Html::element( 'td', array(), $instance->getInstanceType() ); |
439 | 439 | $privateip = $instance->getInstancePrivateIP(); |
— | — | @@ -492,7 +492,7 @@ |
493 | 493 | $projectOut = $header; |
494 | 494 | $projectOut .= $projectArr["$project"]; |
495 | 495 | $out .= Html::rawElement( 'table', |
496 | | - array( 'id' => 'novainstancelist', 'class' => 'wikitable' ), $projectOut ); |
| 496 | + array( 'id' => 'novainstancelist', 'class' => 'wikitable sortable collapsible' ), $projectOut ); |
497 | 497 | } |
498 | 498 | } |
499 | 499 | |
Index: trunk/extensions/OpenStackManager/special/SpecialNovaSecurityGroup.php |
— | — | @@ -270,7 +270,7 @@ |
271 | 271 | $ruleOut .= Html::rawElement( 'td', array(), $actions ); |
272 | 272 | $rulesOut .= Html::rawElement( 'tr', array(), $ruleOut ); |
273 | 273 | } |
274 | | - $rulesOut = Html::rawElement( 'table', array( 'id' => 'novasecuritygrouplist', 'class' => 'wikitable' ), $rulesOut ); |
| 274 | + $rulesOut = Html::rawElement( 'table', array( 'id' => 'novasecuritygrouplist', 'class' => 'wikitable sortable collapsible' ), $rulesOut ); |
275 | 275 | $groupOut .= Html::rawElement( 'td', array(), $rulesOut ); |
276 | 276 | } else { |
277 | 277 | $groupOut .= Html::rawElement( 'td', array(), '' ); |
— | — | @@ -309,7 +309,7 @@ |
310 | 310 | $projectOut = $groupheader; |
311 | 311 | $projectOut .= $projectArr["$project"]; |
312 | 312 | $out .= Html::rawElement( 'table', |
313 | | - array( 'id' => 'novainstancelist', 'class' => 'wikitable' ), $projectOut ); |
| 313 | + array( 'id' => 'novainstancelist', 'class' => 'wikitable sortable collapsible' ), $projectOut ); |
314 | 314 | } |
315 | 315 | } |
316 | 316 | |
Index: trunk/extensions/OpenStackManager/special/SpecialNovaAddress.php |
— | — | @@ -438,7 +438,7 @@ |
439 | 439 | $projectOut = $header; |
440 | 440 | $projectOut .= $projectArr["$project"]; |
441 | 441 | $out .= Html::rawElement( 'table', |
442 | | - array( 'id' => 'novainstancelist', 'class' => 'wikitable' ), $projectOut ); |
| 442 | + array( 'id' => 'novainstancelist', 'class' => 'wikitable sortable collapsible' ), $projectOut ); |
443 | 443 | } |
444 | 444 | } |
445 | 445 | $wgOut->addHTML( $out ); |
Index: trunk/extensions/OpenStackManager/special/SpecialNovaProject.php |
— | — | @@ -259,7 +259,7 @@ |
260 | 260 | $roleOut .= Html::rawElement( 'td', array(), $actions ); |
261 | 261 | $rolesOut .= Html::rawElement( 'tr', array(), $roleOut ); |
262 | 262 | } |
263 | | - $rolesOut = Html::rawElement( 'table', array( 'class' => 'wikitable' ), $rolesOut ); |
| 263 | + $rolesOut = Html::rawElement( 'table', array( 'class' => 'wikitable sortable collapsible' ), $rolesOut ); |
264 | 264 | $projectOut .= Html::rawElement( 'td', array(), $rolesOut ); |
265 | 265 | $link = $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-deleteproject' ), array(), |
266 | 266 | array( 'action' => 'delete', 'projectname' => $projectName ) ); |
— | — | @@ -275,7 +275,7 @@ |
276 | 276 | $projectsOut .= Html::rawElement( 'tr', array(), $projectOut ); |
277 | 277 | } |
278 | 278 | if ( $projectsOut ) { |
279 | | - $out .= Html::rawElement( 'table', array( 'class' => 'wikitable' ), $projectsOut ); |
| 279 | + $out .= Html::rawElement( 'table', array( 'class' => 'wikitable sortable collapsible' ), $projectsOut ); |
280 | 280 | } |
281 | 281 | |
282 | 282 | $wgOut->addHTML( $out ); |
Index: trunk/extensions/OpenStackManager/special/SpecialNovaDomain.php |
— | — | @@ -163,7 +163,7 @@ |
164 | 164 | $domainsOut .= Html::rawElement( 'tr', array(), $domainOut ); |
165 | 165 | } |
166 | 166 | if ( $domains ) { |
167 | | - $out .= Html::rawElement( 'table', array( 'class' => 'wikitable' ), $domainsOut ); |
| 167 | + $out .= Html::rawElement( 'table', array( 'class' => 'wikitable sortable collapsible' ), $domainsOut ); |
168 | 168 | } |
169 | 169 | |
170 | 170 | $wgOut->addHTML( $out ); |
Index: trunk/extensions/OpenStackManager/special/SpecialNovaVolume.php |
— | — | @@ -0,0 +1,336 @@ |
| 2 | +<?php |
| 3 | +class SpecialNovaVolume extends SpecialNova { |
| 4 | + |
| 5 | + var $adminNova, $userNova; |
| 6 | + var $userLDAP; |
| 7 | + |
| 8 | + function __construct() { |
| 9 | + parent::__construct( 'NovaVolume' ); |
| 10 | + } |
| 11 | + |
| 12 | + function execute( $par ) { |
| 13 | + global $wgRequest, $wgUser; |
| 14 | + global $wgOpenStackManagerNovaAdminKeys; |
| 15 | + |
| 16 | + if ( ! $wgUser->isLoggedIn() ) { |
| 17 | + $this->notLoggedIn(); |
| 18 | + return true; |
| 19 | + } |
| 20 | + $this->userLDAP = new OpenStackNovaUser(); |
| 21 | + if ( ! $this->userLDAP->exists() ) { |
| 22 | + $this->noCredentials(); |
| 23 | + return true; |
| 24 | + } |
| 25 | + $project = $wgRequest->getVal( 'project' ); |
| 26 | + $userCredentials = $this->userLDAP->getCredentials( $project ); |
| 27 | + $this->userNova = new OpenStackNovaController( $userCredentials ); |
| 28 | + $adminCredentials = $wgOpenStackManagerNovaAdminKeys; |
| 29 | + $this->adminNova = new OpenStackNovaController( $adminCredentials ); |
| 30 | + |
| 31 | + $action = $wgRequest->getVal( 'action' ); |
| 32 | + |
| 33 | + if ( $action == "create" ) { |
| 34 | + if ( ! $this->userLDAP->inProject( $project ) ) { |
| 35 | + $this->notInProject(); |
| 36 | + return true; |
| 37 | + } |
| 38 | + $this->createVolume(); |
| 39 | + } else if ( $action == "delete" ) { |
| 40 | + if ( ! $this->userLDAP->inProject( $project ) ) { |
| 41 | + $this->notInProject(); |
| 42 | + return true; |
| 43 | + } |
| 44 | + $this->deleteVolume(); |
| 45 | + } else if ( $action == "attach" ) { |
| 46 | + if ( ! $this->userLDAP->inProject( $project ) ) { |
| 47 | + $this->notInProject(); |
| 48 | + return true; |
| 49 | + } |
| 50 | + $this->attachVolume(); |
| 51 | + } else if ( $action == "detach" ) { |
| 52 | + if ( ! $this->userLDAP->inProject( $project ) ) { |
| 53 | + $this->notInProject(); |
| 54 | + return true; |
| 55 | + } |
| 56 | + $this->detachVolume(); |
| 57 | + } else { |
| 58 | + $this->listVolumes(); |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + /** |
| 63 | + * @return bool |
| 64 | + */ |
| 65 | + function createVolume() { |
| 66 | + global $wgRequest, $wgOut; |
| 67 | + |
| 68 | + $this->setHeaders(); |
| 69 | + $wgOut->setPagetitle( wfMsg( 'openstackmanager-createvolume' ) ); |
| 70 | + |
| 71 | + $project = $wgRequest->getText( 'project' ); |
| 72 | + if ( ! $this->userLDAP->inRole( 'sysadmin', $project ) ) { |
| 73 | + $this->notInRole( 'sysadmin' ); |
| 74 | + return false; |
| 75 | + } |
| 76 | + $volumeInfo = array(); |
| 77 | + $volumeInfo['volumename'] = array( |
| 78 | + 'type' => 'text', |
| 79 | + 'label-message' => 'openstackmanager-volumename', |
| 80 | + 'validation-callback' => array( $this, 'validateVolumeName' ), |
| 81 | + 'default' => '', |
| 82 | + 'section' => 'volume/info', |
| 83 | + 'name' => 'volumename', |
| 84 | + ); |
| 85 | + $volumeInfo['volumedescription'] = array( |
| 86 | + 'type' => 'text', |
| 87 | + 'label-message' => 'openstackmanager-volumedescription', |
| 88 | + 'default' => '', |
| 89 | + 'section' => 'volume/info', |
| 90 | + 'name' => 'volumedescription', |
| 91 | + ); |
| 92 | + |
| 93 | + |
| 94 | + # Availability zone names can't be translated. Get the keys, and make an array |
| 95 | + # where the name points to itself as a value |
| 96 | + $availabilityZones = $this->adminNova->getAvailabilityZones(); |
| 97 | + $availabilityZone_keys = array(); |
| 98 | + foreach ( array_keys( $availabilityZones ) as $availabilityZone_key ) { |
| 99 | + $availabilityZone_keys["$availabilityZone_key"] = $availabilityZone_key; |
| 100 | + } |
| 101 | + $volumeInfo['availabilityZone'] = array( |
| 102 | + 'type' => 'select', |
| 103 | + 'section' => 'volume/info', |
| 104 | + 'options' => $availabilityZone_keys, |
| 105 | + 'label-message' => 'openstackmanager-availabilityzone', |
| 106 | + 'name' => 'availabilityZone', |
| 107 | + ); |
| 108 | + |
| 109 | + $volumeInfo['volumeSize'] = array( |
| 110 | + 'type' => 'int', |
| 111 | + 'section' => 'volume/info', |
| 112 | + 'label-message' => 'openstackmanager-volumesize', |
| 113 | + 'name' => 'volumeSize', |
| 114 | + ); |
| 115 | + |
| 116 | + $volumeInfo['project'] = array( |
| 117 | + 'type' => 'hidden', |
| 118 | + 'default' => $project, |
| 119 | + 'name' => 'project', |
| 120 | + ); |
| 121 | + $volumeInfo['action'] = array( |
| 122 | + 'type' => 'hidden', |
| 123 | + 'default' => 'create', |
| 124 | + 'name' => 'action', |
| 125 | + ); |
| 126 | + |
| 127 | + $volumeForm = new SpecialNovaVolumeForm( $volumeInfo, 'openstackmanager-novavolume' ); |
| 128 | + $volumeForm->setTitle( SpecialPage::getTitleFor( 'NovaVolume' ) ); |
| 129 | + $volumeForm->setSubmitID( 'openstackmanager-novavolume-createvolumesubmit' ); |
| 130 | + $volumeForm->setSubmitCallback( array( $this, 'tryCreateSubmit' ) ); |
| 131 | + $volumeForm->show(); |
| 132 | + |
| 133 | + return true; |
| 134 | + } |
| 135 | + |
| 136 | + /** |
| 137 | + * @return bool |
| 138 | + */ |
| 139 | + function deleteVolume() { |
| 140 | + global $wgOut, $wgRequest; |
| 141 | + |
| 142 | + $this->setHeaders(); |
| 143 | + $wgOut->setPagetitle( wfMsg( 'openstackmanager-deletevolume' ) ); |
| 144 | + |
| 145 | + $project = $wgRequest->getText( 'project' ); |
| 146 | + if ( ! $this->userLDAP->inRole( 'sysadmin', $project ) ) { |
| 147 | + $this->notInRole( 'sysadmin' ); |
| 148 | + return false; |
| 149 | + } |
| 150 | + $volumeid = $wgRequest->getText( 'volumeid' ); |
| 151 | + if ( ! $wgRequest->wasPosted() ) { |
| 152 | + $wgOut->addWikiMsg( 'openstackmanager-deletevolumequestion', $volumeid ); |
| 153 | + } |
| 154 | + $volumeInfo = array(); |
| 155 | + $volumeInfo['volumeid'] = array( |
| 156 | + 'type' => 'hidden', |
| 157 | + 'default' => $volumeid, |
| 158 | + 'name' => 'volumeid', |
| 159 | + ); |
| 160 | + $volumeInfo['project'] = array( |
| 161 | + 'type' => 'hidden', |
| 162 | + 'default' => $project, |
| 163 | + 'name' => 'project', |
| 164 | + ); |
| 165 | + $volumeInfo['action'] = array( |
| 166 | + 'type' => 'hidden', |
| 167 | + 'default' => 'delete', |
| 168 | + 'name' => 'action', |
| 169 | + ); |
| 170 | + $volumeForm = new SpecialNovaVolumeForm( $volumeInfo, 'openstackmanager-novavolume' ); |
| 171 | + $volumeForm->setTitle( SpecialPage::getTitleFor( 'NovaVolume' ) ); |
| 172 | + $volumeForm->setSubmitID( 'novavolume-form-deletevolumesubmit' ); |
| 173 | + $volumeForm->setSubmitCallback( array( $this, 'tryDeleteSubmit' ) ); |
| 174 | + $volumeForm->show(); |
| 175 | + |
| 176 | + return true; |
| 177 | + } |
| 178 | + |
| 179 | + /** |
| 180 | + * @return void |
| 181 | + */ |
| 182 | + function listVolumes() { |
| 183 | + global $wgOut, $wgUser; |
| 184 | + |
| 185 | + $this->setHeaders(); |
| 186 | + $wgOut->setPagetitle( wfMsg( 'openstackmanager-volumelist' ) ); |
| 187 | + |
| 188 | + $userProjects = $this->userLDAP->getProjects(); |
| 189 | + $sk = $wgUser->getSkin(); |
| 190 | + $out = ''; |
| 191 | + $volumes = $this->adminNova->getVolumes(); |
| 192 | + $header = Html::element( 'th', array(), wfMsg( 'openstackmanager-volumename' ) ); |
| 193 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeid' ) ); |
| 194 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumedescription' ) ); |
| 195 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumestate' ) ); |
| 196 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeattachmentinstance' ) ); |
| 197 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeattachmentdevice' ) ); |
| 198 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumeattachmentstatus' ) ); |
| 199 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumesize' ) ); |
| 200 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumedeleteonvolumedelete' ) ); |
| 201 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-availabilityzone' ) ); |
| 202 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-volumecreationtime' ) ); |
| 203 | + $header .= Html::element( 'th', array(), wfMsg( 'openstackmanager-actions' ) ); |
| 204 | + $projectArr = array(); |
| 205 | + foreach ( $volumes as $volume ) { |
| 206 | + $project = $volume->getOwner(); |
| 207 | + if ( ! in_array( $project, $userProjects ) ) { |
| 208 | + continue; |
| 209 | + } |
| 210 | + $volumeOut = Html::element( 'td', array(), $volume->getVolumeName() ); |
| 211 | + $volumeId = $volume->getVolumeId(); |
| 212 | + $volumeId = htmlentities( $volumeId ); |
| 213 | + $title = Title::newFromText( $volumeId, NS_NOVA_RESOURCE ); |
| 214 | + $volumeIdLink = $sk->link( $title, $volumeId ); |
| 215 | + $volumeOut .= Html::rawElement( 'td', array(), $volumeIdLink ); |
| 216 | + $volumeOut .= Html::element( 'td', array(), $volume->getVolumeDescription() ); |
| 217 | + $volumeOut .= Html::element( 'td', array(), $volume->getVolumeStatus() ); |
| 218 | + $volumeOut .= Html::element( 'td', array(), $volume->getAttachedInstanceId() ); |
| 219 | + $volumeOut .= Html::element( 'td', array(), $volume->getAttachedDevice() ); |
| 220 | + $volumeOut .= Html::element( 'td', array(), $volume->getAttachmentStatus() ); |
| 221 | + $volumeOut .= Html::element( 'td', array(), $volume->getVolumeSize() ); |
| 222 | + $volumeOut .= Html::element( 'td', array(), $volume->deleteOnInstanceDeletion() ); |
| 223 | + $volumeOut .= Html::element( 'td', array(), $volume->getVolumeAvailabilityZone() ); |
| 224 | + $volumeOut .= Html::element( 'td', array(), $volume->getVolumeCreationTime() ); |
| 225 | + $msg = wfMsgHtml( 'openstackmanager-delete' ); |
| 226 | + $link = $sk->link( $this->getTitle(), $msg, array(), |
| 227 | + array( 'action' => 'delete', |
| 228 | + 'project' => $project, |
| 229 | + 'volumeid' => $volume->getVolumeId() ) ); |
| 230 | + $actions = Html::rawElement( 'li', array(), $link ); |
| 231 | + #$msg = wfMsgHtml( 'openstackmanager-rename' ); |
| 232 | + #$actions .= $sk->link( $this->getTitle(), $msg, array(), |
| 233 | + # array( 'action' => 'rename', |
| 234 | + # 'project' => $project, |
| 235 | + # 'volumeid' => $volume->getVolumeId() ) ); |
| 236 | + $msg = wfMsgHtml( 'openstackmanager-attach' ); |
| 237 | + $link = $sk->link( $this->getTitle(), $msg, array(), |
| 238 | + array( 'action' => 'attach', |
| 239 | + 'project' => $project, |
| 240 | + 'volumeid' => $volume->getVolumeId() ) ); |
| 241 | + $actions .= Html::rawElement( 'li', array(), $link ); |
| 242 | + $msg = wfMsgHtml( 'openstackmanager-detach' ); |
| 243 | + $link = $sk->link( $this->getTitle(), $msg, array(), |
| 244 | + array( 'action' => 'detach', |
| 245 | + 'project' => $project, |
| 246 | + 'volumeid' => $volume->getVolumeId() ) ); |
| 247 | + $actions .= Html::rawElement( 'li', array(), $link ); |
| 248 | + $actions = Html::rawElement( 'ul', array(), $actions ); |
| 249 | + $volumeOut .= Html::rawElement( 'td', array(), $actions ); |
| 250 | + if ( isset( $projectArr["$project"] ) ) { |
| 251 | + $projectArr["$project"] .= Html::rawElement( 'tr', array(), $volumeOut ); |
| 252 | + } else { |
| 253 | + $projectArr["$project"] = Html::rawElement( 'tr', array(), $volumeOut ); |
| 254 | + } |
| 255 | + } |
| 256 | + foreach ( $userProjects as $project ) { |
| 257 | + $out .= Html::element( 'h2', array(), $project ); |
| 258 | + $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-createvolume' ), array(), |
| 259 | + array( 'action' => 'create', 'project' => $project ) ); |
| 260 | + if ( isset( $projectArr["$project"] ) ) { |
| 261 | + $projectOut = $header; |
| 262 | + $projectOut .= $projectArr["$project"]; |
| 263 | + $out .= Html::rawElement( 'table', |
| 264 | + array( 'id' => 'novavolumelist', 'class' => 'wikitable sortable collapsible' ), $projectOut ); |
| 265 | + } |
| 266 | + } |
| 267 | + |
| 268 | + $wgOut->addHTML( $out ); |
| 269 | + } |
| 270 | + |
| 271 | + /** |
| 272 | + * @param $formData |
| 273 | + * @param string $entryPoint |
| 274 | + * @return bool |
| 275 | + */ |
| 276 | + function tryCreateSubmit( $formData, $entryPoint = 'internal' ) { |
| 277 | + global $wgOut, $wgUser; |
| 278 | + |
| 279 | + $volume = $this->userNova->createVolume( $formData['availabilityZone'], $formData['volumeSize'], $formData['volumename'], $formData['volumedescription'] ); |
| 280 | + if ( $volume ) { |
| 281 | + $wgOut->addWikiMsg( 'openstackmanager-createdvolume', $volume->getVolumeID() ); |
| 282 | + } else { |
| 283 | + $wgOut->addWikiMsg( 'openstackmanager-createevolumefailed' ); |
| 284 | + } |
| 285 | + $sk = $wgUser->getSkin(); |
| 286 | + $out = '<br />'; |
| 287 | + $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-backvolumelist' ) ); |
| 288 | + |
| 289 | + $wgOut->addHTML( $out ); |
| 290 | + return true; |
| 291 | + } |
| 292 | + |
| 293 | + /** |
| 294 | + * @param $formData |
| 295 | + * @param string $entryPoint |
| 296 | + * @return bool |
| 297 | + */ |
| 298 | + function tryDeleteSubmit( $formData, $entryPoint = 'internal' ) { |
| 299 | + global $wgOut, $wgUser; |
| 300 | + |
| 301 | + $volume = $this->adminNova->getVolume( $formData['volumeid'] ); |
| 302 | + if ( ! $volume ) { |
| 303 | + $wgOut->addWikiMsg( 'openstackmanager-nonexistantvolume' ); |
| 304 | + return true; |
| 305 | + } |
| 306 | + $volumeid = $volume->getVolumeId(); |
| 307 | + $success = $this->userNova->deleteVolume( $volumeid ); |
| 308 | + if ( $success ) { |
| 309 | + $wgOut->addWikiMsg( 'openstackmanager-deletedvolume', $volumeid ); |
| 310 | + } else { |
| 311 | + $wgOut->addWikiMsg( 'openstackmanager-deletevolumefailed' ); |
| 312 | + } |
| 313 | + $sk = $wgUser->getSkin(); |
| 314 | + $out = '<br />'; |
| 315 | + $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-backvolumelist' ) ); |
| 316 | + |
| 317 | + $wgOut->addHTML( $out ); |
| 318 | + return true; |
| 319 | + } |
| 320 | + |
| 321 | + /** |
| 322 | + * @param $volumename |
| 323 | + * @param $alldata |
| 324 | + * @return bool|string |
| 325 | + */ |
| 326 | + function validateVolumeName( $volumename, $alldata ) { |
| 327 | + if ( ! preg_match( "/^[a-z][a-z0-9\-]*$/", $volumename ) ) { |
| 328 | + return Xml::element( 'span', array( 'class' => 'error' ), wfMsg( 'openstackmanager-badvolumename' ) ); |
| 329 | + } else { |
| 330 | + return true; |
| 331 | + } |
| 332 | + } |
| 333 | + |
| 334 | +} |
| 335 | + |
| 336 | +class SpecialNovaVolumeForm extends HTMLForm { |
| 337 | +} |
Property changes on: trunk/extensions/OpenStackManager/special/SpecialNovaVolume.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 338 | + native |
Index: trunk/extensions/OpenStackManager/special/SpecialNovaKey.php |
— | — | @@ -183,7 +183,7 @@ |
184 | 184 | $keyOut .= Html::element( 'td', array(), $keypair->getKeyFingerprint() ); |
185 | 185 | $projectOut .= Html::rawElement( 'tr', array(), $keyOut ); |
186 | 186 | } |
187 | | - $out .= Html::rawElement( 'table', array( 'id' => 'novakeylist', 'class' => 'wikitable' ), $projectOut ); |
| 187 | + $out .= Html::rawElement( 'table', array( 'id' => 'novakeylist', 'class' => 'wikitable sortable collapsible' ), $projectOut ); |
188 | 188 | } |
189 | 189 | } else if ( $wgOpenStackManagerNovaKeypairStorage == 'ldap' ) { |
190 | 190 | $out .= $sk->link( $this->getTitle(), wfMsgHtml( 'openstackmanager-importkey' ), array(), array( 'action' => 'import' ) ); |
Index: trunk/extensions/OpenStackManager/special/SpecialNovaRole.php |
— | — | @@ -234,7 +234,7 @@ |
235 | 235 | $rolesOut .= Html::rawElement( 'tr', array(), $roleOut ); |
236 | 236 | } |
237 | 237 | if ( $rolesOut ) { |
238 | | - $out .= Html::rawElement( 'table', array( 'class' => 'wikitable' ), $rolesOut ); |
| 238 | + $out .= Html::rawElement( 'table', array( 'class' => 'wikitable sortable collapsible' ), $rolesOut ); |
239 | 239 | } |
240 | 240 | |
241 | 241 | $wgOut->addHTML( $out ); |
Index: trunk/extensions/OpenStackManager/OpenStackManager.i18n.php |
— | — | @@ -72,6 +72,7 @@ |
73 | 73 | 'openstackmanager-novainstance-info' => 'Instance information', |
74 | 74 | 'openstackmanager-novainstance-puppetinfo' => 'Puppet information', |
75 | 75 | |
| 76 | + 'openstackmanager-deleteinstance' => 'Delete Instance', |
76 | 77 | 'openstackmanager-deleteinstancequestion' => 'Are you sure you wish to delete instance "$1"?', |
77 | 78 | 'openstackmanager-instancelist' => 'Instance list', |
78 | 79 | 'openstackmanager-instancename' => 'Instance name', |
— | — | @@ -101,6 +102,31 @@ |
102 | 103 | 'openstackmanager-consoleoutput' => 'Console Output', |
103 | 104 | 'openstackmanager-getconsoleoutput' => 'get console output', |
104 | 105 | |
| 106 | + 'openstackmanager-createvolume' => 'Create Volume', |
| 107 | + 'openstackmanager-volumename' => 'Volume Name', |
| 108 | + 'openstackmanager-volumeid' => 'Volume Id', |
| 109 | + 'openstackmanager-volumedescription' => 'Volume Description', |
| 110 | + 'openstackmanager-volumestate' => 'Volume State', |
| 111 | + 'openstackmanager-volumeattachmentinstance' => 'Attached to Instance', |
| 112 | + 'openstackmanager-volumeattachmentdevice' => 'Attached as Device', |
| 113 | + 'openstackmanager-volumesize' => 'Volume Size (in GBs)', |
| 114 | + 'openstackmanager-volumeattachmentstatus' => 'Attachment Status', |
| 115 | + 'openstackmanager-volumedeleteonvolumedelete' => 'Delete on Instance Deletion?', |
| 116 | + 'openstackmanager-volumecreationtime' => 'Volume Creation Time', |
| 117 | + 'openstackmanager-attach' => 'attach', |
| 118 | + 'openstackmanager-detach' => 'detach', |
| 119 | + 'openstackmanager-deletevolume' => 'Delete Volume', |
| 120 | + 'openstackmanager-deletevolumequestion' => 'Are you sure you wish to delete volume "$1"?', |
| 121 | + 'openstackmanager-volumelist' => 'Volume List', |
| 122 | + 'openstackmanager-badvolumename' => 'An invalid volume name was given.', |
| 123 | + 'openstackmanager-novavolume-volume' => 'Volume', |
| 124 | + 'openstackmanager-novavolume-info' => 'Volume Info', |
| 125 | + 'openstackmanager-createdvolume' => 'Created volume $1.', |
| 126 | + 'openstackmanager-createevolumefailed' => 'Failed to create volume.', |
| 127 | + 'openstackmanager-deletedvolume' => 'Deleted volume.', |
| 128 | + 'openstackmanager-deletevolumefailed' => 'Failed to delete volume.', |
| 129 | + 'openstackmanager-backvolumelist' => 'Back to volume list', |
| 130 | + |
105 | 131 | 'openstackmanager-novapublickey' => 'Public SSH key', |
106 | 132 | 'openstackmanager-novakey-key' => 'Public SSH key', |
107 | 133 | 'openstackmanager-novakey-info' => 'Public SSH key info', |
Index: trunk/extensions/OpenStackManager/OpenStackNovaVolume.php |
— | — | @@ -0,0 +1,151 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +# TODO: Make this an abstract class, and make the EC2 API a subclass |
| 5 | +class OpenStackNovaVolume { |
| 6 | + |
| 7 | + var $volume; |
| 8 | + |
| 9 | + /** |
| 10 | + * @param $apiInstanceResponse |
| 11 | + */ |
| 12 | + function __construct( $apiInstanceResponse ) { |
| 13 | + $this->volume = $apiInstanceResponse; |
| 14 | + } |
| 15 | + |
| 16 | + /** |
| 17 | + * Return the assigned display name of this volume |
| 18 | + * |
| 19 | + * @return string |
| 20 | + */ |
| 21 | + function getVolumeName() { |
| 22 | + return (string)$this->volume->displayName; |
| 23 | + } |
| 24 | + |
| 25 | + /** |
| 26 | + * Return the assigned description of this volume |
| 27 | + * |
| 28 | + * @return string |
| 29 | + */ |
| 30 | + function getVolumeDescription() { |
| 31 | + return (string)$this->volume->displayDescription; |
| 32 | + } |
| 33 | + |
| 34 | + /** |
| 35 | + * Return the ID of this volume |
| 36 | + * |
| 37 | + * @return string |
| 38 | + */ |
| 39 | + function getVolumeId() { |
| 40 | + return (string)$this->volume->volumeId; |
| 41 | + } |
| 42 | + |
| 43 | + /** |
| 44 | + * Return the status of this volume |
| 45 | + * |
| 46 | + * @return string |
| 47 | + */ |
| 48 | + function getVolumeStatus() { |
| 49 | + $status = (string)$this->volume->status; |
| 50 | + $status = explode( ' ', $status ); |
| 51 | + |
| 52 | + return $status[0]; |
| 53 | + } |
| 54 | + |
| 55 | + /** |
| 56 | + * Returns the instance ID this volume is attached to, or an empty string if |
| 57 | + * not attached |
| 58 | + * |
| 59 | + * @return string |
| 60 | + */ |
| 61 | + function getAttachedInstanceId() { |
| 62 | + return (string)$this->volume->attachmentSet->item->instanceId; |
| 63 | + } |
| 64 | + |
| 65 | + /** |
| 66 | + * Returns the attachment status of this volume |
| 67 | + * |
| 68 | + * @return string |
| 69 | + */ |
| 70 | + function getAttachmentStatus() { |
| 71 | + return (string)$this->volume->attachmentSet->item->status; |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * Returns the attachment time of this volume |
| 76 | + * |
| 77 | + * @return string |
| 78 | + */ |
| 79 | + function getAttachmentTime() { |
| 80 | + return (string)$this->volume->attachmentSet->item->attachTime; |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * Will this volume be deleted when the instance it is attached to is deleted? |
| 85 | + * |
| 86 | + * @return bool |
| 87 | + */ |
| 88 | + function deleteOnInstanceDeletion() { |
| 89 | + return (bool)$this->volume->attachmentSet->item->deleteOnTermination; |
| 90 | + } |
| 91 | + |
| 92 | + /** |
| 93 | + * Return the device used when attached to an instance |
| 94 | + * |
| 95 | + * @return string |
| 96 | + */ |
| 97 | + function getAttachedDevice() { |
| 98 | + return (string)$this->volume->attachmentSet->item->device; |
| 99 | + } |
| 100 | + |
| 101 | + /** |
| 102 | + * Return the size, in GB, of this volume |
| 103 | + * |
| 104 | + * @return int |
| 105 | + */ |
| 106 | + function getVolumeSize() { |
| 107 | + return (string)$this->volume->size; |
| 108 | + } |
| 109 | + |
| 110 | + /** |
| 111 | + * Return the creation date of this volume |
| 112 | + * |
| 113 | + * @return string |
| 114 | + */ |
| 115 | + function getVolumeCreationTime() { |
| 116 | + return (string)$this->volume->creationTime; |
| 117 | + } |
| 118 | + |
| 119 | + /** |
| 120 | + * Return the volume's availability zone |
| 121 | + * |
| 122 | + * @return string |
| 123 | + */ |
| 124 | + function getVolumeAvailabilityZone() { |
| 125 | + return (string)$this->volume->availabilityZone; |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Return the project that owns this instance |
| 130 | + * |
| 131 | + * @return string |
| 132 | + */ |
| 133 | + function getOwner() { |
| 134 | + $status = (string)$this->volume->status; |
| 135 | + $status = explode( ' ', $status ); |
| 136 | + |
| 137 | + return str_replace( array('(',','), '', $status[1] ); |
| 138 | + } |
| 139 | + |
| 140 | + /** |
| 141 | + * Return the volume node that this volume exists on |
| 142 | + * |
| 143 | + * @return string |
| 144 | + */ |
| 145 | + function getVolumeNode() { |
| 146 | + $status = (string)$this->volume->status; |
| 147 | + $status = explode( ' ', $status ); |
| 148 | + |
| 149 | + return str_replace( array(','), '', $status[2] ); |
| 150 | + } |
| 151 | + |
| 152 | +} |
Property changes on: trunk/extensions/OpenStackManager/OpenStackNovaVolume.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 153 | + native |
Index: trunk/extensions/OpenStackManager/OpenStackNovaController.php |
— | — | @@ -7,6 +7,7 @@ |
8 | 8 | var $instances, $images, $keypairs, $availabilityZones; |
9 | 9 | var $addresses, $securityGroups; |
10 | 10 | var $instanceTypes; |
| 11 | + var $volumes; |
11 | 12 | |
12 | 13 | /** |
13 | 14 | * @param $credentials |
— | — | @@ -184,6 +185,36 @@ |
185 | 186 | } |
186 | 187 | |
187 | 188 | /** |
| 189 | + * @param $volumeId |
| 190 | + * @return null|OpenStackNovaVolume |
| 191 | + */ |
| 192 | + function getVolume( $volumeId ) { |
| 193 | + $this->getVolumes(); |
| 194 | + if ( isset( $this->volumes["$volumeId"] ) ) { |
| 195 | + return $this->volumes["$volumeId"]; |
| 196 | + } else { |
| 197 | + return null; |
| 198 | + } |
| 199 | + } |
| 200 | + |
| 201 | + /** |
| 202 | + * Get all volumes |
| 203 | + * |
| 204 | + * @return array |
| 205 | + */ |
| 206 | + function getVolumes() { |
| 207 | + $this->volumes = array(); |
| 208 | + $volumes = $this->novaConnection->describe_volumes(); |
| 209 | + $volumes = $volumes->body->volumeSet->item; |
| 210 | + foreach ( $volumes as $volume ) { |
| 211 | + $volume = new OpenStackNovaVolume( $volume ); |
| 212 | + $volumeId = $volume->getVolumeId(); |
| 213 | + $this->volumes["$volumeId"] = $volume; |
| 214 | + } |
| 215 | + return $this->volumes; |
| 216 | + } |
| 217 | + |
| 218 | + /** |
188 | 219 | * @param $instanceName |
189 | 220 | * @param $image |
190 | 221 | * @param $key |
— | — | @@ -475,4 +506,41 @@ |
476 | 507 | return $response->isOK(); |
477 | 508 | } |
478 | 509 | |
| 510 | + /** |
| 511 | + * Create a Nova volume |
| 512 | + * |
| 513 | + * @param $zone |
| 514 | + * @param $size |
| 515 | + * @param $name |
| 516 | + * @param $description |
| 517 | + * @return OpenStackNovaVolume |
| 518 | + */ |
| 519 | + function createVolume( $zone, $size, $name, $description ) { |
| 520 | + $response = $this->novaConnection->createVolume( $zone, array( |
| 521 | + 'Size' => (int)$size, |
| 522 | + 'DisplayName' => $name, |
| 523 | + 'DisplayDescription' => $description, |
| 524 | + )); |
| 525 | + if ( ! $response->isOK() ) { |
| 526 | + return null; |
| 527 | + } else { |
| 528 | + $volume = new OpenStackNovaVolume( $response->body->volumeSet->item ); |
| 529 | + $id = $volume->getVolumeId(); |
| 530 | + $this->volumes["$id"] = $volume; |
| 531 | + return $volume; |
| 532 | + } |
| 533 | + } |
| 534 | + |
| 535 | + /** |
| 536 | + * Delete a Nova volume |
| 537 | + * |
| 538 | + * @param $volumeid |
| 539 | + * @return boolean |
| 540 | + */ |
| 541 | + function deleteVolume( $volumeid ) { |
| 542 | + $response = $this->novaConnection->deleteVolume( $volumeid ); |
| 543 | + |
| 544 | + return $response->isOK(); |
| 545 | + } |
| 546 | + |
479 | 547 | } |
Index: trunk/extensions/OpenStackManager/OpenStackManager.php |
— | — | @@ -21,15 +21,15 @@ |
22 | 22 | 'path' => __FILE__, |
23 | 23 | 'name' => 'OpenStackManager', |
24 | 24 | 'author' => 'Ryan Lane', |
25 | | - 'version' => '1.1', |
| 25 | + 'version' => '1.2', |
26 | 26 | 'url' => 'http://mediawiki.org/wiki/Extension:OpenStackManager', |
27 | 27 | 'descriptionmsg' => 'openstackmanager-desc', |
28 | 28 | ); |
29 | 29 | |
30 | | -define( "NS_VM", 498 ); |
31 | | -define( "NS_VM_TALK", 499 ); |
32 | | -$wgExtraNamespaces[NS_VM] = 'VM'; |
33 | | -$wgExtraNamespaces[NS_VM_TALK] = 'VM_talk'; |
| 30 | +define( "NS_NOVA_RESOURCE", 498 ); |
| 31 | +define( "NS_NOVA_RESOURCE_TALK", 499 ); |
| 32 | +$wgExtraNamespaces[NS_NOVA_RESOURCE] = 'Nova_Resource'; |
| 33 | +$wgExtraNamespaces[NS_NOVA_RESOURCE_TALK] = 'Nova_Resource_Talk'; |
34 | 34 | |
35 | 35 | $wgGroupPermissions['sysop']['manageproject'] = true; |
36 | 36 | $wgAvailableRights[] = 'manageproject'; |
— | — | @@ -91,6 +91,7 @@ |
92 | 92 | $wgAutoloadClasses['OpenStackNovaSecurityGroup'] = $dir . 'OpenStackNovaSecurityGroup.php'; |
93 | 93 | $wgAutoloadClasses['OpenStackNovaSecurityGroupRule'] = $dir . 'OpenStackNovaSecurityGroupRule.php'; |
94 | 94 | $wgAutoloadClasses['OpenStackNovaRole'] = $dir . 'OpenStackNovaRole.php'; |
| 95 | +$wgAutoloadClasses['OpenStackNovaVolume'] = $dir . 'OpenStackNovaVolume.php'; |
95 | 96 | $wgAutoloadClasses['SpecialNovaInstance'] = $dir . 'special/SpecialNovaInstance.php'; |
96 | 97 | $wgAutoloadClasses['SpecialNovaKey'] = $dir . 'special/SpecialNovaKey.php'; |
97 | 98 | $wgAutoloadClasses['SpecialNovaProject'] = $dir . 'special/SpecialNovaProject.php'; |
— | — | @@ -98,6 +99,7 @@ |
99 | 100 | $wgAutoloadClasses['SpecialNovaAddress'] = $dir . 'special/SpecialNovaAddress.php'; |
100 | 101 | $wgAutoloadClasses['SpecialNovaSecurityGroup'] = $dir . 'special/SpecialNovaSecurityGroup.php'; |
101 | 102 | $wgAutoloadClasses['SpecialNovaRole'] = $dir . 'special/SpecialNovaRole.php'; |
| 103 | +$wgAutoloadClasses['SpecialNovaVolume'] = $dir . 'special/SpecialNovaVolume.php'; |
102 | 104 | $wgAutoloadClasses['SpecialNova'] = $dir . 'special/SpecialNova.php'; |
103 | 105 | $wgAutoloadClasses['OpenStackNovaHostJob'] = $dir . 'OpenStackNovaHostJob.php'; |
104 | 106 | $wgAutoloadClasses['AmazonEC2'] = $dir . 'aws-sdk/sdk.class.php'; |
— | — | @@ -115,6 +117,8 @@ |
116 | 118 | $wgSpecialPageGroups['NovaSecurityGroup'] = 'nova'; |
117 | 119 | $wgSpecialPages['NovaRole'] = 'SpecialNovaRole'; |
118 | 120 | $wgSpecialPageGroups['NovaRole'] = 'nova'; |
| 121 | +$wgSpecialPages['NovaVolume'] = 'SpecialNovaVolume'; |
| 122 | +$wgSpecialPageGroups['NovaVolume'] = 'nova'; |
119 | 123 | $wgJobClasses['addDNSHostToLDAP'] = 'OpenStackNovaHostJob'; |
120 | 124 | |
121 | 125 | $wgHooks['LDAPSetCreationValues'][] = 'OpenStackNovaUser::LDAPSetCreationValues'; |