Retire ironic-webclient repository contents
Per the annoucement[0], the ironic-webclient is being retired from future development. Please see README for instructions on obtaining the state of the repository prior to retirement. [0]: http://lists.openstack.org/pipermail/openstack-dev/2016-December/109195.html Change-Id: Ie5f1cc69830fcaacc3db05d6e77a775c9634f6db
This commit is contained in:
parent
c938dc9817
commit
04e7da6f47
.editorconfig.eslintignore.eslintrc.gitignore.gitreviewLICENSEREADMEREADME.mdmodule.jsbower.jsongulpfile.jskarma.conf.jspackage.json
app
css
favicon.icofonts/openstack
index.htmljs/modules
api
ironic_api_interceptor.jsironic_api_version.jsironic_chassis.jsironic_driver.jsironic_driver_properties.jsironic_node.jsironic_node_power_transition.jsironic_node_provision.jsironic_node_provision_transition.jsironic_port.jsmodule.jsvalidator.js
ironic
controller
action
provision_action_modal_controller.jsremove_node_modal_controller.jsunknown_action_modal_controller.js
configuration_add_controller.jsconfiguration_controller.jsdriver_list_controller.jsenroll_modal_controller.jsheader_controller.jsnode_action_controller.jsnode_detail_controller.jsnode_detail_driver_controller.jsnode_detail_ports_controller.jsnode_list_controller.jsopenstack
configuration.jsdummy_resource.jserror_code.jsmodule.jsresource_cache.jsselected_configuration.js
storage
util
view/ironic
test
@ -1,12 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
@ -1,5 +0,0 @@
|
||||
cover
|
||||
www
|
||||
bower_components
|
||||
node_modules
|
||||
dist
|
23
.eslintrc
23
.eslintrc
@ -1,23 +0,0 @@
|
||||
# Enable eslint-plugin-angular
|
||||
plugins:
|
||||
- angular
|
||||
|
||||
extends: openstack
|
||||
|
||||
# Set up globals
|
||||
globals:
|
||||
angular: false
|
||||
module: false
|
||||
|
||||
env:
|
||||
browser: true
|
||||
jasmine: true
|
||||
|
||||
rules:
|
||||
angular/no-private-call: 0
|
||||
angular/no-services:
|
||||
- 2
|
||||
- - $http
|
||||
- $resource
|
||||
- Restangular
|
||||
angular/no-service-method: 0
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,14 +0,0 @@
|
||||
*.iml
|
||||
.idea
|
||||
bower_components/
|
||||
node_modules/
|
||||
cover/
|
||||
npm-debug.log
|
||||
www/
|
||||
.publish/
|
||||
*.tar.gz
|
||||
*.tgz
|
||||
dist
|
||||
|
||||
# Operating system specific files
|
||||
.DS_Store # OSX Folder Caches
|
@ -1,4 +0,0 @@
|
||||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=openstack/ironic-webclient.git
|
202
LICENSE
202
LICENSE
@ -1,202 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
10
README
Normal file
10
README
Normal file
@ -0,0 +1,10 @@
|
||||
This project is no longer maintained.
|
||||
|
||||
The contents of this repository are still available in the Git
|
||||
source code management system. To see the contents of this
|
||||
repository before it reached its end of life, please check out the
|
||||
previous commit with "git checkout HEAD^1".
|
||||
|
||||
For any further questions, please email
|
||||
openstack-dev@lists.openstack.org or join #openstack-dev on
|
||||
Freenode.
|
115
README.md
115
README.md
@ -1,115 +0,0 @@
|
||||
# ironic-webclient
|
||||
|
||||
A webclient for OpenStack Ironic.
|
||||
|
||||
|
||||
## Important Things
|
||||
|
||||
It is imperative that the design and infrastructure of this project makes it
|
||||
easy to package for various linux distributions. As such, the following
|
||||
decisions have been made:
|
||||
|
||||
|
||||
##### The project must be fully functional directly from source.
|
||||
|
||||
* ECMAScript 5 only, no transpiled languages such as TypeScript or
|
||||
CoffeeScript.
|
||||
* All javascript libraries used at runtime (in the browser) must be committed
|
||||
to source.
|
||||
|
||||
Note that we do not guarantee performance if running in this mode. Certain
|
||||
things, such as in-browser CSS compilation will severely degrade the
|
||||
performance of this application.
|
||||
|
||||
|
||||
##### The project must be easy to develop on.
|
||||
|
||||
* We use common javascript tooling to assist in development (npm, gulp,
|
||||
eslint, bower, etc).
|
||||
* These tools are supportive, but not required, as such they are considered to
|
||||
be environmental, and thus not committed to source.
|
||||
|
||||
|
||||
##### The project must be compatible with the OpenStack License.
|
||||
|
||||
* All runtime dependencies and development tools must use licenses compatible
|
||||
with the Apache2.0 license.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
You will need Node.JS and NPM installed on the target system. For Fedora and/or
|
||||
CentOS systemd you can install these as follows:
|
||||
|
||||
```
|
||||
$ yum install -y nodejs npm #dnf on Fedora
|
||||
```
|
||||
|
||||
and on Debian/Ubuntu with:
|
||||
|
||||
```
|
||||
$ apt-get install nodejs nodejs-legacy npm
|
||||
```
|
||||
|
||||
To install the webclient you have to check out the code and install the
|
||||
dependencies. This can be done as follows:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/openstack/ironic-webclient.git
|
||||
$ cd ironic-webclient
|
||||
$ npm install
|
||||
```
|
||||
|
||||
|
||||
### Enable CORS
|
||||
|
||||
To be able to access the Ironic API, you have to enable CORS. A description for
|
||||
this can be found in the chapter [Cross-origin resource sharing](http://docs.openstack.org/admin-guide/cross_project_cors.html)
|
||||
of the OpenStack Administrator's Guide.
|
||||
|
||||
|
||||
### Hosting
|
||||
|
||||
After installing the dependencies and enabling CORS, you have two options of
|
||||
running the web application; using the development server or hosted using
|
||||
a webserver.
|
||||
|
||||
|
||||
#### Development Server
|
||||
|
||||
The webclient offers a built-in webserver option for development purpose. It is
|
||||
not recommended to use this in production use. You can start this server with:
|
||||
|
||||
```
|
||||
$ npm start
|
||||
```
|
||||
|
||||
Which will start the server on [localhost, port 8000](http://localhost:8000).
|
||||
|
||||
If you want to run on a different port or IP, you can specify this from the
|
||||
command line as follows:
|
||||
|
||||
```
|
||||
IP=0.0.0.0 PORT=8080 npm start
|
||||
```
|
||||
|
||||
|
||||
#### Webserver
|
||||
|
||||
For production use, it is recommended to use a webserver. After running
|
||||
|
||||
```
|
||||
$ npm pack
|
||||
```
|
||||
|
||||
you will have a package which will contain all assets needed for hosting the
|
||||
application.
|
||||
|
||||
|
||||
## Other options
|
||||
|
||||
* Package the site.
|
||||
|
||||
```
|
||||
npm pack
|
||||
```
|
88
app/css/bootstrap.scss
vendored
88
app/css/bootstrap.scss
vendored
@ -1,88 +0,0 @@
|
||||
@import "./bootstrap_variables";
|
||||
@import "../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap";
|
||||
@import "./bootstrap_mixins";
|
||||
|
||||
|
||||
.pull-right-bottom {
|
||||
position: absolute;
|
||||
right: $grid-gutter-width / 2;
|
||||
bottom: $padding-base-horizontal;
|
||||
}
|
||||
|
||||
// Navbar form that respects the column-grid
|
||||
.navbar-form-grid {
|
||||
margin-left: -$navbar-padding-horizontal;
|
||||
margin-right: -$navbar-padding-horizontal;
|
||||
padding: 8px $navbar-padding-horizontal;
|
||||
border-top: 1px solid transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
$shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
|
||||
@include box-shadow($shadow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Button default should have button primary active state.
|
||||
*/
|
||||
.btn-default {
|
||||
&.active, &.active:active, &.active:focus, &.active:hover {
|
||||
background-color: $brand-primary;
|
||||
color: $btn-primary-color;
|
||||
border-color: $btn-primary-border;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom button gradient styles.
|
||||
*/
|
||||
.btn-default-gradient {
|
||||
@include button-gradient-variant($btn-default-color, $btn-default-bg, $btn-default-border);
|
||||
}
|
||||
.btn-primary-gradient {
|
||||
@include button-gradient-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border);
|
||||
}
|
||||
// Success appears as green
|
||||
.btn-success-gradient {
|
||||
@include button-gradient-variant($btn-success-color, $btn-success-bg, $btn-success-border);
|
||||
}
|
||||
// Info appears as blue-green
|
||||
.btn-info-gradient {
|
||||
@include button-gradient-variant($btn-info-color, $btn-info-bg, $btn-info-border);
|
||||
}
|
||||
// Warning appears as orange
|
||||
.btn-warning-gradient {
|
||||
@include button-gradient-variant($btn-warning-color, $btn-warning-bg, $btn-warning-border);
|
||||
}
|
||||
// Danger and error appear as red
|
||||
.btn-danger-gradient {
|
||||
@include button-gradient-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border);
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional spacer styles for vertical padding
|
||||
*/
|
||||
.row {
|
||||
&.padding-top {
|
||||
padding-top: $padding-large-vertical;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional table styles
|
||||
*/
|
||||
table.table {
|
||||
th {
|
||||
background-color: $gray-lighter;
|
||||
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form controls inside of table columns.
|
||||
*/
|
||||
table th .form-control {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
padding: $padding-xs-vertical $padding-xs-horizontal;
|
||||
height: auto;
|
||||
}
|
43
app/css/bootstrap_mixins.scss
vendored
43
app/css/bootstrap_mixins.scss
vendored
@ -1,43 +0,0 @@
|
||||
// Button variants
|
||||
//
|
||||
// Easily pump out default styles, as well as :hover, :focus, :active,
|
||||
// and disabled options for all buttons
|
||||
|
||||
@mixin button-gradient-variant($color, $background, $border) {
|
||||
@include button-variant($color, $background, $border); // Use default styles
|
||||
|
||||
//... and override the backgrounds.
|
||||
@include gradient-vertical($background, darken($background, 10%));
|
||||
|
||||
&:focus,
|
||||
&.focus {
|
||||
@include gradient-vertical(darken($background, 10%), darken($background, 20%));
|
||||
}
|
||||
&:hover {
|
||||
@include gradient-vertical(darken($background, 10%), darken($background, 20%));
|
||||
}
|
||||
&:active,
|
||||
&.active,
|
||||
.open > &.dropdown-toggle {
|
||||
@include gradient-vertical(darken($background, 10%), darken($background, 20%));
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&.focus {
|
||||
@include gradient-vertical(darken($background, 17%), darken($background, 27%));
|
||||
}
|
||||
}
|
||||
&.disabled,
|
||||
&[disabled],
|
||||
fieldset[disabled] & {
|
||||
&:hover,
|
||||
&:focus,
|
||||
&.focus {
|
||||
@include gradient-vertical($background, darken($background, 10%));
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
@include gradient-vertical($color, darken($color, 10%));
|
||||
}
|
||||
}
|
4
app/css/bootstrap_variables.scss
vendored
4
app/css/bootstrap_variables.scss
vendored
@ -1,4 +0,0 @@
|
||||
|
||||
// Bootstrap variable overrides for this UI.
|
||||
$navbar-default-bg: #f8f8f8;
|
||||
$navbar-default-border: $navbar-default-bg;
|
1
app/css/font-awesome.scss
vendored
1
app/css/font-awesome.scss
vendored
@ -1 +0,0 @@
|
||||
@import "../../bower_components/fontawesome/scss/font-awesome";
|
@ -1,4 +0,0 @@
|
||||
body {
|
||||
padding-top: 70px;
|
||||
padding-bottom: 70px;
|
||||
}
|
BIN
app/favicon.ico
BIN
app/favicon.ico
Binary file not shown.
Before Width: 16px | Height: 16px | Size: 1.1 KiB |
@ -1,38 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "<%= fontName %>";
|
||||
src: url('<%= fontPath %><%= fontName %>.eot');
|
||||
src: url('<%= fontPath %><%= fontName %>.eot?#iefix') format('eot'),
|
||||
url('<%= fontPath %><%= fontName %>.woff') format('woff'),
|
||||
url('<%= fontPath %><%= fontName %>.ttf') format('truetype'),
|
||||
url('<%= fontPath %><%= fontName %>.svg#<%= fontName %>') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.<%= className %>:before {
|
||||
display: inline-block;
|
||||
font-family: "<%= fontName %>";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
vertical-align: -15%
|
||||
}
|
||||
|
||||
.<%= className %>-lg {
|
||||
font-size: 1.3333333333333333em;
|
||||
line-height: 0.75em;
|
||||
vertical-align: -15%;
|
||||
}
|
||||
.<%= className %>-2x { font-size: 2em; }
|
||||
.<%= className %>-3x { font-size: 3em; }
|
||||
.<%= className %>-4x { font-size: 4em; }
|
||||
.<%= className %>-5x { font-size: 5em; }
|
||||
.<%= className %>-fw {
|
||||
width: 1.2857142857142858em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
<% _.each(glyphs, function(glyph) { %>.<%= className %>-<%= glyph.name %>:before { content: "\<%= glyph.unicode[0].charCodeAt(0).toString(16).toUpperCase() %>" }
|
||||
<% }); %>
|
@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1"
|
||||
id="Layer_1" sodipodi:docname="openstack-black.svg" inkscape:version="0.48.4 r9939" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px" height="100px"
|
||||
viewBox="0 -20 100 100" enable-background="new 0 -20 100 100" xml:space="preserve">
|
||||
<g>
|
||||
<path id="path3038" inkscape:connector-curvature="0" d="M4.522,67.311c-0.748-0.731-1.157-1.744-1.156-2.855l0.035-16.231
|
||||
l9.387,9.284l-0.029,17.95L4.522,67.311z"/>
|
||||
<polygon id="polygon3040" points="81.236,20.472 96.543,19.128 96.646,44.657 81.338,45.997 "/>
|
||||
<polygon id="polygon3042" points="14.87,26.281 30.188,24.941 30.286,50.473 14.971,51.813 "/>
|
||||
<polygon id="polygon3044" points="3.409,41.106 3.315,16.472 12.692,25.742 12.792,50.384 "/>
|
||||
<path id="path3046" inkscape:connector-curvature="0" d="M18.894,79.873c-1.091,0-2.096-0.406-2.831-1.144
|
||||
c-0.732-0.737-1.135-1.748-1.131-2.844l0.029-17.833l15.32-1.344l-0.006,2.842c0,2.102,1.635,3.743,3.725,3.743l0,0
|
||||
c0.113,0,0.23-0.005,0.348-0.015l43.072-3.774c2.182-0.196,3.895-2.055,3.908-4.231l0.004-3.036l15.307-1.339l-0.029,17.641
|
||||
c-0.006,2.501-2.061,4.719-4.576,4.941l-72.745,6.375C19.155,79.868,19.024,79.873,18.894,79.873z"/>
|
||||
<path id="path3048" inkscape:connector-curvature="0" d="M15.006,2.842c0.005-2.5,2.056-4.713,4.572-4.937l72.748-6.338
|
||||
c0.117-0.01,0.242-0.015,0.363-0.015c1.105,0,2.117,0.409,2.857,1.148c0.734,0.737,1.141,1.75,1.139,2.854l-0.061,17.272
|
||||
l-15.299,1.328l0.002-2.283c0-2.099-1.635-3.743-3.723-3.743c-0.113,0-0.23,0.005-0.346,0.015l-43.079,3.743
|
||||
c-2.152,0.191-3.901,2.088-3.901,4.23l-0.002,2.475l-15.318,1.334L15.006,2.842L15.006,2.842z"/>
|
||||
<path id="path3050" inkscape:connector-curvature="0" d="M3.393,9.228L3.446-8.587c0.005-2.512,2.055-4.728,4.57-4.944l72.75-6.324
|
||||
c0.131-0.012,0.262-0.018,0.395-0.018c1.084,0,2.08,0.399,2.805,1.124c0,0,6.672,6.59,8.244,8.145
|
||||
c-0.021,0.001-72.82,6.344-72.82,6.344c-3.609,0.318-6.549,3.502-6.557,7.096l-0.044,15.681L3.393,9.228L3.393,9.228z"/>
|
||||
<polygon id="polygon3052" points="79.85,48.31 93.551,47.109 95.295,48.836 80.654,50.117 71.115,40.689 72.061,40.605 "/>
|
||||
<path id="path3054" inkscape:connector-curvature="0" d="M72.832,10.71l4.615-0.402c0.053-0.005,0.105-0.007,0.158-0.007
|
||||
c0.896,0,1.549,0.659,1.549,1.567l-0.008,4.655l14.252-1.236l1.793,1.775l-14.641,1.286L72.832,10.71z"/>
|
||||
<polygon id="polygon3056" points="69.785,35.295 69.688,10.984 69.99,10.958 79.059,19.932 79.158,44.568 "/>
|
||||
<polygon id="polygon3058" points="13.461,22.238 26.997,21.059 28.835,22.876 14.185,24.158 4.652,14.735 5.772,14.638 "/>
|
||||
<polygon id="polygon3060" points="13.482,54.125 27.201,52.925 28.938,54.644 14.283,55.931 4.752,46.503 5.692,46.419 "/>
|
||||
<path id="path3062" inkscape:connector-curvature="0" d="M34.008,61.12c-0.073,0-0.146-0.004-0.217-0.013l-0.133-0.036
|
||||
c-0.114-0.023-0.158-0.029-0.199-0.043l-0.105-0.054c-0.102-0.044-0.15-0.063-0.193-0.09l-0.088-0.071
|
||||
c-0.068-0.049-0.112-0.076-0.148-0.11c-0.308-0.295-0.477-0.702-0.477-1.15l0.012-4.485l-2.418-2.392l2.424-0.213l-0.005-1.47
|
||||
l33.401-2.925c2.146-0.186,3.896-2.084,3.904-4.232v-1.425l9.395,9.283l-0.006,3.57c-0.008,1.028-0.891,1.981-1.93,2.074
|
||||
l-43.066,3.773C34.108,61.118,34.058,61.12,34.008,61.12z"/>
|
||||
</g>
|
||||
</svg>
|
Before (image error) Size: 3.7 KiB |
@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="100px" height="100px" viewBox="-282.625 482.5 100 100" enable-background="new -282.625 482.5 100 100"
|
||||
xml:space="preserve">
|
||||
<path d="M-232.5,485.549c6.988,0,13.633,1.471,19.643,4.119l-0.006,0.002c0.045-0.068,0.092-0.139,0.139-0.207
|
||||
c2.832-4.191,7.629-6.949,13.068-6.949c8.704,0,15.76,7.057,15.76,15.76c0,5.01-2.336,9.473-5.979,12.357l0.004-0.002
|
||||
c3.9,7.008,6.122,14.807,6.122,23.396c-0.001,26.926-21.827,48.479-48.751,48.479h-0.25c-26.924,0-48.75-21.553-48.75-48.477
|
||||
c0-8.59,2.221-16.525,6.122-23.535l0.004,0.072c-3.643-2.889-5.979-7.316-5.979-12.324c0-8.705,7.056-15.744,15.76-15.744
|
||||
c5.44,0,10.236,2.684,13.069,6.875c0.045,0.07,0.091,0.133,0.137,0.133h-0.005c6.009-3,12.654-4.037,19.642-4.037 M-215.874,527.504
|
||||
h-33.504c-4.322,4-6.998,10.109-6.998,16.689c0,13.117,10.634,23.678,23.75,23.678c13.117,0,23.751-10.525,23.751-23.643
|
||||
C-208.875,537.65-211.55,531.504-215.874,527.504z M-245.542,534.504c0,8,5.782,12.916,12.916,12.916
|
||||
c7.135,0,12.918-4.916,12.918-12.916H-245.542z"/>
|
||||
</svg>
|
Before (image error) Size: 1.3 KiB |
@ -1,50 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="ironic">
|
||||
<head>
|
||||
<title>OpenStack Bare Metal</title>
|
||||
|
||||
<link rel="shortcut icon" href="./favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="./favicon.ico" type="image/x-icon">
|
||||
|
||||
<!-- Angular v1.4.0 -->
|
||||
<script type="application/javascript"
|
||||
src="js/lib/angular.js"></script>
|
||||
<!-- State-based routing for AngularJS v0.2.14 -->
|
||||
<script type="application/javascript"
|
||||
src="js/lib/angular-ui-router.js"></script>
|
||||
<!-- provides interaction support with RESTful services -->
|
||||
<script type="application/javascript"
|
||||
src="js/lib/angular-resource.js"></script>
|
||||
<!-- provides a convenient wrapper for reading and writing browser cookies -->
|
||||
<script type="application/javascript"
|
||||
src="js/lib/angular-cookies.js"></script>
|
||||
<!-- Native AngularJS directives for Bootstrap -->
|
||||
<script type="application/javascript"
|
||||
src="js/lib/ui-bootstrap-tpls.js"></script>
|
||||
<!-- Checkboxes-as-list-selection modal -->
|
||||
<script type="application/javascript"
|
||||
src="js/lib/checklist-model.js"></script>
|
||||
|
||||
<!-- OpenStack specific configuration discovery -->
|
||||
<script type="application/javascript" src="js/openstack.js"></script>
|
||||
<!-- The Ironic-Webclient root application -->
|
||||
<script type="application/javascript" src="js/ironic.js"></script>
|
||||
<!-- UI Utilities used by the ironic client -->
|
||||
<script type="application/javascript" src="js/util.js"></script>
|
||||
<!-- A module of resources that talk with the ironic API -->
|
||||
<script type="application/javascript" src="js/api.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/font-awesome.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/main.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="css/openstack-font.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div ui-view>
|
||||
<p class="text-center">
|
||||
<i class="fa fa-refresh fa-spin"></i>
|
||||
Loading...
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Logic that needs to be applied to every request against the Ironic API. Includes result
|
||||
* transformation and other things.
|
||||
*/
|
||||
angular.module('ironic.api').service('ironicApiInterceptor',
|
||||
function($q, $http) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Ironic's error message is a doubly-encoded JSON string. This checks the body for that
|
||||
* field and runs a second decoder.
|
||||
*
|
||||
* @param {*} responseBody The decoded JSON response body.
|
||||
* @param {Function} headers Headers getter.
|
||||
* @param {int} status The HTTP Status of the response.
|
||||
* @returns {*} The decoded response body.
|
||||
*/
|
||||
function parseErrorResponse (responseBody, headers, status) {
|
||||
if (400 <= status && responseBody.hasOwnProperty('error_message')) {
|
||||
responseBody.error_message = angular.fromJson(responseBody.error_message);
|
||||
}
|
||||
return responseBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* In some cases (as with list responses), we need to return the content of a child property
|
||||
* of the returned body rather than the whole response. This method returns a transformation
|
||||
* function that applies this change.
|
||||
*
|
||||
* @param {String} propertyName The property name to reduce to.
|
||||
* @returns {Function} A function that reduces the response appropriately.
|
||||
*/
|
||||
function parseChildProperty (propertyName) {
|
||||
/**
|
||||
* Response transformer for a specific ironic list response. If the property is not found
|
||||
* (As with error responses), simply returns the original object.
|
||||
*
|
||||
* @param {*} responseBody The body received from the server.
|
||||
* @returns {Array} List of results.
|
||||
*/
|
||||
return function(responseBody) {
|
||||
if (responseBody.hasOwnProperty(propertyName)) {
|
||||
return responseBody[propertyName];
|
||||
}
|
||||
return responseBody;
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Transform the result of an object query from the Ironic API, accommodating for error
|
||||
* and list responses.
|
||||
*
|
||||
* @param {String} childPropertyName (optional) The name of the child property to reduce to.
|
||||
* @returns {Array} An array of transformations.
|
||||
*/
|
||||
response: function(childPropertyName) {
|
||||
var transformers = $http.defaults.transformResponse.concat([]);
|
||||
transformers.push(parseErrorResponse);
|
||||
|
||||
if (childPropertyName) {
|
||||
transformers.push(parseChildProperty(childPropertyName));
|
||||
}
|
||||
|
||||
return transformers;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The current supported version of the ironic api. This version is hardcoded until a more
|
||||
* sophisticated version negotiation algorithm can be provided. The main blocker is that the
|
||||
* current APi abstraction library - ngResource - does not provide pre-flight modificiation of
|
||||
* requests via promise resolution. A patch has been provided
|
||||
* https://github.com/angular/angular.js/pull/13273; if accepted, this parameter will be
|
||||
* incorproated into the ironic_api_interceptor. If not, alternative libraries will have to be
|
||||
* evaluated.
|
||||
*/
|
||||
angular.module('ironic.api').constant('ironicApiVersion', function() {
|
||||
'use strict';
|
||||
return '1.14';
|
||||
});
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IronicChassis is an ngResource abstraction, which switches which Ironic it talks to based on the
|
||||
* selected cloud configuration provided by the $$configuration service. It may be used as if it
|
||||
* was an ngResource instance, and supports the methods `query`, `create`, `read`, `update`, and
|
||||
* `remove`.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicChassis',
|
||||
function($log, $$selectedConfiguration, $$resourceCache, $resource, $$dummyResource,
|
||||
ironicApiInterceptor, ironicApiVersion) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This method extracts the current active API root URI from $$configuration, ensures that
|
||||
* the appropriate Ironic resources exists in the $$resourceCache, and returns it.
|
||||
*
|
||||
* @returns {{}} The created, and cached, IronicPort resource.
|
||||
*/
|
||||
function getResource () {
|
||||
// Pull the current configuration.
|
||||
var currentConfig = $$selectedConfiguration.get();
|
||||
|
||||
// This should resolve the API root, except in cases where the selected configuration is
|
||||
// invalid and/or has not yet been resolved.
|
||||
var ironicConfig = currentConfig.ironic || {};
|
||||
var ironicApiRoot = ironicConfig.apiRoot || null;
|
||||
|
||||
if (!ironicApiRoot) {
|
||||
$log.warn('Ironic API Root for Config [' + currentConfig.id + '] not found.');
|
||||
return $$dummyResource;
|
||||
}
|
||||
|
||||
// Build and/or retrieve a cached instance of the requested service.
|
||||
var chassisUrl = ironicApiRoot + '/chassis/:uuid';
|
||||
|
||||
if (!$$resourceCache.has(chassisUrl)) {
|
||||
$log.debug("Creating new IronicChassis at: " + chassisUrl);
|
||||
|
||||
var resource = $resource(chassisUrl, {uuid: '@uuid'}, {
|
||||
query: {
|
||||
method: 'GET',
|
||||
isArray: true,
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response('chassis')
|
||||
},
|
||||
create: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
read: {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
update: {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
remove: {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
}
|
||||
});
|
||||
|
||||
$$resourceCache.set(chassisUrl, resource);
|
||||
}
|
||||
|
||||
return $$resourceCache.get(chassisUrl);
|
||||
}
|
||||
|
||||
return {
|
||||
query: function() {
|
||||
var r = getResource();
|
||||
return r.query.apply(r, arguments);
|
||||
},
|
||||
create: function() {
|
||||
var r = getResource();
|
||||
return r.create.apply(r, arguments);
|
||||
},
|
||||
read: function() {
|
||||
var r = getResource();
|
||||
return r.read.apply(r, arguments);
|
||||
},
|
||||
update: function() {
|
||||
var r = getResource();
|
||||
return r.update.apply(r, arguments);
|
||||
},
|
||||
remove: function() {
|
||||
var r = getResource();
|
||||
return r.remove.apply(r, arguments);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IronicDriver is an ngResource abstraction, which switches which Ironic it talks to based on the
|
||||
* selected cloud configuration provided by the $$configuration service. It may be used as if it
|
||||
* was an ngResource instance, and supports the methods `query`, `create`, `read`, `update`, and
|
||||
* `remove`.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicDriver',
|
||||
function($log, $$selectedConfiguration, $$resourceCache, $resource, $$dummyResource,
|
||||
ironicApiInterceptor, ironicApiVersion) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This method extracts the current active API root URI from $$configuration, ensures that
|
||||
* the appropriate Ironic resources exists in the $$resourceCache, and returns it.
|
||||
*
|
||||
* @returns {{}} The created, and cached, IronicPort resource.
|
||||
*/
|
||||
function getResource () {
|
||||
// Pull the current configuration.
|
||||
var currentConfig = $$selectedConfiguration.get();
|
||||
|
||||
// This should resolve the API root, except in cases where the selected configuration is
|
||||
// invalid and/or has not yet been resolved.
|
||||
var ironicConfig = currentConfig.ironic || {};
|
||||
var ironicApiRoot = ironicConfig.apiRoot || null;
|
||||
|
||||
if (!ironicApiRoot) {
|
||||
$log.warn('Ironic API Root for Config [' + currentConfig.id + '] not found.');
|
||||
return $$dummyResource;
|
||||
}
|
||||
|
||||
// Build and/or retrieve a cached instance of the requested service.
|
||||
var driverUrl = ironicApiRoot + '/drivers/:uuid';
|
||||
|
||||
if (!$$resourceCache.has(driverUrl)) {
|
||||
$log.debug("Creating new IronicDriver at: " + driverUrl);
|
||||
var resource = $resource(driverUrl, {uuid: '@uuid'}, {
|
||||
query: {
|
||||
method: 'GET',
|
||||
isArray: true,
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response('drivers')
|
||||
},
|
||||
create: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
read: {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
update: {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
remove: {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
}
|
||||
});
|
||||
|
||||
$$resourceCache.set(driverUrl, resource);
|
||||
}
|
||||
|
||||
return $$resourceCache.get(driverUrl);
|
||||
}
|
||||
|
||||
return {
|
||||
query: function() {
|
||||
var r = getResource();
|
||||
return r.query.apply(r, arguments);
|
||||
},
|
||||
create: function() {
|
||||
var r = getResource();
|
||||
return r.create.apply(r, arguments);
|
||||
},
|
||||
read: function() {
|
||||
var r = getResource();
|
||||
return r.read.apply(r, arguments);
|
||||
},
|
||||
update: function() {
|
||||
var r = getResource();
|
||||
return r.update.apply(r, arguments);
|
||||
},
|
||||
remove: function() {
|
||||
var r = getResource();
|
||||
return r.remove.apply(r, arguments);
|
||||
}
|
||||
};
|
||||
});
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IronicDriverProperites is an ngResource abstraction, which switches which Ironic it talks to
|
||||
* based on the selected cloud configuration provided by the $$configuration service. It may be
|
||||
* used as if it was an ngResource instance, and supports the methods `query`, `create`, `read`,
|
||||
* `update`, and * `remove`.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicDriverProperties',
|
||||
function($log, $$selectedConfiguration, $$resourceCache, $resource, $$dummyResource,
|
||||
ironicApiInterceptor, ironicApiVersion) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This method extracts the current active API root URI from $$configuration, ensures that
|
||||
* the appropriate Ironic resources exists in the $$resourceCache, and returns it.
|
||||
*
|
||||
* @returns {{}} The created, and cached, IronicPort resource.
|
||||
*/
|
||||
function getResource () {
|
||||
// Pull the current configuration.
|
||||
var currentConfig = $$selectedConfiguration.get();
|
||||
|
||||
// This should resolve the API root, except in cases where the selected configuration is
|
||||
// invalid and/or has not yet been resolved.
|
||||
var ironicConfig = currentConfig.ironic || {};
|
||||
var ironicApiRoot = ironicConfig.apiRoot || null;
|
||||
|
||||
if (!ironicApiRoot) {
|
||||
$log.warn('Ironic API Root for Config [' + currentConfig.id + '] not found.');
|
||||
return $$dummyResource;
|
||||
}
|
||||
|
||||
// Build and/or retrieve a cached instance of the requested service.
|
||||
var driverUrl = ironicApiRoot + '/drivers/properties?driver_name=:driver_name';
|
||||
|
||||
if (!$$resourceCache.has(driverUrl)) {
|
||||
$log.debug("Creating new IronicDriverProperties at: " + driverUrl);
|
||||
var resource = $resource(driverUrl, {driver_name: 'driver_name'}, {
|
||||
read: {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
}
|
||||
});
|
||||
|
||||
$$resourceCache.set(driverUrl, resource);
|
||||
}
|
||||
|
||||
return $$resourceCache.get(driverUrl);
|
||||
}
|
||||
|
||||
return {
|
||||
read: function() {
|
||||
var r = getResource();
|
||||
return r.read.apply(r, arguments);
|
||||
}
|
||||
};
|
||||
});
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IronicNode is an ngResource abstraction, which switches which Ironic it talks to based on the
|
||||
* selected cloud configuration provided by the $$configuration service. It may be used as if it
|
||||
* was an ngResource instance, and supports the methods `query`, `create`, `read`, `update`, and
|
||||
* `remove`.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicNode',
|
||||
function($log, $$selectedConfiguration, $$resourceCache, $resource, $$dummyResource,
|
||||
ironicApiInterceptor, ironicApiVersion) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This method extracts the current active API root URI from $$configuration, ensures that
|
||||
* the appropriate Ironic resources exists in the $$resourceCache, and returns it.
|
||||
*
|
||||
* @returns {{}} The created, and cached, IronicPort resource.
|
||||
*/
|
||||
function getResource () {
|
||||
// Pull the current configuration.
|
||||
var currentConfig = $$selectedConfiguration.get();
|
||||
|
||||
// This should resolve the API root, except in cases where the selected configuration is
|
||||
// invalid and/or has not yet been resolved.
|
||||
var ironicConfig = currentConfig.ironic || {};
|
||||
var ironicApiRoot = ironicConfig.apiRoot || null;
|
||||
|
||||
if (!ironicApiRoot) {
|
||||
$log.warn('Ironic API Root for Config [' + currentConfig.id + '] not found.');
|
||||
return $$dummyResource;
|
||||
}
|
||||
|
||||
// Build and/or retrieve a cached instance of the requested service.
|
||||
var nodeUrl = ironicApiRoot + '/nodes/:uuid';
|
||||
|
||||
if (!$$resourceCache.has(nodeUrl)) {
|
||||
$log.debug("Creating new IronicNode at: " + nodeUrl);
|
||||
var resource = $resource(nodeUrl, {uuid: '@uuid'}, {
|
||||
query: {
|
||||
method: 'GET',
|
||||
isArray: true,
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response('nodes')
|
||||
},
|
||||
create: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
read: {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
update: {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
remove: {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
}
|
||||
});
|
||||
|
||||
$$resourceCache.set(nodeUrl, resource);
|
||||
}
|
||||
|
||||
return $$resourceCache.get(nodeUrl);
|
||||
}
|
||||
|
||||
return {
|
||||
query: function() {
|
||||
var r = getResource();
|
||||
return r.query.apply(r, arguments);
|
||||
},
|
||||
create: function() {
|
||||
var r = getResource();
|
||||
return r.create.apply(r, arguments);
|
||||
},
|
||||
read: function() {
|
||||
var r = getResource();
|
||||
return r.read.apply(r, arguments);
|
||||
},
|
||||
update: function() {
|
||||
var r = getResource();
|
||||
return r.update.apply(r, arguments);
|
||||
},
|
||||
remove: function() {
|
||||
var r = getResource();
|
||||
return r.remove.apply(r, arguments);
|
||||
}
|
||||
};
|
||||
});
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, LP
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IronicNodePowerTransition is a mock API that returns the list of valid power
|
||||
* transitions for nodes.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicNodePowerTransition',
|
||||
function($q) {
|
||||
'use strict';
|
||||
|
||||
// Build a dummy resource. The API will return this wrapped in an additional 'transitions'
|
||||
// field, but we'll just use the raw array.
|
||||
var transitions = [
|
||||
{
|
||||
from_state: "power on",
|
||||
event: "power off",
|
||||
target_state: "power off",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "power off",
|
||||
event: "power on",
|
||||
target_state: "power on",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "power on",
|
||||
event: "reboot",
|
||||
target_state: "rebooting",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "rebooting",
|
||||
event: "power on",
|
||||
target_state: "power on",
|
||||
actor: "conductor"
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
query: function(params, successHandler, errorHandler) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
// Build our result array.
|
||||
var queryResults = [];
|
||||
queryResults.$promise = deferred.promise;
|
||||
queryResults.$resolved = false;
|
||||
deferred.promise.then(function(results) {
|
||||
angular.forEach(results, function(result) {
|
||||
queryResults.push(result);
|
||||
});
|
||||
});
|
||||
deferred.promise.finally(function() {
|
||||
queryResults.$resolved = true;
|
||||
});
|
||||
|
||||
// Check for a filter
|
||||
if (params) {
|
||||
var filteredResults = transitions.filter(function(item) {
|
||||
var approved = true;
|
||||
angular.forEach(params, function(value, key) {
|
||||
if (!item.hasOwnProperty(key) || item[key] !== value) {
|
||||
approved = false;
|
||||
}
|
||||
});
|
||||
|
||||
return approved;
|
||||
});
|
||||
deferred.resolve(filteredResults);
|
||||
} else {
|
||||
deferred.resolve(transitions);
|
||||
}
|
||||
|
||||
queryResults.$promise.then(successHandler || null, errorHandler || null);
|
||||
|
||||
return queryResults;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This resource handles node provision state transitions. It only exposes the $update (PUT) method,
|
||||
* as that's the only real valid action that can be taken. This service does not validate a
|
||||
* change which a user/script may want to take.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicNodeProvision',
|
||||
function($log, $$selectedConfiguration, $$resourceCache, $resource, $$dummyResource,
|
||||
ironicApiInterceptor, ironicApiVersion) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This method extracts the current active API root URI from $$configuration, ensures that
|
||||
* the appropriate Ironic resources exists in the $$resourceCache, and returns it.
|
||||
*
|
||||
* @returns {{}} The created, and cached, IronicPort resource.
|
||||
*/
|
||||
function getResource () {
|
||||
// Pull the current configuration.
|
||||
var currentConfig = $$selectedConfiguration.get();
|
||||
|
||||
// This should resolve the API root, except in cases where the selected configuration is
|
||||
// invalid and/or has not yet been resolved.
|
||||
var ironicConfig = currentConfig.ironic || {};
|
||||
var ironicApiRoot = ironicConfig.apiRoot || null;
|
||||
|
||||
if (!ironicApiRoot) {
|
||||
$log.warn('Ironic API Root for Config [' + currentConfig.id + '] not found.');
|
||||
return $$dummyResource;
|
||||
}
|
||||
|
||||
// Build and/or retrieve a cached instance of the requested service.
|
||||
var nodeUrl = ironicApiRoot + '/nodes/:node_ident/states/provision';
|
||||
|
||||
if (!$$resourceCache.has(nodeUrl)) {
|
||||
$log.debug("Creating new IronicNodeProvision at: " + nodeUrl);
|
||||
var resource = $resource(nodeUrl, {node_ident: '@node_ident'}, {
|
||||
update: {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
}
|
||||
});
|
||||
|
||||
$$resourceCache.set(nodeUrl, resource);
|
||||
}
|
||||
|
||||
return $$resourceCache.get(nodeUrl);
|
||||
}
|
||||
|
||||
return {
|
||||
update: function() {
|
||||
var r = getResource();
|
||||
return r.update.apply(r, arguments);
|
||||
}
|
||||
};
|
||||
});
|
@ -1,281 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IronicNodeProvisionTransition is a mock API that returns the transitions list for
|
||||
* the ironic state machine. It is intended to be supplanted when the work for
|
||||
* https://review.openstack.org/#/c/224022/ is completed, though it may continue
|
||||
* to exist for legacy API microversions.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicNodeProvisionTransition',
|
||||
function($q) {
|
||||
'use strict';
|
||||
|
||||
// Build a dummy resource. The API will return this wrapped in an additional 'transitions'
|
||||
// field, but we'll just use the raw array.
|
||||
var transitions = [
|
||||
{
|
||||
from_state: "active",
|
||||
event: "rebuild",
|
||||
target_state: "deploying",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "active",
|
||||
event: "delete",
|
||||
target_state: "deleting",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "available",
|
||||
event: "manage",
|
||||
target_state: "manageable",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "available",
|
||||
event: "active",
|
||||
target_state: "deploying",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "clean failed",
|
||||
event: "manage",
|
||||
target_state: "manageable",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "clean wait",
|
||||
event: "fail",
|
||||
target_state: "clean failed",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "clean wait",
|
||||
event: "abort",
|
||||
target_state: "clean failed",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "clean wait",
|
||||
event: "resume",
|
||||
target_state: "cleaning",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "deleting",
|
||||
event: "clean",
|
||||
target_state: "cleaning",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "deleting",
|
||||
event: "error",
|
||||
target_state: "error",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "deploy failed",
|
||||
event: "rebuild",
|
||||
target_state: "deploying",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "deploy failed",
|
||||
event: "delete",
|
||||
target_state: "deleting",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "deploy failed",
|
||||
event: "active",
|
||||
target_state: "deploying",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "wait call-back",
|
||||
event: "delete",
|
||||
target_state: "deleting",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "wait call-back",
|
||||
event: "resume",
|
||||
target_state: "deploying",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "wait call-back",
|
||||
event: "fail",
|
||||
target_state: "deploy failed",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "error",
|
||||
event: "rebuild",
|
||||
target_state: "deploying",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "error",
|
||||
event: "delete",
|
||||
target_state: "deleting",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "enroll",
|
||||
event: "manage",
|
||||
target_state: "verifying",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "inspect failed",
|
||||
event: "inspect",
|
||||
target_state: "inspecting",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "inspect failed",
|
||||
event: "manage",
|
||||
target_state: "manageable",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "manageable",
|
||||
event: "inspect",
|
||||
target_state: "inspecting",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "manageable",
|
||||
event: "provide",
|
||||
target_state: "cleaning",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "manageable",
|
||||
event: "clean",
|
||||
target_state: "cleaning",
|
||||
actor: "user"
|
||||
},
|
||||
{
|
||||
from_state: "verifying",
|
||||
event: "fail",
|
||||
target_state: "enroll",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "verifying",
|
||||
event: "done",
|
||||
target_state: "manageable",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "inspecting",
|
||||
event: "fail",
|
||||
target_state: "inspect failed",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "inspecting",
|
||||
event: "done",
|
||||
target_state: "manageable",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "cleaning",
|
||||
event: "manage",
|
||||
target_state: "manageable",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "cleaning",
|
||||
event: "wait",
|
||||
target_state: "clean wait",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "cleaning",
|
||||
event: "fail",
|
||||
target_state: "clean failed",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "cleaning",
|
||||
event: "done",
|
||||
target_state: "available",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "deploying",
|
||||
event: "fail",
|
||||
target_state: "deploy failed",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "deploying",
|
||||
event: "wait",
|
||||
target_state: "wait call-back",
|
||||
actor: "conductor"
|
||||
},
|
||||
{
|
||||
from_state: "deploying",
|
||||
event: "done",
|
||||
target_state: "active",
|
||||
actor: "conductor"
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
query: function(params, successHandler, errorHandler) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
// Build our result array.
|
||||
var queryResults = [];
|
||||
queryResults.$promise = deferred.promise;
|
||||
queryResults.$resolved = false;
|
||||
deferred.promise.then(function(results) {
|
||||
angular.forEach(results, function(result) {
|
||||
queryResults.push(result);
|
||||
});
|
||||
});
|
||||
deferred.promise.finally(function() {
|
||||
queryResults.$resolved = true;
|
||||
});
|
||||
|
||||
// Check for a filter
|
||||
if (params) {
|
||||
var filteredResults = transitions.filter(function(item) {
|
||||
var approved = true;
|
||||
angular.forEach(params, function(value, key) {
|
||||
if (!item.hasOwnProperty(key) || item[key] !== value) {
|
||||
approved = false;
|
||||
}
|
||||
});
|
||||
|
||||
return approved;
|
||||
});
|
||||
deferred.resolve(filteredResults);
|
||||
} else {
|
||||
deferred.resolve(transitions);
|
||||
}
|
||||
|
||||
queryResults.$promise.then(successHandler || null, errorHandler || null);
|
||||
|
||||
return queryResults;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IronicPort is an ngResource abstraction, which switches which Ironic it talks to based on the
|
||||
* selected cloud configuration provided by the $$configuration service. It may be used as if it
|
||||
* was an ngResource instance, and supports the methods `query`, `create`, `read`, `update`, and
|
||||
* `remove`.
|
||||
*/
|
||||
angular.module('ironic.api').factory('IronicPort',
|
||||
function($log, $$selectedConfiguration, $$resourceCache, $resource, $$dummyResource,
|
||||
ironicApiInterceptor, ironicApiVersion) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* This method extracts the current active API root URI from $$configuration, ensures that
|
||||
* the appropriate Ironic resources exists in the $$resourceCache, and returns it.
|
||||
*
|
||||
* @returns {{}} The created, and cached, IronicPort resource.
|
||||
*/
|
||||
function getResource () {
|
||||
// Pull the current configuration.
|
||||
var currentConfig = $$selectedConfiguration.get();
|
||||
|
||||
// This should resolve the API root, except in cases where the selected configuration is
|
||||
// invalid and/or has not yet been resolved.
|
||||
var ironicConfig = currentConfig.ironic || {};
|
||||
var ironicApiRoot = ironicConfig.apiRoot || null;
|
||||
|
||||
if (!ironicApiRoot) {
|
||||
$log.warn('Ironic API Root for Config [' + currentConfig.id + '] not found.');
|
||||
return $$dummyResource;
|
||||
}
|
||||
|
||||
// Build and/or retrieve a cached instance of the requested service.
|
||||
var portUrl = ironicApiRoot + '/ports/:uuid';
|
||||
|
||||
if (!$$resourceCache.has(portUrl)) {
|
||||
$log.debug("Creating new IronicPort at: " + portUrl);
|
||||
var resource = $resource(portUrl, {uuid: '@uuid'}, {
|
||||
query: {
|
||||
method: 'GET',
|
||||
isArray: true,
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response('ports')
|
||||
},
|
||||
create: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
read: {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
update: {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
},
|
||||
remove: {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-OpenStack-Ironic-API-Version': ironicApiVersion
|
||||
},
|
||||
transformResponse: ironicApiInterceptor.response()
|
||||
}
|
||||
});
|
||||
|
||||
$$resourceCache.set(portUrl, resource);
|
||||
}
|
||||
|
||||
return $$resourceCache.get(portUrl);
|
||||
}
|
||||
|
||||
return {
|
||||
query: function() {
|
||||
var r = getResource();
|
||||
return r.query.apply(r, arguments);
|
||||
},
|
||||
create: function() {
|
||||
var r = getResource();
|
||||
return r.create.apply(r, arguments);
|
||||
},
|
||||
read: function() {
|
||||
var r = getResource();
|
||||
return r.read.apply(r, arguments);
|
||||
},
|
||||
update: function() {
|
||||
var r = getResource();
|
||||
return r.update.apply(r, arguments);
|
||||
},
|
||||
remove: function() {
|
||||
var r = getResource();
|
||||
return r.remove.apply(r, arguments);
|
||||
}
|
||||
};
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A module of resources that talk with the ironic API.
|
||||
*/
|
||||
angular.module('ironic.api', ['openstack', 'ngResource'])
|
||||
.config(function($$configurationProvider, $windowProvider) {
|
||||
'use strict';
|
||||
|
||||
// Build a default ironic location from the $window provider
|
||||
var location = $windowProvider.$get().location;
|
||||
var apiRoot = location.protocol + '//' + location.hostname + ':6385';
|
||||
|
||||
// This line registers ironic's default API root, as detected via the current hostname, with
|
||||
// the $$configurationProvider's default API detection mechanism.
|
||||
$$configurationProvider.$registerDefault('ironic', apiRoot);
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Form validator that will perform an asynchronous check to see if Ironic is
|
||||
* available at the provided url. It will expose a variable on the control to
|
||||
* which it is applied, with an array of detected API versions.
|
||||
*/
|
||||
/*eslint-disable angular/no-services */
|
||||
angular.module('ironic.api').directive('ironicApiUrl',
|
||||
function ($q, $http) {
|
||||
/*eslint-enable angular/no-services */
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
|
||||
ctrl.$ironicVersions = [];
|
||||
|
||||
ctrl.$asyncValidators.ironicApiUrl =
|
||||
function (modelValue) {
|
||||
var def = $q.defer();
|
||||
|
||||
$http.get(modelValue).then(function (result) {
|
||||
var name = result.data.name;
|
||||
|
||||
if (name !== 'OpenStack Ironic API') {
|
||||
def.reject();
|
||||
}
|
||||
|
||||
var versions = result.data.versions || [];
|
||||
for (var i = 0; i < versions.length; i++) {
|
||||
versions[i] = versions[i].id;
|
||||
}
|
||||
ctrl.$ironicVersions = versions;
|
||||
def.resolve();
|
||||
}, function () {
|
||||
def.reject();
|
||||
});
|
||||
|
||||
return def.promise;
|
||||
};
|
||||
}
|
||||
};
|
||||
});
|
@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A generic controller which permits a user to issue provision state actions against a list of
|
||||
* nodes.
|
||||
*/
|
||||
angular.module('ironic').controller('ProvisionActionModalController',
|
||||
function($q, $uibModalInstance, nodeIds, actionName, IronicNode, IronicNodeProvisionTransition,
|
||||
IronicNodeProvision) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
vm.someUpdated = false;
|
||||
vm.updating = false;
|
||||
vm.someNodesExcluded = false;
|
||||
vm.actionName = actionName;
|
||||
|
||||
// Setup our nodes.
|
||||
vm.nodes = [];
|
||||
vm.nodes.$resolved = false;
|
||||
|
||||
// This is the data preloader, which drives all of our modal data setup. This logic will
|
||||
// execute in sequence.
|
||||
vm.nodes.$promise = $q
|
||||
.all({
|
||||
nodes: loadNodes(),
|
||||
states: loadValidStates()
|
||||
})
|
||||
.then(filterNodes)
|
||||
.then(contextWrap)
|
||||
.then(applyNodesToContext)
|
||||
.then(toggleExclusionFlag)
|
||||
.finally(function() {
|
||||
vm.nodes.$resolved = true;
|
||||
});
|
||||
|
||||
/**
|
||||
* Resolve all states for which the current action is valid.
|
||||
*
|
||||
* @return {Promise} A promise that resolves with all valid states.
|
||||
*/
|
||||
function loadValidStates () {
|
||||
return IronicNodeProvisionTransition.query().$promise
|
||||
.then(function(transitions) {
|
||||
return transitions
|
||||
.filter(function(transition) {
|
||||
return transition.event === actionName;
|
||||
})
|
||||
.map(function(transition) {
|
||||
return transition.from_state;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the node details for all the passed node ID's.
|
||||
*
|
||||
* @return {Promise} A promise that resolves with all nodes details.
|
||||
*/
|
||||
function loadNodes () {
|
||||
var promises = [];
|
||||
angular.forEach(nodeIds, function(nodeId) {
|
||||
promises.push(IronicNode.read({uuid: nodeId}).$promise);
|
||||
});
|
||||
return $q.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the nodes into a valid set.
|
||||
*
|
||||
* @param {{}} results Results from preloading the valid states and valid nodes.
|
||||
* @return {[]} A list of nodes that may be manipulated with this action.
|
||||
*/
|
||||
function filterNodes (results) {
|
||||
var nodes = results.nodes;
|
||||
var states = results.states;
|
||||
|
||||
return nodes.filter(function(node) {
|
||||
return states.indexOf(node.provision_state) > -1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap each node in a context object, used to track state.
|
||||
*
|
||||
* @param {[]} nodes A list of nodes.
|
||||
* @return {[]} A list of context wrapped nodes.
|
||||
*/
|
||||
function contextWrap (nodes) {
|
||||
return nodes.map(function(node) {
|
||||
return {
|
||||
node: node,
|
||||
error: null,
|
||||
state: 'ready', // ready, busy, error, complete
|
||||
changed: false
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the nodes to the controller's variables, in a non-destructive fashion.
|
||||
*
|
||||
* @param {[]} nodes The list of nodes to apply.
|
||||
* @return {void}
|
||||
*/
|
||||
function applyNodesToContext (nodes) {
|
||||
return angular.forEach(nodes, function(node) {
|
||||
vm.nodes.push(node);
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the flag on the controller that indicates that some of the selected nodes are not
|
||||
* in a valid state for this action.
|
||||
*
|
||||
* @param {[]} loadedNodes A list of loaded nodes.
|
||||
* @return {[]} That same list of loaded nodes, with no modifications.
|
||||
*/
|
||||
function toggleExclusionFlag (loadedNodes) {
|
||||
vm.someNodesExcluded = loadedNodes.length !== nodeIds.length;
|
||||
return loadedNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the action for which this controller has been configured.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
vm.apply = function() {
|
||||
vm.updating = true;
|
||||
var promises = [];
|
||||
|
||||
// For each context object in our controller...
|
||||
angular.forEach(vm.nodes, function(ctx) {
|
||||
// Try to issue the request.
|
||||
ctx.state = 'updating';
|
||||
|
||||
var state = IronicNodeProvision.update({
|
||||
node_ident: ctx.node.uuid,
|
||||
target: actionName
|
||||
}, function() {
|
||||
vm.someUpdated = true;
|
||||
ctx.changed = true;
|
||||
ctx.state = 'complete';
|
||||
}, function(error) {
|
||||
ctx.state = 'error';
|
||||
ctx.error = error.data.error_message;
|
||||
});
|
||||
|
||||
promises.push(state.$promise);
|
||||
});
|
||||
|
||||
// Wait for all the promises...
|
||||
$q.all(promises).then(
|
||||
function() {
|
||||
// If all are successful, just close.
|
||||
vm.close();
|
||||
})
|
||||
.finally(function() {
|
||||
// Flip the updating bit.
|
||||
vm.updating = false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Close this modal.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
vm.close = function() {
|
||||
if (vm.someUpdated) {
|
||||
// Something was changed, collect the changed nodes and return them.
|
||||
var changedNodeIds = [];
|
||||
angular.forEach(vm.nodes, function(ctx) {
|
||||
if (ctx.changed) {
|
||||
changedNodeIds.push(ctx.node.uuid);
|
||||
}
|
||||
});
|
||||
$uibModalInstance.close(changedNodeIds);
|
||||
} else {
|
||||
// Nothing was changed.
|
||||
$uibModalInstance.dismiss();
|
||||
}
|
||||
};
|
||||
});
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This controller backs the "Remove Node" modal.
|
||||
*/
|
||||
angular.module('ironic').controller('RemoveNodeModalController',
|
||||
function($uibModalInstance, nodes, $q) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
// Wrap all the nodes in their own context objects.
|
||||
vm.someDeleted = false;
|
||||
vm.deleting = false;
|
||||
vm.nodes = [];
|
||||
angular.forEach(nodes, function(node) {
|
||||
vm.nodes.push({
|
||||
node: node,
|
||||
error: null,
|
||||
state: 'present'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Remove all the nodes on this controller.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.remove = function() {
|
||||
vm.deleting = true;
|
||||
var promises = [];
|
||||
|
||||
// For each context object in our controller...
|
||||
angular.forEach(vm.nodes, function(ctx) {
|
||||
// Try to delete it.
|
||||
ctx.state = 'removing';
|
||||
var promise = ctx.node.$remove(
|
||||
function() {
|
||||
vm.someDeleted = true;
|
||||
ctx.state = 'removed';
|
||||
},
|
||||
function(error) {
|
||||
ctx.state = 'error';
|
||||
ctx.error = error.data.error_message;
|
||||
}
|
||||
);
|
||||
promises.push(promise);
|
||||
});
|
||||
|
||||
// Wait for all the promises...
|
||||
$q.all(promises).then(
|
||||
function() {
|
||||
// If all are successful, just close.
|
||||
vm.deleting = false;
|
||||
if (vm.someDeleted) {
|
||||
$uibModalInstance.close();
|
||||
} else {
|
||||
$uibModalInstance.dismiss();
|
||||
}
|
||||
},
|
||||
function() {
|
||||
// Flip the deleting bit.
|
||||
vm.deleting = false;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Close this modal.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.close = function() {
|
||||
if (vm.someDeleted) {
|
||||
// Something was changed.
|
||||
$uibModalInstance.close();
|
||||
} else {
|
||||
// Nothing was changed.
|
||||
$uibModalInstance.dismiss();
|
||||
}
|
||||
};
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, LP
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This controller handles the popup that informs the user that we either do not know, or cannot
|
||||
* perform, the node action they've requested.
|
||||
*/
|
||||
angular.module('ironic').controller('UnknownActionModalController',
|
||||
function($scope, $uibModalInstance, actionName) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
vm.actionName = actionName;
|
||||
vm.close = function() {
|
||||
$uibModalInstance.dismiss();
|
||||
};
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This controller allows the creation of a new configuration.
|
||||
*/
|
||||
angular.module('ironic').controller('ConfigurationAddController',
|
||||
function($scope, $state, $location, $$configuration, $uibModalInstance, configuration) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
vm.configuration = configuration;
|
||||
vm.newConfiguration = {
|
||||
name: '',
|
||||
ironic: {
|
||||
apiRoot: ''
|
||||
}
|
||||
};
|
||||
|
||||
vm.location = {
|
||||
host: $location.host(),
|
||||
protocol: $location.protocol(),
|
||||
port: $location.port()
|
||||
};
|
||||
|
||||
vm.save = function() {
|
||||
vm.newConfiguration.id = vm.newConfiguration.name;
|
||||
$uibModalInstance.close(vm.newConfiguration);
|
||||
};
|
||||
|
||||
vm.close = function() {
|
||||
$uibModalInstance.dismiss();
|
||||
};
|
||||
});
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This controller allows the management of all the cloud configuration entries.
|
||||
*/
|
||||
angular.module('ironic').controller('ConfigurationController',
|
||||
function($state, $location, $$configuration, $$selectedConfiguration, $uibModal) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
vm.configurations = [];
|
||||
|
||||
vm.location = {
|
||||
host: $location.host(),
|
||||
protocol: $location.protocol(),
|
||||
port: $location.port()
|
||||
};
|
||||
|
||||
/**
|
||||
* Reload all configurations in this controller.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function reloadConfigurations () {
|
||||
vm.configurations = $$configuration.query({});
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a single configuration for the current application runtime.
|
||||
*
|
||||
* @param {{}} configuration The configuration to select.
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.select = function(configuration) {
|
||||
$$selectedConfiguration.set(configuration).$promise.then(
|
||||
function() {
|
||||
$state.go('root.ironic.nodes');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays the local configuration add modal.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.add = function() {
|
||||
// var deferred = $q.defer();
|
||||
$uibModal.open({
|
||||
templateUrl: 'view/ironic/config_add.html',
|
||||
controller: 'ConfigurationAddController as ctrl',
|
||||
backdrop: 'static',
|
||||
resolve: {
|
||||
configuration: function() {
|
||||
return $$configuration.query({}).$promise;
|
||||
}
|
||||
}
|
||||
}).result.then(
|
||||
function(newConfig) {
|
||||
$$configuration.create(newConfig).$promise.then(reloadConfigurations);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a configuration.
|
||||
* @param {{}} config The configuration to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.remove = function(config) {
|
||||
config.$remove().$promise.then(reloadConfigurations);
|
||||
};
|
||||
|
||||
reloadConfigurations();
|
||||
});
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Driver List for the Ironic UI.
|
||||
*/
|
||||
angular.module('ironic')
|
||||
.controller('DriverListController', function($scope, $q, IronicDriver) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
// Set up controller parameters
|
||||
vm.errorMessage = null;
|
||||
vm.drivers = [];
|
||||
|
||||
/**
|
||||
* Initialize the controller.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.init = function() {
|
||||
vm.loadDrivers();
|
||||
};
|
||||
|
||||
/**
|
||||
* Load the entire list of drivers.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.loadDrivers = function() {
|
||||
vm.errorMessage = null;
|
||||
vm.drivers = IronicDriver.query({}, function() {
|
||||
// Do nothing.
|
||||
}, function(error) {
|
||||
vm.errorMessage = error.data.error_message;
|
||||
vm.drivers = null;
|
||||
});
|
||||
};
|
||||
|
||||
vm.init();
|
||||
});
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This controller handles the enrollment of a new, single, node
|
||||
*/
|
||||
angular.module('ironic').controller('EnrollModalController',
|
||||
function($scope, $uibModalInstance, IronicDriver, IronicDriverProperties,
|
||||
IronicNode) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
vm.drivers = null;
|
||||
vm.errorMessage = null;
|
||||
vm.driverProperties = null;
|
||||
vm.node = null;
|
||||
|
||||
vm.loadDrivers = function() {
|
||||
vm.errorMessage = null;
|
||||
vm.drivers = IronicDriver.query({}, function() {
|
||||
// Do nothing on success.
|
||||
}, function(error) {
|
||||
vm.errorMessage = error.data.error_message;
|
||||
vm.drivers = null;
|
||||
});
|
||||
};
|
||||
|
||||
// Given a driver name, retrieve all the driver's options.
|
||||
vm.loadDriverProperties = function(driverName) {
|
||||
vm.driverProperties = null;
|
||||
vm.errorMessage = null;
|
||||
vm.node = {
|
||||
name: vm.node ? vm.node.name : '', // Preserve previously entered names.
|
||||
driver: driverName,
|
||||
driver_info: {}
|
||||
};
|
||||
|
||||
var params = {
|
||||
driver_name: driverName
|
||||
};
|
||||
|
||||
IronicDriverProperties.read(params).$promise.then(
|
||||
function(properties) {
|
||||
vm.driverProperties = properties;
|
||||
},
|
||||
function(error) {
|
||||
vm.errorMessage = error.data.error_message;
|
||||
});
|
||||
};
|
||||
|
||||
vm.enroll = function() {
|
||||
vm.errorMessage = null;
|
||||
IronicNode.create(vm.node,
|
||||
function(node) {
|
||||
$uibModalInstance.close(node);
|
||||
},
|
||||
function(error) {
|
||||
vm.errorMessage = error.data.error_message;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
vm.close = function() {
|
||||
$uibModalInstance.dismiss();
|
||||
};
|
||||
|
||||
// Initialize the drivers.
|
||||
vm.loadDrivers();
|
||||
});
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controller for our application header.
|
||||
*/
|
||||
angular.module('ironic').controller('HeaderController',
|
||||
function ($scope, $state, configurations, currentConfiguration, $$selectedConfiguration) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
vm.configurations = configurations;
|
||||
vm.currentConfiguration = currentConfiguration;
|
||||
|
||||
vm.switchCloud = function (cloudConfig) {
|
||||
$$selectedConfiguration.set(cloudConfig).$promise.then(
|
||||
function() {
|
||||
$state.reload();
|
||||
});
|
||||
};
|
||||
});
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controller which handles manipulation of individual nodes.
|
||||
*/
|
||||
angular.module('ironic').controller('NodeActionController',
|
||||
function($uibModal) {
|
||||
'use strict';
|
||||
|
||||
var vm = this;
|
||||
|
||||
// Set up controller parameters
|
||||
vm.errorMessage = null;
|
||||
|
||||
/**
|
||||
* Generic unknown action handler, here as a placeholder until we get actual actions built out.
|
||||
*
|
||||
* @param {String} actionName The name of the action to perform.
|
||||
* @param {[{}]} nodes An array of nodes on which to perform this action.
|
||||
* @returns {Promise} A promise that resolves when the user performs the action.
|
||||
*/
|
||||
function unknownActionHandler (actionName, nodes) {
|
||||
return $uibModal.open({
|
||||
templateUrl: 'view/ironic/action/unknown.html',
|
||||
controller: 'UnknownActionModalController as ctrl',
|
||||
resolve: {
|
||||
actionName: function() {
|
||||
return actionName;
|
||||
},
|
||||
nodes: function() {
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
}).result;
|
||||
}
|
||||
|
||||
vm.powerAction = unknownActionHandler;
|
||||
|
||||
/**
|
||||
* Provision action handler, delegates the provision action to the modal controller.
|
||||
*
|
||||
* @param {String} actionName The name of the action to perform.
|
||||
* @param {[{}]} nodes An array of nodes on which to perform this action.
|
||||
* @returns {Promise} A promise that resolves when the user performs the action.
|
||||
*/
|
||||
vm.provisionAction = function provisionActionHandler (actionName, nodes) {
|
||||
var modalParams = {
|
||||
templateUrl: 'view/ironic/action/provision.html',
|
||||
controller: 'ProvisionActionModalController as ctrl',
|
||||
resolve: {
|
||||
actionName: function() {
|
||||
return actionName;
|
||||
},
|
||||
nodeIds: function() {
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
switch (actionName) {
|
||||
case 'manage':
|
||||
case 'rebuild':
|
||||
case 'delete':
|
||||
case 'deploy':
|
||||
case 'fail':
|
||||
case 'abort':
|
||||
case 'clean':
|
||||
case 'inspect':
|
||||
case 'provide':
|
||||
default:
|
||||
modalParams.templateUrl = 'view/ironic/action/provision.html';
|
||||
}
|
||||
|
||||
return $uibModal.open(modalParams).result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete the node in this controller.
|
||||
*
|
||||
* @param {IronicNode} node The node instance to remove.
|
||||
* @return {Promise} A promise that will resolve true if the modal closed with some deletions.
|
||||
*/
|
||||
vm.remove = function(node) {
|
||||
|
||||
// Return the result of the modal.
|
||||
return $uibModal.open({
|
||||
templateUrl: 'view/ironic/action/remove_node.html',
|
||||
controller: 'RemoveNodeModalController as ctrl',
|
||||
backdrop: 'static',
|
||||
resolve: {
|
||||
nodes: function() {
|
||||
return [node];
|
||||
}
|
||||
}
|
||||
}).result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enroll a new node.
|
||||
*
|
||||
* @return {Promise} A promise that will resolve true if a node has been added.
|
||||
*/
|
||||
vm.enroll = function() {
|
||||
return $uibModal.open({
|
||||
templateUrl: 'view/ironic/enroll/index.html',
|
||||
controller: 'EnrollModalController as ctrl',
|
||||
backdrop: 'static'
|
||||
}).result;
|
||||
};
|
||||
});
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Node handling for the Ironic UI.
|
||||
*/
|
||||
angular.module('ironic').controller('NodeDetailController',
|
||||
function(nodeUuid, IronicNode) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
// Set up controller parameters
|
||||
vm.errorMessage = null;
|
||||
vm.node = null;
|
||||
|
||||
// Load the node.
|
||||
vm.node = IronicNode.read({
|
||||
uuid: nodeUuid
|
||||
}, angular.noop, function(error) {
|
||||
// Set the error message and clear the node promise.
|
||||
vm.errorMessage = error.data.error_message;
|
||||
vm.node = null;
|
||||
});
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Node driver handling for the Ironic UI.
|
||||
*/
|
||||
angular.module('ironic').controller('NodeDetailDriverController',
|
||||
function(nodeUuid, IronicNode, IronicDriver) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
// Set up controller parameters
|
||||
vm.errorMessage = null;
|
||||
vm.driver = null;
|
||||
|
||||
// Generic, shared error handler.
|
||||
function errorHandler (error) {
|
||||
// Set the error message and clear the port promise.
|
||||
vm.errorMessage = error.data.error_message;
|
||||
vm.driver = null;
|
||||
}
|
||||
|
||||
// Load the node.
|
||||
IronicNode.read({
|
||||
uuid: nodeUuid
|
||||
}, function(node) {
|
||||
vm.driver = IronicDriver.read({
|
||||
uuid: node.driver
|
||||
}, angular.noop, errorHandler);
|
||||
}, errorHandler);
|
||||
|
||||
});
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Node port handling for the Ironic UI.
|
||||
*/
|
||||
angular.module('ironic').controller('NodeDetailPortsController',
|
||||
function(nodeUuid, IronicPort) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
// Set up controller parameters
|
||||
vm.errorMessage = null;
|
||||
vm.ports = null;
|
||||
|
||||
// Load the node.
|
||||
vm.ports = IronicPort.query({
|
||||
node: nodeUuid
|
||||
}, angular.noop, function(error) {
|
||||
// Set the error message and clear the node promise.
|
||||
vm.errorMessage = error.data.error_message;
|
||||
vm.ports = null;
|
||||
});
|
||||
});
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Node handling for the Ironic UI.
|
||||
*/
|
||||
angular.module('ironic')
|
||||
.controller('NodeListController', function($scope, $q, IronicNode, IronicNodeProvisionTransition,
|
||||
IronicNodePowerTransition) {
|
||||
'use strict';
|
||||
var vm = this;
|
||||
|
||||
// Set up controller parameters
|
||||
vm.errorMessage = null;
|
||||
vm.nodes = [];
|
||||
vm.selectedNodes = [];
|
||||
vm.selectAll = false;
|
||||
vm.provisionTransitions = [];
|
||||
vm.powerTransitions = [];
|
||||
|
||||
/**
|
||||
* Initialize the controller.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.init = function() {
|
||||
vm.loadProvisionTransitions();
|
||||
vm.loadPowerTransitions();
|
||||
vm.loadNodes();
|
||||
};
|
||||
|
||||
// Load the node list.
|
||||
vm.loadNodes = function() {
|
||||
vm.errorMessage = null;
|
||||
vm.nodes = IronicNode.query({}, function() {
|
||||
vm.selectedNodes = [];
|
||||
vm.selectAll = false;
|
||||
}, function(error) {
|
||||
vm.errorMessage = error.data.error_message;
|
||||
vm.selectedNodes = [];
|
||||
vm.selectAll = false;
|
||||
vm.nodes = null;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Check the selected nodes anytime we suspect that the selectAll property may no longer be
|
||||
* valid.
|
||||
*/
|
||||
// using $watchCollection only works on non-scope items if the property provided is a
|
||||
// generator. Otherwise this syntax would have to be $scope.$watchCollection('foo'), and
|
||||
// we do not permit polluting the scope.
|
||||
var unwatchSelectedNodes = $scope.$watchCollection(function() {
|
||||
return vm.selectedNodes;
|
||||
}, function(newValue) {
|
||||
vm.selectAll = newValue.length === vm.nodes.length;
|
||||
});
|
||||
$scope.$on('$destroy', unwatchSelectedNodes);
|
||||
|
||||
/**
|
||||
* Select, or deselect, all nodes based on the value of the checkbox.
|
||||
*
|
||||
* @param {Boolean} selectAll Whether to select all.
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.toggleSelectAll = function(selectAll) {
|
||||
if (selectAll) {
|
||||
vm.selectedNodes = vm.nodes.map(function(item) {
|
||||
return angular.copy(item.uuid);
|
||||
});
|
||||
} else {
|
||||
vm.selectedNodes = [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load all valid user power transition names into the controller.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.loadPowerTransitions = function() {
|
||||
var transitionPromise = IronicNodePowerTransition.query({actor: 'user'}).$promise;
|
||||
|
||||
vm.powerTransitions = [];
|
||||
vm.powerTransitions.$resolved = false;
|
||||
vm.powerTransitions.$promise = transitionPromise
|
||||
.then(mapTransitionNames)
|
||||
.then(function(names) {
|
||||
angular.forEach(names, function(name) {
|
||||
vm.powerTransitions.push(name);
|
||||
});
|
||||
vm.powerTransitions.$resolved = true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Load all valid user provisioning transitions names into the controller.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
vm.loadProvisionTransitions = function() {
|
||||
var transitionPromise = IronicNodeProvisionTransition.query({actor: 'user'}).$promise;
|
||||
|
||||
vm.provisionTransitions = [];
|
||||
vm.provisionTransitions.$resolved = false;
|
||||
vm.provisionTransitions.$promise = transitionPromise
|
||||
.then(mapTransitionNames)
|
||||
.then(function(names) {
|
||||
angular.forEach(names, function(name) {
|
||||
vm.provisionTransitions.push(name);
|
||||
});
|
||||
vm.provisionTransitions.$resolved = true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* This helper method reduces the transition data format down to the actual action name that
|
||||
* can be performed on a node.
|
||||
*
|
||||
* @param {[{}]} transitions The list of resolved transitions.
|
||||
* @returns {Array} The reduced list of available transitions.
|
||||
*/
|
||||
function mapTransitionNames (transitions) {
|
||||
var reducedTransitions = [];
|
||||
transitions = transitions.map(function(item) {
|
||||
return item.event;
|
||||
});
|
||||
// deduplicate.
|
||||
|
||||
angular.forEach(transitions, function(name) {
|
||||
if (reducedTransitions.indexOf(name) === -1) {
|
||||
reducedTransitions.push(name);
|
||||
}
|
||||
});
|
||||
return reducedTransitions;
|
||||
}
|
||||
|
||||
vm.init();
|
||||
});
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Ironic Root Application.
|
||||
*
|
||||
* This module defines dependencies and root routes, but no actual
|
||||
* functionality.
|
||||
*/
|
||||
angular.module('ironic', ['ui.router', 'ui.bootstrap', 'ironic.util', 'ironic.api',
|
||||
'checklist-model'])
|
||||
.config(function($urlRouterProvider, $httpProvider, $stateProvider, $$configurationProvider) {
|
||||
'use strict';
|
||||
|
||||
// Default UI route
|
||||
$urlRouterProvider.otherwise('/ironic/nodes');
|
||||
|
||||
// Enable all of our configuration detection methods
|
||||
$$configurationProvider.$enableDefault(true);
|
||||
$$configurationProvider.$enableConfigLoad(true);
|
||||
$$configurationProvider.$enableLocalStorage(true);
|
||||
|
||||
// Ironic's root state, used to resolve global resources before
|
||||
// the application fully initializes.
|
||||
$stateProvider
|
||||
.state('root', {
|
||||
abstract: true,
|
||||
url: '',
|
||||
templateUrl: 'view/ironic/root.html'
|
||||
})
|
||||
.state('root.ironic', {
|
||||
abstract: true,
|
||||
url: '/ironic',
|
||||
views: {
|
||||
header: {
|
||||
templateUrl: 'view/ironic/header.html',
|
||||
controller: 'HeaderController as headerCtrl'
|
||||
},
|
||||
root: {
|
||||
templateUrl: 'view/ironic/ironic.html'
|
||||
}
|
||||
},
|
||||
resolve: {
|
||||
configurations: function($$configuration) {
|
||||
return $$configuration.query({}).$promise;
|
||||
},
|
||||
currentConfiguration: function($$selectedConfiguration, $q) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
var resource = $$selectedConfiguration.get();
|
||||
resource.$promise.then(
|
||||
function() {
|
||||
deferred.resolve(resource);
|
||||
},
|
||||
function() {
|
||||
deferred.reject('no_config');
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('root.ironic.nodes', {
|
||||
url: '/nodes',
|
||||
views: {
|
||||
'main@root.ironic': {
|
||||
templateUrl: 'view/ironic/node_list.html',
|
||||
controller: 'NodeListController as nodeListCtrl'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('root.ironic.nodes.detail', {
|
||||
abstract: true,
|
||||
url: '/:uuid',
|
||||
resolve: {
|
||||
nodeUuid: function($stateParams) {
|
||||
return $stateParams.uuid;
|
||||
}
|
||||
},
|
||||
views: {
|
||||
'main@root.ironic': {
|
||||
templateUrl: 'view/ironic/detail.html',
|
||||
controller: 'NodeDetailController as nodeCtrl'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('root.ironic.nodes.detail.node', {
|
||||
url: '/node',
|
||||
templateUrl: 'view/ironic/detail_node.html'
|
||||
})
|
||||
.state('root.ironic.nodes.detail.ports', {
|
||||
url: '/ports',
|
||||
templateUrl: 'view/ironic/detail_ports.html',
|
||||
controller: 'NodeDetailPortsController as portCtrl'
|
||||
})
|
||||
.state('root.ironic.nodes.detail.driver', {
|
||||
url: '/driver',
|
||||
templateUrl: 'view/ironic/detail_driver.html',
|
||||
controller: 'NodeDetailDriverController as driverCtrl'
|
||||
})
|
||||
.state('root.ironic.drivers', {
|
||||
url: '/drivers',
|
||||
views: {
|
||||
'main@root.ironic': {
|
||||
controller: 'DriverListController as driverListCtrl',
|
||||
templateUrl: 'view/ironic/driver_list.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('root.config', {
|
||||
url: '/config',
|
||||
views: {
|
||||
header: {
|
||||
templateUrl: 'view/ironic/config_header.html'
|
||||
},
|
||||
root: {
|
||||
templateUrl: 'view/ironic/config.html',
|
||||
controller: 'ConfigurationController as ctrl'
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.run(function($rootScope, $state) {
|
||||
'use strict';
|
||||
|
||||
var listener = $rootScope.$on('$stateChangeError',
|
||||
function(evt, toState, toParams, fromState, fromParams, reason) {
|
||||
if (reason === 'no_config') {
|
||||
$state.go('root.config');
|
||||
} else {
|
||||
$state.go('root.ironic.nodes');
|
||||
}
|
||||
});
|
||||
$rootScope.$on('$destroy', listener);
|
||||
});
|
@ -1,641 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This resource acts as a resource-like service that provides cloud api configurations
|
||||
* from various optional sources. First, you may hardcode a configuration using
|
||||
* $$configurationProvider.$addConfig. Secondly, you may use the default configuration
|
||||
* as registered by peer libraries using $$configurationProvider.$registerDefault.
|
||||
* Thirdly, it can load a configuration from ./config.json. Lastly, it provides
|
||||
* a simple CRUD interface by which a user may manipulate configurations that
|
||||
* are persisted in a browser's persistent storage.
|
||||
*
|
||||
* An example configuration file follows:
|
||||
*
|
||||
* [{
|
||||
* "name": "My Little Cloud",
|
||||
* "ironic": {
|
||||
* "apiRoot": "https://ironic.example.com:6385/"
|
||||
* },
|
||||
* "glance": {
|
||||
* "apiRoot": "https://glance.example.com:9292/"
|
||||
* }
|
||||
* }]
|
||||
*/
|
||||
angular.module('openstack').provider('$$configuration',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var merge = angular.merge;
|
||||
var forEach = angular.forEach;
|
||||
|
||||
/**
|
||||
* Promise variables, used to keep certain result sets in state.
|
||||
*/
|
||||
var deferAll, deferConfig, deferStatic, deferDefault, deferLocal;
|
||||
|
||||
/**
|
||||
* ID key for the persistent storage.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
var storageKey = '$$configuration';
|
||||
|
||||
/**
|
||||
* Internal flag: Is the default configuration enabled?
|
||||
*
|
||||
* @type {boolean} True if enabled, otherwise false.
|
||||
*/
|
||||
var enableDefault = false;
|
||||
|
||||
/**
|
||||
* Internal flag: Is configuration loading enabled?
|
||||
*
|
||||
* @type {boolean} True if enabled, otherwise false.
|
||||
*/
|
||||
var enableConfigLoad = false;
|
||||
|
||||
/**
|
||||
* Internal flag: Is persisting via localStorage enabled?
|
||||
*
|
||||
* @type {boolean} True if enabled, otherwise false.
|
||||
*/
|
||||
var enableLocalStorage = false;
|
||||
|
||||
/**
|
||||
* A list of static configurations, added to the provider.
|
||||
*
|
||||
* @type {Array}
|
||||
*/
|
||||
var staticConfigs = [];
|
||||
|
||||
/**
|
||||
* The default configuration instance.
|
||||
*
|
||||
* @type {{}}
|
||||
*/
|
||||
var defaultConfig = {
|
||||
id: 'default',
|
||||
name: 'Default Cloud',
|
||||
source: 'default'
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a new configuration to the provider. Use this method if you are providing your
|
||||
* own configuration loading mechanism during application initialization, such as a
|
||||
* hardcoded configuration. For a user-provided configuration, we recommend you use
|
||||
* $$configuration.create({}); instead.
|
||||
*
|
||||
* @param {*} configuration The configuration to add.
|
||||
* @returns {void}
|
||||
*/
|
||||
this.$addConfig = function(configuration) {
|
||||
configuration = angular.copy(configuration);
|
||||
configuration.source = 'static';
|
||||
staticConfigs.push(configuration);
|
||||
|
||||
// Reset associated promises
|
||||
if (deferStatic) {
|
||||
deferStatic = null;
|
||||
deferAll = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a service's default API URL. This allows peer libraries, such as glance-apilib
|
||||
* or ironic-apilib, to set a 'default' location for their API.
|
||||
*
|
||||
* @param {String} serviceName The name of the service to register. Example: 'ironic'.
|
||||
* @param {String} serviceUrl The root url of the API.
|
||||
* @returns {void}
|
||||
*/
|
||||
this.$registerDefault = function(serviceName, serviceUrl) {
|
||||
defaultConfig[serviceName] = {
|
||||
id: serviceName,
|
||||
apiRoot: serviceUrl
|
||||
};
|
||||
|
||||
if (deferDefault) {
|
||||
deferDefault = null;
|
||||
deferAll = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable, or disable, the default configuration mechanism. This mechanism assumes that peer
|
||||
* libraries, such as ironic-jslib or others, register an expected 'default' API root during
|
||||
* application initialization. These are provided under the 'default' id.
|
||||
*
|
||||
* This feature is disabled by default, enable it if you want your UI to permit automatic
|
||||
* creation of default configurations.
|
||||
*
|
||||
* @param {Boolean} enable Whether to enable the default configuration mechanism.
|
||||
* @returns {void}
|
||||
*/
|
||||
this.$enableDefault = function(enable) {
|
||||
enable = !!enable;
|
||||
// Only change things if things have changed
|
||||
if (enable !== enableDefault) {
|
||||
enableDefault = enable;
|
||||
|
||||
// Reset associated promises
|
||||
if (deferDefault) {
|
||||
deferDefault = null;
|
||||
deferAll = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable, or disable, the configuration loading mechanism. This mechanism attempts to load
|
||||
* a list of cloud configurations from a ./config.json file that lives adjacent to your user
|
||||
* interface. This feature is disabled by default, enable it if you want to configure your
|
||||
* cloud with a static config.json file.
|
||||
*
|
||||
* @param {Boolean} enable Whether to enable configuration loading.
|
||||
* @returns {void}
|
||||
*/
|
||||
this.$enableConfigLoad = function(enable) {
|
||||
enable = !!enable;
|
||||
// Only change things if things have changed
|
||||
if (enable !== enableConfigLoad) {
|
||||
enableConfigLoad = enable;
|
||||
|
||||
// Reset associated promises
|
||||
if (deferConfig) {
|
||||
deferConfig = null;
|
||||
deferAll = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable, or disable, loading cloud configuration from a browser's LocalStorage. This may
|
||||
* be used either to drive a user-provided configuration UI, or to read a configuration that
|
||||
* is shared between applications on the same domain.
|
||||
*
|
||||
* @param {Boolean} enable Whether to enable localStorage configurations.
|
||||
* @returns {void}
|
||||
*/
|
||||
this.$enableLocalStorage = function(enable) {
|
||||
enable = !!enable;
|
||||
// Only change things if things have changed
|
||||
if (enable !== enableLocalStorage) {
|
||||
enableLocalStorage = enable;
|
||||
|
||||
// Reset associated promises
|
||||
if (deferLocal) {
|
||||
deferLocal = null;
|
||||
deferAll = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a shallow copy of an object without persisting private methods.
|
||||
*
|
||||
* @param {*} src The source object.
|
||||
* @returns {*|{}} A copy of the object.
|
||||
*/
|
||||
function cleanCopy (src) {
|
||||
var dst = {};
|
||||
|
||||
for (var key in src) {
|
||||
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$')) {
|
||||
dst[key] = src[key];
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
this.$get = function($q, $$persistentStorage, $log, $http) {
|
||||
|
||||
/**
|
||||
* Store a list of data in local persistent storage.
|
||||
*
|
||||
* @param {*} list An array of config objects.
|
||||
* @returns {void}
|
||||
*/
|
||||
function saveLocal (list) {
|
||||
$$persistentStorage.set(storageKey, list);
|
||||
deferLocal = null;
|
||||
deferAll = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all configurations from the browser local storage, if enabled.
|
||||
*
|
||||
* @returns {promise} A resolving promise for local configuration objects.
|
||||
*/
|
||||
function resolveLocal () {
|
||||
if (!deferLocal) {
|
||||
deferLocal = $q.defer();
|
||||
if (enableLocalStorage) {
|
||||
var configs = $$persistentStorage.get(storageKey) || [];
|
||||
forEach(configs, function(config) {
|
||||
config.source = 'local';
|
||||
});
|
||||
deferLocal.resolve(configs);
|
||||
} else {
|
||||
deferLocal.resolve([]);
|
||||
}
|
||||
}
|
||||
return deferLocal.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all configurations from our various storage mechanisms.
|
||||
*
|
||||
* @returns {promise} A resolving promise for all configuration objects.
|
||||
*/
|
||||
function resolveAll () {
|
||||
// Only trigger this if the promise has been cleared.
|
||||
if (!deferAll) {
|
||||
deferAll = $q.defer();
|
||||
|
||||
$q.all({
|
||||
local: resolveLocal(),
|
||||
config: resolveConfig(),
|
||||
default: resolveDefault(),
|
||||
static: resolveStatic()
|
||||
}).then(function(results) {
|
||||
var list = [];
|
||||
forEach(results.local, function(config) {
|
||||
list.push(config);
|
||||
});
|
||||
forEach(results.config, function(config) {
|
||||
list.push(config);
|
||||
});
|
||||
forEach(results.default, function(config) {
|
||||
list.push(config);
|
||||
});
|
||||
forEach(results.static, function(config) {
|
||||
list.push(config);
|
||||
});
|
||||
deferAll.resolve(list);
|
||||
});
|
||||
}
|
||||
|
||||
return deferAll.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve configuration files from the ./config.json file.
|
||||
*
|
||||
* @returns {promise} A resolving promise for configFile configuration objects.
|
||||
*/
|
||||
function resolveConfig () {
|
||||
if (!deferConfig) {
|
||||
deferConfig = $q.defer();
|
||||
|
||||
if (!enableConfigLoad) {
|
||||
deferConfig.resolve([]);
|
||||
} else {
|
||||
$log.info('Attempting to load parameters from ./config.json');
|
||||
$http.get('./config.json').then(
|
||||
function(response) {
|
||||
|
||||
// The result must be an array.
|
||||
if (!angular.isArray(response.data)) {
|
||||
$log.warn('Content of ./config.json must be a valid JSON array.');
|
||||
response.data = [];
|
||||
}
|
||||
|
||||
forEach(response.data, function(config) {
|
||||
config.source = 'host';
|
||||
});
|
||||
|
||||
deferConfig.resolve(response.data);
|
||||
},
|
||||
function() {
|
||||
$log.warn('Cannot load ./config.json, using defaults.');
|
||||
deferConfig.resolve([]);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
return deferConfig.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the default configuration.
|
||||
*
|
||||
* @returns {promise} A resolving promise for default API calls.
|
||||
*/
|
||||
function resolveDefault () {
|
||||
if (!deferDefault) {
|
||||
deferDefault = $q.defer();
|
||||
if (enableDefault) {
|
||||
deferDefault.resolve([defaultConfig]);
|
||||
} else {
|
||||
deferDefault.resolve([]);
|
||||
}
|
||||
}
|
||||
|
||||
return deferDefault.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a list of configurations added to the services at config time.
|
||||
*
|
||||
* @returns {promise} A resolving promise of static configuration objects.
|
||||
*/
|
||||
function resolveStatic () {
|
||||
if (!deferStatic) {
|
||||
deferStatic = $q.defer();
|
||||
deferStatic.resolve(staticConfigs);
|
||||
}
|
||||
return deferStatic.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new local configuration. This requires that localStorage is enabled.
|
||||
*
|
||||
* @param {{}} newConfig The configuration to create.
|
||||
* @returns {{}} A resource for this new configuration object.
|
||||
*/
|
||||
function createConfig (newConfig) {
|
||||
// Create a result object
|
||||
var deferred = $q.defer();
|
||||
|
||||
// Decorate the result resource with necessary bits.
|
||||
newConfig = resourceify(newConfig, deferred.promise);
|
||||
|
||||
// We must have local storage enabled.
|
||||
if (!enableLocalStorage) {
|
||||
deferred.reject('local_storage_disabled');
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
// The user must provide an id property.
|
||||
if (!newConfig.id) {
|
||||
deferred.reject('no_id_provided');
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
// Resolve both all and local.
|
||||
$q.all({
|
||||
all: resolveAll(),
|
||||
local: resolveLocal()
|
||||
}).then(function(results) {
|
||||
// Check for duplicate ID's, reject if one exists.
|
||||
for (var i = 0; i < results.all.length; i++) {
|
||||
if (newConfig.id === results.all[i].id) {
|
||||
deferred.reject('duplicate_id');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new config.
|
||||
results.local.push(cleanCopy(newConfig));
|
||||
|
||||
// Stash the results
|
||||
saveLocal(results.local);
|
||||
|
||||
// resolve and exit
|
||||
deferred.resolve(newConfig);
|
||||
});
|
||||
|
||||
return newConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a new locally stored configuration.
|
||||
*
|
||||
* @param {{}} config The configuration object to update.
|
||||
* @returns {{}} The updated configuration.
|
||||
*/
|
||||
function updateConfig (config) {
|
||||
var deferred = $q.defer();
|
||||
config = resourceify(config, deferred.promise);
|
||||
|
||||
// We must have local storage enabled.
|
||||
if (!enableLocalStorage) {
|
||||
deferred.reject('local_storage_disabled');
|
||||
return config;
|
||||
}
|
||||
|
||||
// Load local configurations
|
||||
resolveLocal().then(
|
||||
function(results) {
|
||||
// Try to find the matching id.
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var storedConfig = results[i];
|
||||
if (config.id === storedConfig.id) {
|
||||
// Merge the new values onto the stored config.
|
||||
storedConfig = merge(storedConfig, cleanCopy(config));
|
||||
|
||||
// Stash the results
|
||||
saveLocal(results);
|
||||
|
||||
// Resolve the promise
|
||||
deferred.resolve(config);
|
||||
return;
|
||||
}
|
||||
}
|
||||
deferred.reject('not_found');
|
||||
});
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a configuration by ID.
|
||||
*
|
||||
* @param {{}} config The configuration object to resolve.
|
||||
* @returns {{}} The configuration resource.
|
||||
*/
|
||||
function readConfig (config) {
|
||||
var deferred = $q.defer();
|
||||
config = resourceify(config, deferred.promise);
|
||||
|
||||
// Force the user to provide an ID.
|
||||
if (!config.id) {
|
||||
deferred.reject('no_id_provided');
|
||||
return config;
|
||||
}
|
||||
|
||||
// Load everything, then...
|
||||
resolveAll().then(
|
||||
function(results) {
|
||||
// Try to find the matching id.
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var storedConfig = results[i];
|
||||
if (config.id === storedConfig.id) {
|
||||
// Merge values onto the config.
|
||||
merge(config, cleanCopy(storedConfig));
|
||||
deferred.resolve(config);
|
||||
return;
|
||||
}
|
||||
}
|
||||
deferred.reject('not_found');
|
||||
});
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a locally stored configuration from the cache.
|
||||
*
|
||||
* @param {{}} config The configuration object to remove.
|
||||
* @returns {{}} The configuration object, with appropriate promises.
|
||||
*/
|
||||
function removeConfig (config) {
|
||||
var deferred = $q.defer();
|
||||
config = resourceify(config, deferred.promise);
|
||||
|
||||
// We must have local storage enabled.
|
||||
if (!enableLocalStorage) {
|
||||
deferred.reject('local_storage_disabled');
|
||||
return config;
|
||||
}
|
||||
|
||||
// Load local configurations
|
||||
resolveLocal().then(
|
||||
function(results) {
|
||||
// Try to find the matching id.
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var storedConfig = results[i];
|
||||
if (storedConfig.id === config.id) {
|
||||
|
||||
// Remove the config from local storage.
|
||||
results.splice(i, 1);
|
||||
|
||||
// Stash the results
|
||||
saveLocal(results);
|
||||
|
||||
// Resolve the promise and exit
|
||||
deferred.resolve(config);
|
||||
return;
|
||||
}
|
||||
}
|
||||
deferred.reject('not_found');
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method decorates a raw resource with manipulation methods like $delete, $update,
|
||||
* etc. These convenience methods permit individual instance manipulation.
|
||||
*
|
||||
* @param {{}} instance The instance to decorate.
|
||||
* @param {Promise} promise The promise to apply.
|
||||
*
|
||||
* @returns {{}} A clone of the instance, with $ methods added.
|
||||
*/
|
||||
function resourceify (instance, promise) {
|
||||
instance.$promise = promise;
|
||||
|
||||
// Set the initial resolved, and keep it up to date.
|
||||
instance.$resolved = false;
|
||||
instance.$promise.then(function() {
|
||||
instance.$resolved = true;
|
||||
}, function() {
|
||||
instance.$resolved = true;
|
||||
});
|
||||
|
||||
instance.$remove = function() {
|
||||
return removeConfig(instance);
|
||||
};
|
||||
instance.$create = function() {
|
||||
return createConfig(instance);
|
||||
};
|
||||
instance.$update = function() {
|
||||
return updateConfig(instance);
|
||||
};
|
||||
instance.$read = function() {
|
||||
return readConfig(instance);
|
||||
};
|
||||
return instance;
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get a list of all configurations.
|
||||
*
|
||||
* @returns {{}} A list of configurations.
|
||||
*/
|
||||
query: function() {
|
||||
// Start with the promise
|
||||
var listDeferred = $q.defer();
|
||||
|
||||
// Build a resource
|
||||
var list = resourceify([], listDeferred.promise);
|
||||
|
||||
// Resolve all the resources, then resolve the list promise.
|
||||
resolveAll().then(
|
||||
function(results) {
|
||||
// Load cloned configs into the result array.
|
||||
forEach(results, function(config) {
|
||||
var rDeferred = $q.defer();
|
||||
var resource = resourceify(cleanCopy(config), rDeferred.promise);
|
||||
listDeferred.promise.then(
|
||||
function() {
|
||||
rDeferred.resolve(resource);
|
||||
});
|
||||
list.push(resource);
|
||||
});
|
||||
|
||||
listDeferred.resolve(list);
|
||||
});
|
||||
return list;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new configuration.
|
||||
*
|
||||
* @param {{}} configuration The configuration to add.
|
||||
* @returns {{}} A resource for this new configuration object.
|
||||
*/
|
||||
create: function(configuration) {
|
||||
return createConfig(configuration);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a specific configuration by ID.
|
||||
*
|
||||
* @param {String} id The configuration ID/Name to load.
|
||||
* @returns {{}} The configuration resource.
|
||||
*/
|
||||
read: function(id) {
|
||||
return readConfig({id: id});
|
||||
},
|
||||
|
||||
/**
|
||||
* Update a configuration in the loaded cache. This will error if the user attempts to
|
||||
* update a configuration from a static provider - say the config file.
|
||||
*
|
||||
* @param {{}} configuration The configuration object to update.
|
||||
* @returns {{}} The updated configuration.
|
||||
*/
|
||||
update: function(configuration) {
|
||||
return updateConfig(configuration);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a particular configuration from the configuration list.
|
||||
*
|
||||
* @param {String} id The ID to remove.
|
||||
* @returns {{}} The configuration object, with appropriate promises.
|
||||
*/
|
||||
remove: function(id) {
|
||||
return removeConfig({id: id});
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The $$dummyResource component is a placeholder, which simulates the ngResource API. It does
|
||||
* nothing on its own, and should only be used in situations where a more appropriate resource
|
||||
* could not be resolved.
|
||||
*/
|
||||
angular.module('openstack').factory('$$dummyResource',
|
||||
function($q) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Apply common resource-like behavior, and instantly reject the promise.
|
||||
*
|
||||
* @param {*} resource An object to decorate.
|
||||
* @returns {*} The decorated instance.
|
||||
*/
|
||||
function resourceify (resource) {
|
||||
var deferred = $q.defer();
|
||||
resource.$promise = deferred.promise;
|
||||
resource.$resolved = false;
|
||||
|
||||
resource.$promise.finally(function() {
|
||||
resource.$resolved = true;
|
||||
});
|
||||
deferred.reject('dummy_resource');
|
||||
return resource;
|
||||
}
|
||||
|
||||
return {
|
||||
query: function() {
|
||||
return resourceify([]);
|
||||
},
|
||||
create: function() {
|
||||
return resourceify({});
|
||||
},
|
||||
read: function() {
|
||||
return resourceify({});
|
||||
},
|
||||
update: function() {
|
||||
return resourceify({});
|
||||
},
|
||||
remove: function() {
|
||||
return resourceify({});
|
||||
}
|
||||
};
|
||||
});
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An application-wide static constant that contains error code constants.
|
||||
* Different modules and components may dynamically add error codes that serve
|
||||
* their own needs.
|
||||
*/
|
||||
angular.module('openstack').constant('$$errorCode', {});
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OpenStack specific configuration discovery.
|
||||
*/
|
||||
angular.module('openstack', ['ngCookies', 'ngResource']);
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The resource cache acts as a centralized location where different services' resource
|
||||
* instances may be stored. It plays a central role in multi-cloud environments, as a resource
|
||||
* abstraction - say IronicNode - can create and cache the actual ngResource instances for N>1
|
||||
* configured ironic endpoints.
|
||||
*
|
||||
* In order to maintain flexibility, it does not build resources, it only accepts preconstructed
|
||||
* instances. It is strongly recommended that you store your resource instances using the root
|
||||
* URI of the API to which your instance is talking, so that 'https://somecloud.com:6385/v1/nodes'
|
||||
* will be stored separately from 'https://someothercloud.com:6385/v1/nodes'.
|
||||
*/
|
||||
angular.module('openstack').factory('$$resourceCache',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Cache of all the resource instances.
|
||||
*
|
||||
* @type {{}}
|
||||
*/
|
||||
var resourceCache = {};
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Store a resource instance in the cache.
|
||||
*
|
||||
* @param {String} uri The root uri of the resource.
|
||||
* @param {*} resource The resource to store.
|
||||
* @return {*} The stored resource.
|
||||
*/
|
||||
set: function(uri, resource) {
|
||||
resourceCache[uri] = resource;
|
||||
return resource;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a resource instance from the cache.
|
||||
*
|
||||
* @param {String} uri The uri of the resource to retrieve.
|
||||
* @return {*|undefined} The resource, or undefined.
|
||||
*/
|
||||
get: function(uri) {
|
||||
if (resourceCache[uri]) {
|
||||
return resourceCache[uri];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether or not a resource is in the cache.
|
||||
*
|
||||
* @param {String} uri The uri of the resource to check.
|
||||
* @return {true|false} Whether this resource has already been cached.
|
||||
*/
|
||||
has: function(uri) {
|
||||
return resourceCache.hasOwnProperty(uri);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a specific resource from the cache.
|
||||
*
|
||||
* @param {String} uri The uri of the resource to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
remove: function(uri) {
|
||||
if (resourceCache.hasOwnProperty(uri)) {
|
||||
delete resourceCache[uri];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return all the uri keys currently registered.
|
||||
*
|
||||
* @returns {Array} An array of all registered uri keys.
|
||||
*/
|
||||
keys: function() {
|
||||
var keys = [];
|
||||
/*eslint-disable guard-for-in*/
|
||||
for (var key in resourceCache) {
|
||||
keys.push(key);
|
||||
}
|
||||
/*eslint-enable guard-for-in*/
|
||||
return keys;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove everything from the cache.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
clearAll: function() {
|
||||
var keys = this.keys();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
delete resourceCache[keys[i]];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the number of resources in the cache.
|
||||
*
|
||||
* @returns {number} The number of resources cached.
|
||||
*/
|
||||
length: function() {
|
||||
return this.keys().length;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The $$selectedConfiguration service provides a way of easily accessing, and modifying,
|
||||
* the current active cloud configuration used in an application. It will resolve configurations
|
||||
* from the $$configuration provider, which provides multiple configuration loading mechanisms.
|
||||
*/
|
||||
angular.module('openstack').service('$$selectedConfiguration',
|
||||
function($$persistentStorage, $$configuration) {
|
||||
'use strict';
|
||||
|
||||
var storageKey = '$$selectedConfiguration';
|
||||
var currentConfiguration, selectingConfiguration;
|
||||
|
||||
return {
|
||||
/**
|
||||
* Retrieve the currently active configuration. If there is not configuration selected,
|
||||
* this resources' $promise will fail.
|
||||
*
|
||||
* @returns {*} The configuration.
|
||||
*/
|
||||
get: function() {
|
||||
// If we're in the process of selecting one, return that.
|
||||
if (selectingConfiguration) {
|
||||
return selectingConfiguration;
|
||||
}
|
||||
|
||||
// If we have a current one, return that.
|
||||
if (currentConfiguration) {
|
||||
return currentConfiguration;
|
||||
}
|
||||
|
||||
// Return the 'selected' configuration by setting it.
|
||||
return this.set($$persistentStorage.get(storageKey));
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a particular configuration as active. The selection will only be persisted to
|
||||
* LocalStorage if the selected configuration is valid and available in the
|
||||
* $$configuration list.
|
||||
*
|
||||
* @param {String} configurationId The configuration to activate.
|
||||
* @returns {*} The active configuration.
|
||||
*/
|
||||
set: function(configurationId) {
|
||||
// Normalize input
|
||||
|
||||
if (angular.isObject(configurationId)) {
|
||||
configurationId = configurationId.id || null;
|
||||
}
|
||||
|
||||
// If we're in a resolved state and the ID's match...
|
||||
if (currentConfiguration && currentConfiguration.id === configurationId) {
|
||||
return currentConfiguration;
|
||||
}
|
||||
|
||||
// If we're in a resolving state and the ID's match...
|
||||
if (selectingConfiguration && selectingConfiguration.id === configurationId) {
|
||||
return selectingConfiguration;
|
||||
}
|
||||
|
||||
// If we've reached this point, we need to resolve a new configuration.
|
||||
selectingConfiguration = $$configuration.read(configurationId);
|
||||
selectingConfiguration.$promise.then(
|
||||
function() {
|
||||
// Only set this if the promise resolves sucessfully.
|
||||
$$persistentStorage.set(storageKey, configurationId);
|
||||
currentConfiguration = selectingConfiguration;
|
||||
},
|
||||
function() {
|
||||
// if setting fails, clear the existing storage key if it matches. This case occurs
|
||||
// if the system initializes with a config ID that has been invalidated since the
|
||||
// previous run.
|
||||
if ($$persistentStorage.get(storageKey) === configurationId) {
|
||||
$$persistentStorage.remove(storageKey);
|
||||
}
|
||||
}
|
||||
).finally(
|
||||
function() {
|
||||
// clear the selecting configuration
|
||||
selectingConfiguration = null;
|
||||
});
|
||||
|
||||
return selectingConfiguration;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file provides an implementation of the storage API, backed by cookies.
|
||||
* This particular implementation is not intelligent: It will access the
|
||||
* cookie for this domain, as configured by the $cookieProvider, and will
|
||||
* grant access to all values stored this way.
|
||||
*/
|
||||
angular.module('openstack').factory('$$cookieStorage',
|
||||
function($cookies) {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Is this storage type supported?
|
||||
*
|
||||
* @returns {boolean} True if it is supported, otherwise false.
|
||||
*/
|
||||
isSupported: function() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a value to the provided key in memory storage. If the
|
||||
* value already exists it will be overwritten.
|
||||
*
|
||||
* @param {String} key The key to store the value at.
|
||||
* @param {*} value The value to store.
|
||||
* @return {*} The stored value.
|
||||
*/
|
||||
set: function(key, value) {
|
||||
$cookies.put(key, angular.toJson(value));
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a value from this storage provider.
|
||||
*
|
||||
* @param {String} key The key to retrieve.
|
||||
* @return {*|undefined} The value, or undefined if it is not set.
|
||||
*/
|
||||
get: function(key) {
|
||||
var result = angular.fromJson($cookies.get(key));
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a specific value from the storage provider.
|
||||
*
|
||||
* @param {String} key The key to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
remove: function(key) {
|
||||
$cookies.remove(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return all the keys currently registered.
|
||||
*
|
||||
* @returns {Array} An array of all registered keys.
|
||||
*/
|
||||
keys: function() {
|
||||
var all = $cookies.getAll();
|
||||
var keys = [];
|
||||
/*eslint-disable guard-for-in*/
|
||||
for (var key in all) {
|
||||
keys.push(key);
|
||||
}
|
||||
/*eslint-enable guard-for-in*/
|
||||
return keys;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove everything from the memory storage mechanism.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
clearAll: function() {
|
||||
var all = $cookies.getAll();
|
||||
/*eslint-disable guard-for-in*/
|
||||
for (var key in all) {
|
||||
$cookies.remove(key);
|
||||
}
|
||||
/*eslint-enable guard-for-in*/
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the size of the current memory storage.
|
||||
*
|
||||
* @returns {number} The number of keys in storage.
|
||||
*/
|
||||
length: function() {
|
||||
return this.keys().length;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A $$localStorage service behind a common API. If localStorage is not
|
||||
* supported, this will log a warning to the console. If you want a provider
|
||||
* that gracefully degrades, use $$persistentStorage.
|
||||
*/
|
||||
angular.module('openstack').factory('$$localStorage',
|
||||
function($window, $log) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Detect whether localStorage is supported, and make sure we can write
|
||||
* to it.
|
||||
*/
|
||||
var isSupported = (function() {
|
||||
|
||||
// Does it exist?
|
||||
if (!$window.localStorage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Can we write to it?
|
||||
var testKey = '__' + Math.round(Math.random() * 1e7);
|
||||
try {
|
||||
$window.localStorage.setItem(testKey, '');
|
||||
$window.localStorage.removeItem(testKey);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Is this storage type supported?
|
||||
*
|
||||
* @returns {boolean} True if it is supported, otherwise false.
|
||||
*/
|
||||
isSupported: function() {
|
||||
return isSupported;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a value of the provided key. If the
|
||||
* value already exists it will be overwritten.
|
||||
*
|
||||
* @param {String} key The key to store the value at.
|
||||
* @param {*} value The value to store.
|
||||
* @return {*} The stored value.
|
||||
*/
|
||||
set: function(key, value) {
|
||||
if (isSupported) {
|
||||
$window.localStorage.setItem(key, angular.toJson(value));
|
||||
return value;
|
||||
}
|
||||
$log.warn('$$localStorage not supported');
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a value from this storage provider.
|
||||
*
|
||||
* @param {String} key The key to retrieve.
|
||||
* @return {*|undefined} The value, or undefined if it is not set.
|
||||
*/
|
||||
get: function(key) {
|
||||
if (isSupported) {
|
||||
var result = angular.fromJson($window.localStorage.getItem(key));
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
$log.warn('$$localStorage not supported');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a specific value from the storage provider.
|
||||
*
|
||||
* @param {String} key The key to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
remove: function(key) {
|
||||
if (isSupported) {
|
||||
return $window.localStorage.removeItem(key);
|
||||
}
|
||||
$log.warn('$$localStorage not supported');
|
||||
},
|
||||
|
||||
/**
|
||||
* Return all the keys currently registered.
|
||||
*
|
||||
* @returns {Array} An array of all registered keys.
|
||||
*/
|
||||
keys: function() {
|
||||
if (isSupported) {
|
||||
var keys = [];
|
||||
for (var i = 0; i < $window.localStorage.length; i++) {
|
||||
keys.push($window.localStorage.key(i));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
$log.warn('$$localStorage not supported');
|
||||
return [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove everything from the memory storage mechanism.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
clearAll: function() {
|
||||
if (isSupported) {
|
||||
var keys = this.keys();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.remove(keys[i]);
|
||||
}
|
||||
}
|
||||
$log.warn('$$localStorage not supported');
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the size of the current memory storage.
|
||||
*
|
||||
* @returns {number} The number of keys in storage.
|
||||
*/
|
||||
length: function() {
|
||||
if (isSupported) {
|
||||
return $window.localStorage.length;
|
||||
}
|
||||
$log.warn('$$localStorage not supported');
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This provides a memory-based key/value storage mechanism. It's provided as
|
||||
* a fallback option for all other storage mechanisms, to prevent unexpected
|
||||
* runtime failures.
|
||||
*/
|
||||
angular.module('openstack').factory('$$memoryStorage',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var memoryStorage = {};
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Is this storage type supported?
|
||||
*
|
||||
* @returns {boolean} True if it is supported, otherwise false.
|
||||
*/
|
||||
isSupported: function() {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a value to the provided key in memory storage. If the
|
||||
* value already exists it will be overwritten.
|
||||
*
|
||||
* @param {String} key The key to store the value at.
|
||||
* @param {*} value The value to store.
|
||||
* @return {*} The stored value.
|
||||
*/
|
||||
set: function(key, value) {
|
||||
memoryStorage[key] = value;
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a value from this storage provider.
|
||||
*
|
||||
* @param {String} key The key to retrieve.
|
||||
* @return {*|undefined} The value, or undefined if it is not set.
|
||||
*/
|
||||
get: function(key) {
|
||||
if (memoryStorage.hasOwnProperty(key)) {
|
||||
return memoryStorage[key];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a specific value from the storage provider.
|
||||
*
|
||||
* @param {String} key The key to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
remove: function(key) {
|
||||
delete memoryStorage[key];
|
||||
},
|
||||
|
||||
/**
|
||||
* Return all the keys currently registered.
|
||||
*
|
||||
* @returns {Array} An array of all registered keys.
|
||||
*/
|
||||
keys: function() {
|
||||
var keys = [];
|
||||
/*eslint-disable guard-for-in*/
|
||||
for (var key in memoryStorage) {
|
||||
keys.push(key);
|
||||
}
|
||||
/*eslint-enable guard-for-in*/
|
||||
return keys;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove everything from the memory storage mechanism.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
clearAll: function() {
|
||||
var keys = [];
|
||||
/*eslint-disable guard-for-in*/
|
||||
for (var key in memoryStorage) {
|
||||
keys.push(key);
|
||||
}
|
||||
/*eslint-enable guard-for-in*/
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
delete memoryStorage[keys[i]];
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the size of the current memory storage.
|
||||
*
|
||||
* @returns {number} The number of keys in storage.
|
||||
*/
|
||||
length: function() {
|
||||
return this.keys().length;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A convenience component that automatically selects the most secure, and most
|
||||
* persistent, storage mechanism available in the current runtime. This does
|
||||
* not include sessionStorage, which must be used independently.
|
||||
*/
|
||||
angular.module('openstack').factory('$$persistentStorage',
|
||||
function($log, $$cookieStorage, $$memoryStorage, $$localStorage) {
|
||||
'use strict';
|
||||
|
||||
// Check for local storage.
|
||||
if ($$localStorage.isSupported()) {
|
||||
return $$localStorage;
|
||||
}
|
||||
|
||||
// Check for cookie storage.
|
||||
if ($$cookieStorage.isSupported()) {
|
||||
return $$cookieStorage;
|
||||
}
|
||||
|
||||
$log.warn('Warning: No persistent storage mechanism supported, all storage will be transient.');
|
||||
return $$memoryStorage;
|
||||
});
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A $$sessionStorage service behind a common API. If sessionStorage is not
|
||||
* supported, this will log a warning to the console. If you want a provider
|
||||
* that gracefully degrades, use $$persistentStorage.
|
||||
*/
|
||||
angular.module('openstack').factory('$$sessionStorage',
|
||||
function($window, $log) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Detect whether sessionStorage is supported, and make sure we can
|
||||
* write to it.
|
||||
*/
|
||||
var isSupported = (function() {
|
||||
|
||||
// Does it exist?
|
||||
if (!$window.sessionStorage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Can we write to it?
|
||||
var testKey = '__' + Math.round(Math.random() * 1e7);
|
||||
try {
|
||||
$window.sessionStorage.setItem(testKey, '');
|
||||
$window.sessionStorage.removeItem(testKey);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* Is this storage type supported?
|
||||
*
|
||||
* @returns {boolean} True if it is supported, otherwise false.
|
||||
*/
|
||||
isSupported: function() {
|
||||
return isSupported;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a value of the provided key. If the
|
||||
* value already exists it will be overwritten.
|
||||
*
|
||||
* @param {String} key The key to store the value at.
|
||||
* @param {*} value The value to store.
|
||||
* @return {*} The stored value.
|
||||
*/
|
||||
set: function(key, value) {
|
||||
if (isSupported) {
|
||||
$window.sessionStorage.setItem(key, angular.toJson(value));
|
||||
return value;
|
||||
}
|
||||
$log.warn('$$sessionStorage not supported');
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve a value from this storage provider.
|
||||
*
|
||||
* @param {String} key The key to retrieve.
|
||||
* @return {*|undefined} The value, or undefined if it is not set.
|
||||
*/
|
||||
get: function(key) {
|
||||
if (isSupported) {
|
||||
var result = angular.fromJson($window.sessionStorage.getItem(key));
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
$log.warn('$$sessionStorage not supported');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a specific value from the storage provider.
|
||||
*
|
||||
* @param {String} key The key to remove.
|
||||
* @returns {void}
|
||||
*/
|
||||
remove: function(key) {
|
||||
if (isSupported) {
|
||||
return $window.sessionStorage.removeItem(key);
|
||||
}
|
||||
$log.warn('$$sessionStorage not supported');
|
||||
},
|
||||
|
||||
/**
|
||||
* Return all the keys currently registered.
|
||||
*
|
||||
* @returns {Array} An array of all registered keys.
|
||||
*/
|
||||
keys: function() {
|
||||
if (isSupported) {
|
||||
var keys = [];
|
||||
for (var i = 0; i < $window.sessionStorage.length; i++) {
|
||||
keys.push($window.sessionStorage.key(i));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
$log.warn('$$sessionStorage not supported');
|
||||
return [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove everything from the memory storage mechanism.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
clearAll: function() {
|
||||
if (isSupported) {
|
||||
var keys = this.keys();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.remove(keys[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
$log.warn('$$sessionStorage not supported');
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the size of the current memory storage.
|
||||
*
|
||||
* @returns {number} The number of keys in storage.
|
||||
*/
|
||||
length: function() {
|
||||
if (isSupported) {
|
||||
return $window.sessionStorage.length;
|
||||
}
|
||||
$log.warn('$$sessionStorage not supported');
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
});
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This directive requires ui-router, as it listens for events dispatched as
|
||||
* a user navigates through the application, and adds the 'active' class to
|
||||
* the bound element if the user's selected path matches the one configured.
|
||||
*/
|
||||
angular.module('ironic.util').directive('activePath',
|
||||
function ($location, $rootScope) {
|
||||
'use strict';
|
||||
|
||||
return {
|
||||
link: function ($scope, element, attrs) {
|
||||
var activePath = attrs.activePath;
|
||||
|
||||
function setActivePath () {
|
||||
var path = $location.path();
|
||||
var isMatchedPath = path.match(activePath) !== null;
|
||||
|
||||
element.toggleClass('active', isMatchedPath);
|
||||
}
|
||||
|
||||
// This is angularjs magic, the return method from any $on
|
||||
// binding will return a function that will disconnect
|
||||
// that binding.
|
||||
var disconnectBinding =
|
||||
$rootScope.$on('$stateChangeSuccess', setActivePath);
|
||||
$scope.$on('$destroy', disconnectBinding);
|
||||
|
||||
// INIT
|
||||
setActivePath();
|
||||
}
|
||||
};
|
||||
});
|
@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
angular.module('ironic.util').filter('capitalize',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
return function(input) {
|
||||
input = input || '';
|
||||
return input.replace(/([^\W_]+[^\s-]*) */g, function(txt) {
|
||||
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
|
||||
});
|
||||
};
|
||||
});
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* UI Utilities used by the ironic client.
|
||||
*/
|
||||
angular.module('ironic.util', []);
|
@ -1,58 +0,0 @@
|
||||
<div class="modal-header">
|
||||
<button type="button"
|
||||
class="close"
|
||||
ng-disabled="!ctrl.nodes.$resolved || ctrl.updating"
|
||||
ng-click="ctrl.close()">×</button>
|
||||
<h3 class="panel-title">{{ctrl.actionName | capitalize }} Node</h3>
|
||||
</div>
|
||||
<div class="modal-body" ng-if="!ctrl.nodes.$resolved">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<p class="text-center text-muted">
|
||||
<i class="fa fa-spin fa-refresh"></i> Loading Details...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body" ng-if="ctrl.nodes.$resolved && ctrl.nodes.length > 0">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<p>Ironic will {{ctrl.actionName}} the following nodes.</p>
|
||||
<table class="table table-condensed table-striped">
|
||||
<tr>
|
||||
<th>Node ID</th>
|
||||
<th>Node Name</th>
|
||||
<th>Node State</th>
|
||||
</tr>
|
||||
<tr ng-repeat="ctx in ctrl.nodes">
|
||||
<td>{{ctx.node.uuid}}</td>
|
||||
<td>{{ctx.node.name || 'None'}}</td>
|
||||
<td ng-switch="ctx.state">
|
||||
<div ng-switch-when="updating" class="text-warning">
|
||||
<i class="fa fa-spin fa-refresh"></i> Updating...
|
||||
</div>
|
||||
<div ng-switch-when="complete" class="text-muted">
|
||||
Complete
|
||||
</div>
|
||||
<div ng-switch-when="error" class="text-danger">
|
||||
<i class="fa fa-exclamation-triangle"></i> Error
|
||||
</div>
|
||||
<div ng-switch-default>
|
||||
{{ctx.node.provision_state | capitalize}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer ng-scope">
|
||||
<button class="btn btn-danger" ng-click="ctrl.apply()"
|
||||
ng-disabled="!ctrl.nodes.$resolved || ctrl.updating">
|
||||
{{ ctrl.actionName | capitalize }}
|
||||
</button>
|
||||
<button class="btn btn-default" ng-click="ctrl.close()"
|
||||
ng-disabled="!ctrl.nodes.$resolved || ctrl.updating">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
@ -1,52 +0,0 @@
|
||||
<div class="modal-header">
|
||||
<button type="button"
|
||||
class="close"
|
||||
ng-disabled="ctrl.deleting"
|
||||
ng-click="ctrl.close()">×</button>
|
||||
<h3 class="panel-title">Remove Nodes</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="alert alert-danger">
|
||||
<span class="fa fa-exclamation-circle"></span>
|
||||
You are about to remove the following nodes.
|
||||
</div>
|
||||
<dl class="dl-horizontal">
|
||||
<dt ng-repeat-start="e in ctrl.nodes"
|
||||
ng-switch="e.state">
|
||||
<div ng-switch-when="removing" class="text-warning">
|
||||
<i class="fa fa-spin fa-refresh"></i> Removing...
|
||||
</div>
|
||||
<div ng-switch-when="removed" class="text-muted">
|
||||
Removed:
|
||||
</div>
|
||||
<div ng-switch-when="error" class="text-danger">
|
||||
<i class="fa fa-exclamation-triangle"></i> Error:
|
||||
</div>
|
||||
<div ng-switch-default>
|
||||
Node:
|
||||
</div>
|
||||
</dt>
|
||||
<dd ng-repeat-end>
|
||||
{{e.node.uuid}}
|
||||
<span ng-if="e.node.name">({{e.node.name}})</span>
|
||||
<span class="text-danger" ng-if="e.error"><br/>
|
||||
{{e.error.faultcode}}: {{e.error.faultstring}}
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
This will remove all knowledge of the nodes from the system. It will not modify the nodes,
|
||||
however you will lose the ability to manage them via this application.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer ng-scope">
|
||||
<p class="text-danger" ng-if="!!ctrl.error_message">{{ctrl.error_message}}</p>
|
||||
<button class="btn btn-danger" ng-click="ctrl.remove()"
|
||||
ng-disabled="ctrl.deleting">Remove
|
||||
</button>
|
||||
<button class="btn btn-default" ng-click="ctrl.close()"
|
||||
ng-disabled="ctrl.deleting">Cancel
|
||||
</button>
|
||||
</div>
|
@ -1,16 +0,0 @@
|
||||
<div class="modal-header">
|
||||
<button type="button"
|
||||
class="close"
|
||||
ng-click="ctrl.close()">×</button>
|
||||
<h3 class="panel-title">Unsupported Action</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<p>The action "{{ctrl.actionName | capitalize}}" is not yet supported.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer ng-scope">
|
||||
<button class="btn btn-default" ng-click="ctrl.close()">Cancel</button>
|
||||
</div>
|
@ -1,81 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h3>Manage Clouds</h3>
|
||||
|
||||
<p>Below you see a collection of all the Ironic clouds available
|
||||
to you. You may add additional ones here, or remove ones that
|
||||
you've previously added.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<table class="table table-condensed table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>API Endpoint</th>
|
||||
<th>Source</th>
|
||||
<th class="text-right">
|
||||
<button class="btn btn-default btn-sm"
|
||||
ng-click="ctrl.add()">
|
||||
<i class="fa fa-plus"></i>
|
||||
<span class="hidden-xs">Add Cloud</span>
|
||||
</button>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-if="ctrl.configurations.$resolved && ctrl.configurations.length == 0">
|
||||
<tr>
|
||||
<td colspan="4" class="text-center text-muted">
|
||||
<em>
|
||||
<small>We were unable to detect a valid ironic service. Would you like
|
||||
to <a href="" ng-click="ctrl.add()">add one</a>?
|
||||
</small>
|
||||
</em>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr ng-repeat="config in ctrl.configurations">
|
||||
<td>
|
||||
<a href="" ng-click="ctrl.select(config)">
|
||||
{{config.name}}
|
||||
<i class="fa fa-play-circle"></i>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
{{config.ironic.apiRoot}}
|
||||
</td>
|
||||
<td ng-switch="config.source">
|
||||
<div ng-switch-when="local">
|
||||
<small class="text-info">Local</small>
|
||||
<i class="fa fa-question-circle"
|
||||
tooltip="This configuration was added by you, and is stored in your browser."></i>
|
||||
</div>
|
||||
<div ng-switch-when="host">
|
||||
<small class="text-success">Host</small>
|
||||
<i class="fa fa-question-circle"
|
||||
tooltip="This configuration was loaded from the server."></i>
|
||||
</div>
|
||||
<div ng-switch-when="static">
|
||||
<small class="text-success">Static</small>
|
||||
<i class="fa fa-question-circle"
|
||||
tooltip="This configuratoin was set by your application administrator."></i>
|
||||
</div>
|
||||
<div ng-switch-when="default">
|
||||
<small class="text-success">Default</small>
|
||||
<i class="fa fa-question-circle"
|
||||
tooltip="This configuration was automatically detected."></i>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="close"
|
||||
ng-if="config.source === 'local'"
|
||||
ng-click="ctrl.remove(config)">
|
||||
×</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
@ -1,85 +0,0 @@
|
||||
<div class="modal-header">
|
||||
<button type="button"
|
||||
class="close"
|
||||
ng-click="ctrl.close()">×</button>
|
||||
<h3 class="panel-title">Add Cloud</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<form name="configForm">
|
||||
<div class="form-group has-feedback"
|
||||
ng-class="{'has-error': configForm.name.$invalid && configForm.name.$dirty,
|
||||
'has-success': configForm.name.$valid && configForm.name.$dirty}">
|
||||
<label for="name" class="control-label">Name</label>
|
||||
<input id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
class="form-control"
|
||||
ng-model="ctrl.newConfiguration.name"
|
||||
required
|
||||
ng-minlength="5"
|
||||
placeholder="Please provide a distinct name for this cloud.">
|
||||
<span class="glyphicon glyphicon-remove form-control-feedback"
|
||||
ng-if="!configForm.name.$valid && configForm.name.$dirty">
|
||||
</span>
|
||||
<span class="glyphicon glyphicon-ok form-control-feedback"
|
||||
ng-if="configForm.name.$valid">
|
||||
</span>
|
||||
<small class="help-block">This will be used to
|
||||
distinguish this group of API's from others. Please
|
||||
use a name longer than 5 characters.
|
||||
</small>
|
||||
</div>
|
||||
<div class="form-group has-feedback"
|
||||
ng-class="{'has-error': configForm.ironic.$invalid && configForm.ironic.$dirty,
|
||||
'has-success': configForm.ironic.$valid && configForm.ironic.$dirty}">
|
||||
<label class="control-label" for="ironic">
|
||||
Ironic API URL
|
||||
<small class="text-muted"
|
||||
ng-if="configForm.ironic.$pending">
|
||||
 
|
||||
<i class="fa fa-spin fa-refresh"></i>
|
||||
Checking...
|
||||
</small>
|
||||
</label>
|
||||
|
||||
<input id="ironic"
|
||||
name="ironic"
|
||||
type="url"
|
||||
required
|
||||
ironic-api-url
|
||||
class="form-control"
|
||||
ng-model="ctrl.newConfiguration.ironic.apiRoot"
|
||||
ng-model-options="{debounce: 250}"
|
||||
placeholder="https://ironic.example.com:6385">
|
||||
<span class="glyphicon glyphicon-remove form-control-feedback"
|
||||
ng-if="!configForm.ironic.$valid && configForm.ironic.$dirty">
|
||||
</span>
|
||||
<span class="glyphicon glyphicon-ok form-control-feedback"
|
||||
ng-if="configForm.ironic.$valid">
|
||||
</span>
|
||||
<small class="help-block"
|
||||
ng-if="!configForm.ironic.$valid">Your API must
|
||||
support CORS requests from
|
||||
{{ctrl.location.protocol}}://{{ctrl.location.host}}:{{ctrl.location.port}}
|
||||
</small>
|
||||
<small class="help-block"
|
||||
ng-if="configForm.ironic.$valid">Versions
|
||||
{{configForm.ironic.$ironicVersions.join(', ')}}
|
||||
detected.
|
||||
</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer ng-scope">
|
||||
<button type="submit"
|
||||
ng-disabled="!configForm.$valid"
|
||||
ng-click="ctrl.save()"
|
||||
class="btn btn-primary">
|
||||
Save
|
||||
</button>
|
||||
<button class="btn btn-default" ng-click="ctrl.close()">Cancel</button>
|
||||
</div>
|
@ -1,11 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="navbar-header col-lg-3 col-xs-2">
|
||||
<a class="navbar-brand text-nowrap"
|
||||
href="#/ironic"
|
||||
active-path="^\/ironic$">
|
||||
<i class="of of-openstack"></i>
|
||||
<span class="hidden-sm hidden-md hidden-xs">OpenStack</span>
|
||||
Bare Metal
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
@ -1,37 +0,0 @@
|
||||
<div class="container-fluid"
|
||||
ng-if="!nodeCtrl.errorMessage">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h1>Node: {{nodeCtrl.node.name || nodeCtrl.node.uuid}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<ul class="nav nav-tabs">
|
||||
<li active-path="^\/ironic\/nodes\/.*\/node$">
|
||||
<a href="#/ironic/nodes/{{nodeCtrl.node.uuid}}/node">Node</a>
|
||||
</li>
|
||||
<li active-path="^\/ironic\/nodes\/.*\/ports$">
|
||||
<a href="#/ironic/nodes/{{nodeCtrl.node.uuid}}/ports">Ports</a>
|
||||
</li>
|
||||
<li active-path="^\/ironic\/nodes\/.*\/driver$">
|
||||
<a href="#/ironic/nodes/{{nodeCtrl.node.uuid}}/driver">Driver</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" ui-view>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid"
|
||||
ng-if="nodeCtrl.errorMessage">
|
||||
<div class="row">
|
||||
<div class="col-xs-13">
|
||||
<h2 class="text-center text-danger">Error:
|
||||
({{nodeCtrl.errorMessage.faultcode}})
|
||||
{{nodeCtrl.errorMessage.faultstring}}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,28 +0,0 @@
|
||||
<div class="col-xs-12">
|
||||
<table class="table-condensed table table-bordered col-xs-12">
|
||||
<tbody ng-if="driverCtrl.driver && driverCtrl.driver.$resolved">
|
||||
<tr ng-repeat="(key, value) in driverCtrl.driver">
|
||||
<th>{{key}}</th>
|
||||
<td>{{value}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody ng-if="driverCtrl.driver && !driverCtrl.driver.$resolved">
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<i class="fa fa-spin fa-refresh"></i>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody ng-if="driverCtrl.errorMessage">
|
||||
<tr>
|
||||
<td class="text-center text-danger">
|
||||
<strong>Error:</strong>
|
||||
({{driverCtrl.errorMessage.faultcode}})
|
||||
{{driverCtrl.errorMessage.faultstring}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
@ -1,28 +0,0 @@
|
||||
<div class="col-xs-12">
|
||||
<table class="table-condensed table table-bordered col-xs-12">
|
||||
<tbody ng-if="nodeCtrl.node && nodeCtrl.node.$resolved">
|
||||
<tr ng-repeat="(key, value) in nodeCtrl.node">
|
||||
<th>{{key}}</th>
|
||||
<td>{{value}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody ng-if="nodeCtrl.node && !nodeCtrl.node.$resolved">
|
||||
<tr>
|
||||
<td class="text-center">
|
||||
<i class="fa fa-spin fa-refresh"></i>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tbody ng-if="nodeCtrl.errorMessage">
|
||||
<tr>
|
||||
<td class="text-center text-danger">
|
||||
<strong>Error:</strong>
|
||||
({{nodeCtrl.errorMessage.faultcode}})
|
||||
{{nodeCtrl.errorMessage.faultstring}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
@ -1,34 +0,0 @@
|
||||
<div class="col-xs-12">
|
||||
<br/>
|
||||
|
||||
<div ng-repeat="port in portCtrl.ports"
|
||||
ng-if="portCtrl.ports && portCtrl.ports.$resolved && portCtrl.ports.length > 0">
|
||||
<h3>Port: {{port.uuid}}</h3>
|
||||
<table class="table-condensed table table-bordered">
|
||||
<tr ng-repeat="(key, value) in port">
|
||||
<th>{{key}}</th>
|
||||
<td>{{value}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div ng-if="portCtrl.ports && portCtrl.ports.$resolved && portCtrl.ports.length == 0">
|
||||
<p class="text-center">
|
||||
This node has no ports.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div ng-if="portCtrl.ports && !portCtrl.ports.$resolved">
|
||||
<p class="text-center">
|
||||
<i class="fa fa-spin fa-refresh"></i>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div ng-if="portCtrl.errorMessage">
|
||||
<p class="text-center text-danger">
|
||||
<strong>Error:</strong>
|
||||
({{portCtrl.errorMessage.faultcode}})
|
||||
{{portCtrl.errorMessage.faultstring}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
@ -1,50 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h1>Driver List</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row padding-top">
|
||||
<div class="col-xs-12">
|
||||
<button type="button" class="btn btn-default"
|
||||
ng-disabled="!driverListCtrl.drivers.$resolved"
|
||||
ng-click="driverListCtrl.init()">
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row padding-top">
|
||||
<div class="col-xs-12">
|
||||
<table class="table table-condensed table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Related Nodes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-if="driverListCtrl.drivers.$resolved && driverListCtrl.drivers.length > 0">
|
||||
<tr ng-repeat="driver in driverListCtrl.drivers"
|
||||
ng-class="{'info': driverListCtrl.selectedDrivers.indexOf(driver.uuid) > -1}">
|
||||
<td>{{driver.name || 'Unnamed'}}</td>
|
||||
<td>
|
||||
<a href="">View</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody ng-if="driverListCtrl.drivers.$resolved && driverListCtrl.drivers.length == 0">
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted">
|
||||
<small><em>No drivers were found.</em></small>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody ng-if="!driverListCtrl.drivers.$resolved">
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted">
|
||||
<i class="fa fa-refresh fa-spin"></i>
|
||||
Loading drivers...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
@ -1,64 +0,0 @@
|
||||
<div class="modal-header">
|
||||
<button type="button"
|
||||
class="close"
|
||||
ng-click="ctrl.close()">×</button>
|
||||
<h3 class="panel-title">Enroll Node</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-xs-3 control-label">Node Name</label>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" ng-model="ctrl.node.name"
|
||||
id="name" name="name"
|
||||
placeholder="A descriptive node name (optional)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="driver" class="col-xs-3 control-label">Node Driver</label>
|
||||
|
||||
<div class="col-sm-9">
|
||||
<select id="driver"
|
||||
class="form-control"
|
||||
ng-options="driver as driver.name for driver in ctrl.drivers"
|
||||
ng-model="ctrl.selectedDriver"
|
||||
ng-change="ctrl.loadDriverProperties(ctrl.selectedDriver.name)">
|
||||
<option value="" disabled selected>Choose a Driver</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr ng-if="ctrl.driverProperties.$resolved"/>
|
||||
<form class="form-horizontal" name="configForm" id="configForm">
|
||||
<p class="text-center"
|
||||
ng-if="ctrl.driverProperties && !ctrl.driverProperties.$resolved">
|
||||
<small><em><i class="fa fa-spin fa-refresh"></i></em></small>
|
||||
</p>
|
||||
<div class="form-group" ng-repeat="(name, desc) in ctrl.driverProperties">
|
||||
<label for="{{name}}" class="col-xs-3 control-label">{{name}}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
id="{{name}}"
|
||||
name="{{name}}"
|
||||
ng-model="ctrl.node.driver_info[name]"
|
||||
placeholder="{{desc}}"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer ng-scope">
|
||||
<p class="text-danger" ng-if="!!ctrl.error_message">{{ctrl.error_message}}</p>
|
||||
<button type="submit"
|
||||
ng-disabled="!ctrl.driverProperties.$resolved || !configForm.$valid"
|
||||
ng-click="ctrl.enroll()"
|
||||
class="btn btn-primary">
|
||||
Enroll
|
||||
</button>
|
||||
<button class="btn btn-default" ng-click="ctrl.close()">Cancel</button>
|
||||
</div>
|
@ -1,50 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="navbar-header col-lg-3 col-xs-2">
|
||||
<a class="navbar-brand text-nowrap"
|
||||
href="#"
|
||||
active-path="^\/ironic$">
|
||||
<i class="of of-openstack"></i>
|
||||
<span class="hidden-sm hidden-md hidden-xs">OpenStack</span>
|
||||
Bare Metal
|
||||
</a>
|
||||
</div>
|
||||
<ul class="nav navbar-nav col-xs-2">
|
||||
<li uib-dropdown is-open="status.isopen">
|
||||
<a href="#"
|
||||
uib-dropdown-toggle
|
||||
data-toggle="dropdown"
|
||||
class="text-nowrap">
|
||||
{{headerCtrl.currentConfiguration.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-header">Switch to...</li>
|
||||
<li ng-repeat="cloud in headerCtrl.configurations">
|
||||
<a href="#"
|
||||
ng-click="headerCtrl.switchCloud(cloud)">
|
||||
<i class="fa fa-cloud"></i>
|
||||
{{cloud.name}}
|
||||
</a>
|
||||
</li>
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href="#/config" class="text-muted">
|
||||
<i class="fa fa-gear"></i>
|
||||
Manage
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nav navbar-form-grid col-lg-7 col-xs-8">
|
||||
<div class="col-xs-9 col-sm-10">
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
placeholder="Search"
|
||||
disabled/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default-gradient col-xs-3 col-sm-2" disabled>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
@ -1,22 +0,0 @@
|
||||
<div class="row" ng-controller="NodeActionController as ctrl">
|
||||
<div class="col-xs-6">
|
||||
<div class="btn-group btn-group-lg">
|
||||
<button type="button"
|
||||
active-path="\/ironic\/nodes\/?.*"
|
||||
ui-sref="root.ironic.nodes"
|
||||
class="btn btn-default">Nodes</button>
|
||||
<button type="button"
|
||||
ui-sref="root.ironic.drivers"
|
||||
active-path="\/ironic\/drivers\/?.*"
|
||||
class="btn btn-default">Drivers</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<button ng-click="ctrl.enroll()"
|
||||
class="btn btn-primary btn-lg pull-right">
|
||||
<i class="fa fa-plus"></i> Node
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div ui-view="main">
|
||||
</div>
|
@ -1,112 +0,0 @@
|
||||
<div class="row padding-top">
|
||||
<div class="col-xs-12"
|
||||
ng-controller="NodeActionController as actionCtrl">
|
||||
<div class="btn-group" uib-dropdown>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
ng-disabled="nodeListCtrl.selectedNodes.length == 0"
|
||||
ng-click="actionCtrl.powerAction(nodeListCtrl.powerTransitions[0], nodeListCtrl.selectedNodes)">
|
||||
{{nodeListCtrl.powerTransitions[0] | capitalize}}
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
uib-dropdown-toggle
|
||||
ng-disabled="nodeListCtrl.selectedNodes.length == 0">
|
||||
<i class="caret"></i>
|
||||
</button>
|
||||
<ul uib-dropdown-menu>
|
||||
<li ng-repeat="event in nodeListCtrl.powerTransitions">
|
||||
<a ng-disabled="nodeListCtrl.selectedNodes.length == 0"
|
||||
ng-click="actionCtrl.powerAction(event, nodeListCtrl.selectedNodes)"
|
||||
href="">
|
||||
{{event | capitalize}}
|
||||
</a>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li ng-repeat="event in nodeListCtrl.provisionTransitions">
|
||||
<a ng-disabled="nodeListCtrl.selectedNodes.length == 0"
|
||||
ng-click="actionCtrl.provisionAction(event, nodeListCtrl.selectedNodes)"
|
||||
href="">
|
||||
{{event | capitalize}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default"
|
||||
ng-disabled="nodeListCtrl.selectedNodes.length == 0"
|
||||
ng-click="actionCtrl.powerAction('reboot', nodeListCtrl.selectedNodes)">
|
||||
Reboot
|
||||
</button>
|
||||
<button type="button" class="btn btn-default"
|
||||
ng-disabled="!nodeListCtrl.nodes.$resolved"
|
||||
ng-click="nodeListCtrl.init()">
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row padding-top">
|
||||
<div class="col-xs-12">
|
||||
<table class="table table-condensed table-striped table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox"
|
||||
ng-model="nodeListCtrl.selectAll"
|
||||
ng-change="nodeListCtrl.toggleSelectAll(nodeListCtrl.selectAll)"
|
||||
ng-if="nodeListCtrl.nodes.length > 0"
|
||||
/></th>
|
||||
<th>UUID</th>
|
||||
<th>Name</th>
|
||||
<th>Instance</th>
|
||||
<th>Provision State</th>
|
||||
<th>
|
||||
<select class="form-control input-sm pull-right" disabled>
|
||||
<option value="-1">All</option>
|
||||
<option value="true">True</option>
|
||||
<option value="false">False</option>
|
||||
</select>
|
||||
Maintenance
|
||||
</th>
|
||||
<th>
|
||||
<select class="form-control input-sm pull-right" disabled>
|
||||
<option value="-1">All</option>
|
||||
<option value="on">On</option>
|
||||
<option value="off">Off</option>
|
||||
</select>
|
||||
Power
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-if="nodeListCtrl.nodes.$resolved && nodeListCtrl.nodes.length > 0">
|
||||
<tr ng-repeat="node in nodeListCtrl.nodes"
|
||||
ng-class="{'info': nodeListCtrl.selectedNodes.indexOf(node.uuid) > -1}">
|
||||
<td>
|
||||
<input type="checkbox"
|
||||
checklist-model="nodeListCtrl.selectedNodes"
|
||||
checklist-value="node.uuid"/>
|
||||
</td>
|
||||
<td><a href="#/ironic/nodes/{{node.uuid}}/node">{{node.uuid}}</a></td>
|
||||
<td>{{node.name || 'Unnamed'}}</td>
|
||||
<td>{{node.instance_uuid || 'None'}}</td>
|
||||
<td>{{node.provision_state | capitalize}}</td>
|
||||
<td>{{node.maintenance ? 'True' : 'False'}}</td>
|
||||
<td>{{node.power_state || 'Unknown'}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody ng-if="nodeListCtrl.nodes.$resolved && nodeListCtrl.nodes.length == 0">
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted">
|
||||
<small><em>No nodes were found.</em></small>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody ng-if="!nodeListCtrl.nodes.$resolved">
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted">
|
||||
<i class="fa fa-refresh fa-spin"></i>
|
||||
Loading nodes...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
@ -1,9 +0,0 @@
|
||||
<nav class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container-fluid" ui-view="header"></div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid" ui-view="root"></div>
|
||||
|
||||
<nav class="navbar navbar-default navbar-fixed-bottom">
|
||||
<div class="container-fluid" ui-view="footer"></div>
|
||||
</nav>
|
35
bower.json
35
bower.json
@ -1,35 +0,0 @@
|
||||
{
|
||||
"name": "openstack-ironic-webclient",
|
||||
"version": "1.0.0",
|
||||
"description": "A webclient for OpenStack Ironic.",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"angular": "1.5.1",
|
||||
"angular-bootstrap": "1.2.4",
|
||||
"angular-cookies": "1.5.1",
|
||||
"angular-resource": "1.5.1",
|
||||
"angular-ui-router": "0.2.18",
|
||||
"bootstrap-sass": "3.3.6",
|
||||
"fontawesome": "4.5.0",
|
||||
"checklist-model": "0.9.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"overrides": {
|
||||
"bootstrap-sass": {
|
||||
"dependencies": false,
|
||||
"main": [
|
||||
"assets/stylesheets/_bootstrap.scss",
|
||||
"assets/fonts/bootstrap/glyphicons-halflings-regular.eot",
|
||||
"assets/fonts/bootstrap/glyphicons-halflings-regular.svg",
|
||||
"assets/fonts/bootstrap/glyphicons-halflings-regular.ttf",
|
||||
"assets/fonts/bootstrap/glyphicons-halflings-regular.woff",
|
||||
"assets/fonts/bootstrap/glyphicons-halflings-regular.woff2"
|
||||
]
|
||||
},
|
||||
"fontawesome": {
|
||||
"main": [
|
||||
"fonts/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
197
gulpfile.js
197
gulpfile.js
@ -1,197 +0,0 @@
|
||||
(function initializeGulp () {
|
||||
'use strict';
|
||||
|
||||
var SERVER_PORT = process.env.PORT || 8000;
|
||||
var SERVER_HOST = process.env.IPADDR || process.env.IP || 'localhost';
|
||||
|
||||
var gulp = require('gulp');
|
||||
var sass = require('gulp-sass');
|
||||
var concat = require('gulp-concat');
|
||||
var mainBowerFiles = require('main-bower-files');
|
||||
var filter = require('gulp-filter');
|
||||
var webserver = require('gulp-webserver');
|
||||
var del = require('del');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var iconfont = require('gulp-iconfont');
|
||||
var consolidate = require('gulp-consolidate');
|
||||
var vinylPaths = require('vinyl-paths');
|
||||
var merge = require('merge-stream');
|
||||
|
||||
var dir = {
|
||||
app: './app',
|
||||
dist: './www',
|
||||
cover: './cover',
|
||||
bower: './bower_components',
|
||||
npm: './node_modules'
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleans all imported, and generated, files from the project.
|
||||
*
|
||||
* @param {Function} cb callback.
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('clean', function () {
|
||||
return gulp.src([
|
||||
dir.npm,
|
||||
dir.bower,
|
||||
dir.dist,
|
||||
dir.cover
|
||||
]).pipe(vinylPaths(del));
|
||||
});
|
||||
|
||||
/**
|
||||
* Build our font from the icon svg.
|
||||
*
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('iconfont', function() {
|
||||
gulp.src([dir.app + '/fonts/openstack/*.svg'])
|
||||
.pipe(iconfont({
|
||||
fontName: 'openstack',
|
||||
appendCodepoints: true,
|
||||
appendUnicode: true,
|
||||
formats: ['ttf', 'eot', 'woff', 'woff2', 'svg']
|
||||
}))
|
||||
.on('glyphs', function(glyphs) {
|
||||
var options = {
|
||||
glyphs: glyphs,
|
||||
fontName: 'openstack',
|
||||
fontPath: '../fonts/',
|
||||
className: 'of'
|
||||
};
|
||||
return gulp.src(dir.app + '/fonts/openstack/openstack-font.css')
|
||||
.pipe(consolidate('lodash', options))
|
||||
.pipe(gulp.dest(dir.dist + '/css'));
|
||||
})
|
||||
.pipe(gulp.dest(dir.dist + '/fonts'));
|
||||
});
|
||||
|
||||
/**
|
||||
* Start a local server and serve the packaged application code.
|
||||
* This also watches the source tree and will update the application
|
||||
* whenever changes are detected.
|
||||
*
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('serve', ['package'], function () {
|
||||
|
||||
// Watch changes to the fonts directory.
|
||||
gulp.watch([dir.app + '/fonts/**/*.*'], ['iconfont']);
|
||||
|
||||
// Watch changes to the css directory.
|
||||
gulp.watch([dir.app + '/css/*.scss'], ['package:styles']);
|
||||
|
||||
// Watch changes to the bower.json file.
|
||||
gulp.watch(['./bower.json'], ['package:libs']);
|
||||
|
||||
gulp.watch(
|
||||
[dir.app + '/**/*.+(html)'],
|
||||
['package:static']);
|
||||
gulp.watch(
|
||||
[dir.app + '/**/*.+(js)'],
|
||||
['package:app']);
|
||||
|
||||
return gulp.src(dir.dist)
|
||||
.pipe(webserver({
|
||||
host: SERVER_HOST,
|
||||
port: SERVER_PORT,
|
||||
livereload: true,
|
||||
open: true
|
||||
}));
|
||||
});
|
||||
|
||||
/**
|
||||
* Copy all the fonts into the dist directory, and generate any custom
|
||||
* fonts necessary for the application.
|
||||
*
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('package:fonts', ['iconfont'], function () {
|
||||
var files = mainBowerFiles();
|
||||
return gulp.src(files)
|
||||
.pipe(filter(['*.eot', '*.svg', '*.ttf', '*.woff', '*.woff2']))
|
||||
.pipe(gulp.dest(dir.dist + '/fonts'));
|
||||
});
|
||||
|
||||
/**
|
||||
* Compile all styling files for the project. We're using SCSS includes here,
|
||||
* to explicitly choose which bits we need included.
|
||||
*
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('package:styles', function () {
|
||||
return gulp.src([dir.app + '/css/*.scss'])
|
||||
.pipe(sass())
|
||||
.pipe(gulp.dest(dir.dist + '/css'));
|
||||
});
|
||||
|
||||
/**
|
||||
* Copy all external javascript files, as independent documents (since
|
||||
* they may carry their own license) into the output directory.
|
||||
*
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('package:libs', function () {
|
||||
// NOTE: This is the extension point for package maintainers. If, rather
|
||||
// than using bower, you would like to link in dependencies from a different
|
||||
// source (ex. debian package), this is the method that would need to be
|
||||
// extended to look for those.
|
||||
var files = mainBowerFiles();
|
||||
return gulp.src(files)
|
||||
.pipe(filter('*.js'))
|
||||
.pipe(gulp.dest(dir.dist + '/js/lib'));
|
||||
});
|
||||
|
||||
/**
|
||||
* Iterate through the modules directory and build a concatenated js file for each directory.
|
||||
*
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('package:app', function () {
|
||||
var streams = [];
|
||||
var modulePath = path.join(dir.app, 'js', 'modules');
|
||||
|
||||
/*eslint-disable no-sync */
|
||||
fs.readdirSync(modulePath)
|
||||
.filter(function(file) {
|
||||
// Only pull directories
|
||||
return fs.statSync(path.join(modulePath, file)).isDirectory();
|
||||
}).forEach(function(libName) {
|
||||
// Build a file glob pattern.
|
||||
var libPath = path.join(modulePath, libName);
|
||||
var files = [
|
||||
path.join(libPath, 'module.js'),
|
||||
path.join(libPath, '**/*.js')
|
||||
];
|
||||
|
||||
// Create a concat stream for this library.
|
||||
var stream = gulp.src(files)
|
||||
.pipe(concat(libName + '.js'))
|
||||
.pipe(gulp.dest(path.join(dir.dist, 'js')));
|
||||
streams.push(stream);
|
||||
});
|
||||
/*eslint-enable no-sync */
|
||||
|
||||
// Merge all the streams and return.
|
||||
return merge.apply(merge, streams);
|
||||
});
|
||||
|
||||
/**
|
||||
* Copy static assets into our package.
|
||||
*
|
||||
* @return {*} A gulp stream that performs this action.
|
||||
*/
|
||||
gulp.task('package:static', function () {
|
||||
return gulp.src([
|
||||
dir.app + '/**/*.+(html|ico)'
|
||||
]).pipe(gulp.dest(dir.dist));
|
||||
});
|
||||
|
||||
/**
|
||||
* Package the app
|
||||
*/
|
||||
gulp.task('package', ['package:static', 'package:app', 'package:fonts',
|
||||
'package:styles', 'package:libs']);
|
||||
})();
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
module.exports = function (config) {
|
||||
|
||||
config.set({
|
||||
|
||||
port: 9876,
|
||||
|
||||
basePath: './',
|
||||
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
browsers: ['Chrome', 'Firefox'],
|
||||
|
||||
reporters: ['progress', 'coverage', 'threshold'],
|
||||
|
||||
browserNoActivityTimeout: 30000,
|
||||
|
||||
plugins: [
|
||||
'karma-jasmine',
|
||||
'karma-coverage',
|
||||
'karma-threshold-reporter',
|
||||
'karma-chrome-launcher',
|
||||
'karma-firefox-launcher'
|
||||
],
|
||||
|
||||
preprocessors: {
|
||||
'www/js/{!lib/**/*.js,*.js}': ['coverage']
|
||||
},
|
||||
|
||||
files: [
|
||||
// Library files, with some ordering.
|
||||
'www/js/lib/angular.js',
|
||||
'node_modules/angular-mocks/angular-mocks.js',
|
||||
'www/js/lib/*.js',
|
||||
|
||||
// Application files
|
||||
'www/js/**/*.js',
|
||||
|
||||
// Mocks
|
||||
'test/mock/**/*.js',
|
||||
|
||||
// Tests
|
||||
'test/spec/**/*.js'
|
||||
],
|
||||
|
||||
coverageReporter: {
|
||||
type: 'html',
|
||||
dir: 'cover',
|
||||
instrumenterOptions: {
|
||||
istanbul: {noCompact: true}
|
||||
}
|
||||
},
|
||||
|
||||
// Coverage threshold values.
|
||||
thresholdReporter: {
|
||||
statements: 94, // target 100
|
||||
branches: 96, // target 100
|
||||
functions: 92, // target 100
|
||||
lines: 94 // target 100
|
||||
},
|
||||
|
||||
exclude: [],
|
||||
|
||||
singleRun: true
|
||||
});
|
||||
};
|
||||
})();
|
48
package.json
48
package.json
@ -1,48 +0,0 @@
|
||||
{
|
||||
"name": "ironic-webclient",
|
||||
"version": "1.0.0",
|
||||
"description": "A webclient for OpenStack Ironic.",
|
||||
"main": "www/index.html",
|
||||
"repository": "https://git.openstack.org/openstack/ironic-webclient",
|
||||
"scripts": {
|
||||
"postinstall": "bower install --config.interactive=false",
|
||||
"start": "gulp serve",
|
||||
"prepublish": "gulp package",
|
||||
"lint": "eslint ./",
|
||||
"pretest": "gulp package",
|
||||
"test": "karma start ./karma.conf.js",
|
||||
"clean": "gulp clean"
|
||||
},
|
||||
"files": [
|
||||
"www"
|
||||
],
|
||||
"author": "OpenStack <openstack-dev@lists.openstack.org>",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"angular-mocks": "1.4.6",
|
||||
"bower": "1.5.2",
|
||||
"del": "1.2.1",
|
||||
"eslint": "1.10.3",
|
||||
"eslint-config-openstack": "1.2.4",
|
||||
"eslint-plugin-angular": "1.0.0",
|
||||
"gulp": "3.9.0",
|
||||
"gulp-concat": "2.6.0",
|
||||
"gulp-consolidate": "0.1.2",
|
||||
"gulp-filter": "3.0.0",
|
||||
"gulp-iconfont": "5.0.1",
|
||||
"gulp-sass": "2.0.4",
|
||||
"gulp-webserver": "0.9.1",
|
||||
"jasmine": "2.3.2",
|
||||
"karma": "0.13.9",
|
||||
"karma-chrome-launcher": "0.2.0",
|
||||
"karma-cli": "0.1.0",
|
||||
"karma-coverage": "0.5.0",
|
||||
"karma-firefox-launcher": "0.1.6",
|
||||
"karma-jasmine": "0.3.6",
|
||||
"karma-threshold-reporter": "0.1.15",
|
||||
"lodash": "3.10.1",
|
||||
"main-bower-files": "2.9.0",
|
||||
"merge-stream": "1.0.0",
|
||||
"vinyl-paths": "1.0.0"
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module provides some basic IronicDriver API responses.
|
||||
*
|
||||
* Usage: beforeEach(module('ironic.mock.IronicDriver'));
|
||||
*/
|
||||
angular.module('ironic.api.mock.IronicDriver',
|
||||
['ironic.api', 'openstack.mock.$$selectedConfiguration'])
|
||||
.run(function($httpBackend) {
|
||||
'use strict';
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/drivers')
|
||||
.respond(200, {
|
||||
drivers: [
|
||||
{name: 'test_driver_1'},
|
||||
{name: 'test_driver_2'}
|
||||
]
|
||||
});
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/drivers/test_driver_1')
|
||||
.respond(200, {
|
||||
name: "test_driver_1"
|
||||
});
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/drivers/test_driver_2')
|
||||
.respond(200, {
|
||||
name: "test_driver_2"
|
||||
});
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module provides some basic IronicDriverProperties API responses.
|
||||
*
|
||||
* Usage: beforeEach(module('ironic.mock.IronicDriverProperties'));
|
||||
*/
|
||||
angular.module('ironic.api.mock.IronicDriverProperties',
|
||||
['ironic.api', 'openstack.mock.$$selectedConfiguration'])
|
||||
.run(function($httpBackend) {
|
||||
'use strict';
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/drivers/properties?driver_name=test_driver_1')
|
||||
.respond(200, {name: 'test_driver_1'});
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/drivers/properties?driver_name=test_driver_2')
|
||||
.respond(200, {name: 'test_driver_2'});
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/drivers/properties?driver_name=invalid')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
});
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module provides some basic IronicNode API responses.
|
||||
*
|
||||
* Usage: beforeEach(module('ironic.mock.IronicNode'));
|
||||
*/
|
||||
angular.module('ironic.api.mock.IronicNode',
|
||||
['ironic.api', 'openstack.mock.$$selectedConfiguration'])
|
||||
.run(function($httpBackend) {
|
||||
'use strict';
|
||||
|
||||
var nodes = [
|
||||
{
|
||||
uuid: 'test_node_1',
|
||||
driver: 'test_driver_1',
|
||||
provision_state: 'enroll'
|
||||
},
|
||||
{
|
||||
uuid: 'test_node_2',
|
||||
driver: 'test_driver_1',
|
||||
provision_state: 'enroll'
|
||||
},
|
||||
{
|
||||
uuid: 'test_node_3',
|
||||
driver: 'test_driver_2',
|
||||
provision_state: 'manageable'
|
||||
}
|
||||
];
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/nodes')
|
||||
.respond(200, {
|
||||
nodes: angular.copy(nodes)
|
||||
});
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/nodes/test_node_1')
|
||||
.respond(200, angular.copy(nodes[0]));
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/nodes/test_node_2')
|
||||
.respond(200, angular.copy(nodes[1]));
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/nodes/test_node_3')
|
||||
.respond(200, angular.copy(nodes[3]));
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module provides some basic IronicPort API responses.
|
||||
*
|
||||
* Usage: beforeEach(module('ironic.mock.IronicPort'));
|
||||
*/
|
||||
angular.module('ironic.api.mock.IronicPort',
|
||||
['ironic.api', 'openstack.mock.$$selectedConfiguration'])
|
||||
.run(function($httpBackend) {
|
||||
'use strict';
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/ports?node=test_node_1')
|
||||
.respond(200, {
|
||||
ports: []
|
||||
});
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/ports?node=test_node_2')
|
||||
.respond(200, {
|
||||
ports: []
|
||||
});
|
||||
|
||||
$httpBackend
|
||||
.whenGET('http://ironic.example.com:1000/ports?node=test_node_3')
|
||||
.respond(200, {
|
||||
ports: []
|
||||
});
|
||||
});
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module loads various mock configurations into the test scope.
|
||||
*
|
||||
* Usage: beforeEach(module('openstack.mock.$$configuration'));
|
||||
*/
|
||||
angular.module('openstack.mock.$$configuration', ['openstack'])
|
||||
.config(function($$configurationProvider) {
|
||||
'use strict';
|
||||
|
||||
// Disable unused configuration options for the test harness.
|
||||
$$configurationProvider.$enableLocalStorage(false);
|
||||
$$configurationProvider.$enableDefault(false);
|
||||
$$configurationProvider.$enableConfigLoad(false);
|
||||
|
||||
// Wrap a spy around our other feature flags so they can't accidentally be triggered in a
|
||||
// test harness.
|
||||
spyOn($$configurationProvider, '$enableLocalStorage');
|
||||
spyOn($$configurationProvider, '$enableDefault');
|
||||
spyOn($$configurationProvider, '$enableConfigLoad');
|
||||
|
||||
$$configurationProvider.$addConfig({
|
||||
id: 'test_config_1',
|
||||
ironic: {apiRoot: 'http://ironic.example.com:1000'}
|
||||
});
|
||||
$$configurationProvider.$addConfig({
|
||||
id: 'test_config_2',
|
||||
ironic: {apiRoot: 'http://ironic.example.com:2000'}
|
||||
});
|
||||
});
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module automatically selects a default configuration for the test harness.
|
||||
*
|
||||
* Usage: beforeEach(module('openstack.mock.$$selectedConfiguration'));
|
||||
*/
|
||||
angular.module('openstack.mock.$$selectedConfiguration', ['openstack.mock.$$configuration'])
|
||||
.run(function($$selectedConfiguration, $$persistentStorage, $rootScope) {
|
||||
'use strict';
|
||||
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
afterEach(function() {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
});
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mock service override for the ui-router template factory, so that we can unit test components
|
||||
* without having to mock out the entire template loading mechanism.
|
||||
*/
|
||||
angular.module('template.mock', ['ui.router'])
|
||||
.run(function($templateFactory) {
|
||||
'use strict';
|
||||
|
||||
// Spy on the fromUrl method, so we intercept all $http calls
|
||||
// to templates and don't fail on creating those.
|
||||
spyOn($templateFactory, 'fromUrl');
|
||||
});
|
@ -1,103 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's HTTP interceptors.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic API Transformation Methods',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var ironicApiInterceptor;
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
beforeEach(inject(function($injector) {
|
||||
ironicApiInterceptor = $injector.get('ironicApiInterceptor');
|
||||
}));
|
||||
|
||||
/**
|
||||
* A dummy response body for a valid object.
|
||||
*/
|
||||
var objectResponse = {
|
||||
uuid: 'foo'
|
||||
};
|
||||
|
||||
/**
|
||||
* A dummy response object for a valid list of objects.
|
||||
*/
|
||||
var listResponse = {
|
||||
resourceName: [
|
||||
angular.copy(objectResponse)
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* A dummy error response.
|
||||
*/
|
||||
var errorResponse = {
|
||||
error_message: {
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
}
|
||||
};
|
||||
var encodedErrorResponse = angular.copy(errorResponse);
|
||||
encodedErrorResponse.error_message = angular.toJson(encodedErrorResponse.error_message);
|
||||
|
||||
/**
|
||||
* Run all changes through the filter chain.
|
||||
*
|
||||
* @param {String} resourceName The name of the resource to resolve.
|
||||
* @param {*} body The response data body to modify.
|
||||
* @param {int} status The HTTP status code to return.
|
||||
* @return {*} The modified body.
|
||||
*/
|
||||
function applyResponseTransformationChain (resourceName, body, status) {
|
||||
status = status || 200;
|
||||
var transformers = ironicApiInterceptor.response(resourceName);
|
||||
for (var i = 0; i < transformers.length; i++) {
|
||||
var transformer = transformers[i];
|
||||
body = transformer(body, function() {
|
||||
}, status);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
it('should transform a regular object response',
|
||||
function() {
|
||||
var result = applyResponseTransformationChain(
|
||||
null,
|
||||
angular.toJson(objectResponse),
|
||||
200
|
||||
);
|
||||
expect(result).toEqual(objectResponse);
|
||||
});
|
||||
|
||||
it('should transform an object error response (twice)',
|
||||
function() {
|
||||
var result = applyResponseTransformationChain(
|
||||
null,
|
||||
angular.toJson(encodedErrorResponse),
|
||||
400
|
||||
);
|
||||
expect(result).toEqual(errorResponse);
|
||||
});
|
||||
|
||||
it('should transform a correct list response',
|
||||
function() {
|
||||
var result = applyResponseTransformationChain(
|
||||
'resourceName',
|
||||
angular.toJson(listResponse),
|
||||
200
|
||||
);
|
||||
expect(result).toEqual(listResponse.resourceName);
|
||||
});
|
||||
|
||||
it('should transform an error list response (twice)',
|
||||
function() {
|
||||
var result = applyResponseTransformationChain(
|
||||
'resourceName',
|
||||
angular.toJson(encodedErrorResponse),
|
||||
400
|
||||
);
|
||||
expect(result).toEqual(errorResponse);
|
||||
});
|
||||
});
|
@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's API Version Header.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Version Header',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $httpBackend;
|
||||
|
||||
// Load common configuration mocks.
|
||||
beforeEach(module('openstack.mock.$$selectedConfiguration'));
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
it('should exist',
|
||||
inject(function(ironicApiVersion) {
|
||||
expect(ironicApiVersion).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should return 1.14',
|
||||
inject(function(ironicApiVersion) {
|
||||
expect(ironicApiVersion()).toBe('1.14');
|
||||
}));
|
||||
|
||||
it('should be attached to all ironic API requests',
|
||||
inject(function(IronicNode, IronicPort, IronicChassis, IronicDriver,
|
||||
IronicDriverProperties) {
|
||||
var expectedHeaders = {
|
||||
'X-OpenStack-Ironic-API-Version': "1.14",
|
||||
Accept: "application/json, text/plain, */*"
|
||||
};
|
||||
|
||||
// Everything's a 404 response for simplicity's sake. We only care about the header.
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/nodes/fake',
|
||||
expectedHeaders)
|
||||
.respond(404, '');
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/ports/fake',
|
||||
expectedHeaders)
|
||||
.respond(404, '');
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/chassis/fake',
|
||||
expectedHeaders)
|
||||
.respond(404, '');
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/drivers/fake',
|
||||
expectedHeaders)
|
||||
.respond(404, '');
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/drivers/properties?driver_name=fake',
|
||||
expectedHeaders)
|
||||
.respond(404, '');
|
||||
|
||||
IronicNode.read({uuid: 'fake'});
|
||||
IronicPort.read({uuid: 'fake'});
|
||||
IronicChassis.read({uuid: 'fake'});
|
||||
IronicDriver.read({uuid: 'fake'});
|
||||
IronicDriverProperties.read({driver_name: 'fake'});
|
||||
|
||||
$httpBackend.flush();
|
||||
|
||||
}));
|
||||
|
||||
});
|
@ -1,217 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's ngResource IronicChassis implementation.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Chassis Resource',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope, $httpBackend;
|
||||
|
||||
// Load common configuration mocks.
|
||||
beforeEach(module('openstack.mock.$$configuration'));
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
it('should implement a basic CRUD interface',
|
||||
inject(function(IronicChassis) {
|
||||
expect(IronicChassis.query).toBeDefined();
|
||||
expect(IronicChassis.create).toBeDefined();
|
||||
expect(IronicChassis.read).toBeDefined();
|
||||
expect(IronicChassis.update).toBeDefined();
|
||||
expect(IronicChassis.remove).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should switch API requests if the configuration changes.',
|
||||
inject(function(IronicChassis, $$selectedConfiguration) {
|
||||
|
||||
// Select #1
|
||||
var config1 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config1.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/chassis')
|
||||
.respond(200, {chassis: [{}]});
|
||||
var result1 = IronicChassis.query({});
|
||||
expect(result1.$promise).toBeDefined();
|
||||
expect(result1.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result1.$resolved).toBeTruthy();
|
||||
expect(result1.length).toBe(1);
|
||||
expect(result1.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch configs.
|
||||
var config2 = $$selectedConfiguration.set('test_config_2');
|
||||
$rootScope.$apply();
|
||||
expect(config2.ironic.apiRoot).toBe('http://ironic.example.com:2000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:2000/chassis')
|
||||
.respond(200, {chassis: [{}, {}]});
|
||||
var result2 = IronicChassis.query({});
|
||||
expect(result2.$promise).toBeDefined();
|
||||
expect(result2.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result2.$resolved).toBeTruthy();
|
||||
expect(result2.length).toBe(2);
|
||||
expect(result2.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch it back.
|
||||
var config3 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config3.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:1000/chassis')
|
||||
.respond(200, {chassis: [{}]});
|
||||
var result3 = IronicChassis.query({});
|
||||
expect(result3.$promise).toBeDefined();
|
||||
expect(result3.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result3.$resolved).toBeTruthy();
|
||||
expect(result3.length).toBe(1);
|
||||
expect(result3.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should return a failed resource if an invalid config has been selected',
|
||||
inject(function(IronicChassis) {
|
||||
var queryResult = IronicChassis.query({id: 'meaningless'});
|
||||
expect(angular.isArray(queryResult)).toBeTruthy();
|
||||
expect(queryResult.$promise).toBeDefined();
|
||||
expect(queryResult.$resolved).toBeFalsy();
|
||||
|
||||
var createResult = IronicChassis.create({id: 'meaningless'});
|
||||
expect(angular.isObject(createResult)).toBeTruthy();
|
||||
expect(createResult.$promise).toBeDefined();
|
||||
expect(createResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(createResult.$resolved).toBeTruthy();
|
||||
expect(createResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var updateResult = IronicChassis.update({id: 'meaningless'});
|
||||
expect(angular.isObject(updateResult)).toBeTruthy();
|
||||
expect(updateResult.$promise).toBeDefined();
|
||||
expect(updateResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(updateResult.$resolved).toBeTruthy();
|
||||
expect(updateResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var readResult = IronicChassis.read({id: 'meaningless'});
|
||||
expect(angular.isObject(readResult)).toBeTruthy();
|
||||
expect(readResult.$promise).toBeDefined();
|
||||
expect(readResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(readResult.$resolved).toBeTruthy();
|
||||
expect(readResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var removeResult = IronicChassis.remove({id: 'meaningless'});
|
||||
expect(angular.isObject(removeResult)).toBeTruthy();
|
||||
expect(removeResult.$promise).toBeDefined();
|
||||
expect(removeResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(removeResult.$resolved).toBeTruthy();
|
||||
expect(removeResult.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse query error responses',
|
||||
inject(function(IronicChassis, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/chassis')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicChassis.query({});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD regular responses',
|
||||
inject(function(IronicChassis, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/chassis/1')
|
||||
.respond(200, {uuid: 1});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicChassis.read({uuid: 1});
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(1);
|
||||
expect(result.uuid).toBe(1);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD error responses',
|
||||
inject(function(IronicChassis, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/chassis/1')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicChassis.read({uuid: 1});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
});
|
@ -1,217 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's ngResource IronicDriver implementation.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Driver Resource',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope, $httpBackend;
|
||||
|
||||
// Load common configuration mocks.
|
||||
beforeEach(module('openstack.mock.$$configuration'));
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
it('should implement a basic CRUD interface',
|
||||
inject(function(IronicDriver) {
|
||||
expect(IronicDriver.query).toBeDefined();
|
||||
expect(IronicDriver.create).toBeDefined();
|
||||
expect(IronicDriver.read).toBeDefined();
|
||||
expect(IronicDriver.update).toBeDefined();
|
||||
expect(IronicDriver.remove).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should switch API requests if the configuration changes.',
|
||||
inject(function(IronicDriver, $$selectedConfiguration) {
|
||||
|
||||
// Select #1
|
||||
var config1 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config1.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/drivers')
|
||||
.respond(200, {drivers: [{}]});
|
||||
var result1 = IronicDriver.query({});
|
||||
expect(result1.$promise).toBeDefined();
|
||||
expect(result1.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result1.$resolved).toBeTruthy();
|
||||
expect(result1.length).toBe(1);
|
||||
expect(result1.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch configs.
|
||||
var config2 = $$selectedConfiguration.set('test_config_2');
|
||||
$rootScope.$apply();
|
||||
expect(config2.ironic.apiRoot).toBe('http://ironic.example.com:2000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:2000/drivers')
|
||||
.respond(200, {drivers: [{}, {}]});
|
||||
var result2 = IronicDriver.query({});
|
||||
expect(result2.$promise).toBeDefined();
|
||||
expect(result2.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result2.$resolved).toBeTruthy();
|
||||
expect(result2.length).toBe(2);
|
||||
expect(result2.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch it back.
|
||||
var config3 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config3.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:1000/drivers')
|
||||
.respond(200, {drivers: [{}]});
|
||||
var result3 = IronicDriver.query({});
|
||||
expect(result3.$promise).toBeDefined();
|
||||
expect(result3.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result3.$resolved).toBeTruthy();
|
||||
expect(result3.length).toBe(1);
|
||||
expect(result3.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should return a failed resource if an invalid config has been selected',
|
||||
inject(function(IronicDriver) {
|
||||
var queryResult = IronicDriver.query({id: 'meaningless'});
|
||||
expect(angular.isArray(queryResult)).toBeTruthy();
|
||||
expect(queryResult.$promise).toBeDefined();
|
||||
expect(queryResult.$resolved).toBeFalsy();
|
||||
|
||||
var createResult = IronicDriver.create({id: 'meaningless'});
|
||||
expect(angular.isObject(createResult)).toBeTruthy();
|
||||
expect(createResult.$promise).toBeDefined();
|
||||
expect(createResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(createResult.$resolved).toBeTruthy();
|
||||
expect(createResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var updateResult = IronicDriver.update({id: 'meaningless'});
|
||||
expect(angular.isObject(updateResult)).toBeTruthy();
|
||||
expect(updateResult.$promise).toBeDefined();
|
||||
expect(updateResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(updateResult.$resolved).toBeTruthy();
|
||||
expect(updateResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var readResult = IronicDriver.read({id: 'meaningless'});
|
||||
expect(angular.isObject(readResult)).toBeTruthy();
|
||||
expect(readResult.$promise).toBeDefined();
|
||||
expect(readResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(readResult.$resolved).toBeTruthy();
|
||||
expect(readResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var removeResult = IronicDriver.remove({id: 'meaningless'});
|
||||
expect(angular.isObject(removeResult)).toBeTruthy();
|
||||
expect(removeResult.$promise).toBeDefined();
|
||||
expect(removeResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(removeResult.$resolved).toBeTruthy();
|
||||
expect(removeResult.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse query error responses',
|
||||
inject(function(IronicDriver, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/drivers')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicDriver.query({});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD regular responses',
|
||||
inject(function(IronicDriver, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/drivers/1')
|
||||
.respond(200, {uuid: 1});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicDriver.read({uuid: 1});
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(1);
|
||||
expect(result.uuid).toBe(1);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD error responses',
|
||||
inject(function(IronicDriver, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/drivers/1')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicDriver.read({uuid: 1});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
});
|
@ -1,183 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's ngResource Ironic Driver Properties implementation.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Driver Properties Resource',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope, $httpBackend;
|
||||
|
||||
// Create some test data
|
||||
var testReturnData = {
|
||||
foo: 'bar'
|
||||
};
|
||||
|
||||
// Load common configuration mocks.
|
||||
beforeEach(module('openstack.mock.$$configuration'));
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
it('should implement a basic CRUD interface',
|
||||
inject(function(IronicDriverProperties) {
|
||||
expect(IronicDriverProperties.read).toBeDefined("must have read() method");
|
||||
}));
|
||||
|
||||
it('should switch API requests if the configuration changes.',
|
||||
inject(function(IronicDriverProperties, $$selectedConfiguration) {
|
||||
|
||||
// Select #1
|
||||
var config1 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config1.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/drivers/properties?driver_name=foo')
|
||||
.respond(200, testReturnData);
|
||||
var result1 = IronicDriverProperties.read({driver_name: 'foo'});
|
||||
expect(result1.$promise).toBeDefined();
|
||||
expect(result1.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result1.$resolved).toBeTruthy();
|
||||
expect(result1.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch configs.
|
||||
var config2 = $$selectedConfiguration.set('test_config_2');
|
||||
$rootScope.$apply();
|
||||
expect(config2.ironic.apiRoot).toBe('http://ironic.example.com:2000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend
|
||||
.expect('GET', 'http://ironic.example.com:2000/drivers/properties?driver_name=foo')
|
||||
.respond(200, testReturnData);
|
||||
var result2 = IronicDriverProperties.read({driver_name: 'foo'});
|
||||
expect(result2.$promise).toBeDefined();
|
||||
expect(result2.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result2.$resolved).toBeTruthy();
|
||||
expect(result2.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch it back.
|
||||
var config3 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config3.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend
|
||||
.expect('GET', 'http://ironic.example.com:1000/drivers/properties?driver_name=foo')
|
||||
.respond(200, testReturnData);
|
||||
var result3 = IronicDriverProperties.read({driver_name: 'foo'});
|
||||
expect(result3.$promise).toBeDefined();
|
||||
expect(result3.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result3.$resolved).toBeTruthy();
|
||||
expect(result3.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should return a failed resource if an invalid config has been selected',
|
||||
inject(function(IronicDriverProperties) {
|
||||
var queryResult = IronicDriverProperties.read({driver_name: 'foo'});
|
||||
expect(queryResult.$promise).toBeDefined();
|
||||
expect(queryResult.$resolved).toBeFalsy();
|
||||
}));
|
||||
|
||||
it('should correctly parse query error responses',
|
||||
inject(function(IronicDriverProperties, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/drivers/properties?driver_name=foo')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicDriverProperties.read({driver_name: 'foo'});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD regular responses',
|
||||
inject(function(IronicDriverProperties, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/drivers/properties?driver_name=foo')
|
||||
.respond(200, testReturnData);
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicDriverProperties.read({driver_name: 'foo'});
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(1);
|
||||
expect(result.foo).toBe('bar');
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD error responses',
|
||||
inject(function(IronicDriverProperties, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend
|
||||
.expectGET('http://ironic.example.com:1000/drivers/properties?driver_name=foo')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicDriverProperties.read({driver_name: 'foo'});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
});
|
@ -1,216 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's ngResource IronicNode implementation.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Node Resource',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope, $httpBackend;
|
||||
|
||||
// Load common configuration mocks.
|
||||
beforeEach(module('openstack.mock.$$configuration'));
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
it('should implement a basic CRUD interface',
|
||||
inject(function(IronicNode) {
|
||||
expect(IronicNode.query).toBeDefined();
|
||||
expect(IronicNode.create).toBeDefined();
|
||||
expect(IronicNode.read).toBeDefined();
|
||||
expect(IronicNode.update).toBeDefined();
|
||||
expect(IronicNode.remove).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should switch API requests if the configuration changes.',
|
||||
inject(function(IronicNode, $$selectedConfiguration) {
|
||||
// Select #1
|
||||
var config1 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config1.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/nodes')
|
||||
.respond(200, {nodes: [{}]});
|
||||
var result1 = IronicNode.query({});
|
||||
expect(result1.$promise).toBeDefined();
|
||||
expect(result1.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result1.$resolved).toBeTruthy();
|
||||
expect(result1.length).toBe(1);
|
||||
expect(result1.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch configs.
|
||||
var config2 = $$selectedConfiguration.set('test_config_2');
|
||||
$rootScope.$apply();
|
||||
expect(config2.ironic.apiRoot).toBe('http://ironic.example.com:2000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:2000/nodes')
|
||||
.respond(200, {nodes: [{}, {}]});
|
||||
var result2 = IronicNode.query({});
|
||||
expect(result2.$promise).toBeDefined();
|
||||
expect(result2.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result2.$resolved).toBeTruthy();
|
||||
expect(result2.length).toBe(2);
|
||||
expect(result2.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch it back.
|
||||
var config3 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config3.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:1000/nodes')
|
||||
.respond(200, {nodes: [{}]});
|
||||
var result3 = IronicNode.query({});
|
||||
expect(result3.$promise).toBeDefined();
|
||||
expect(result3.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result3.$resolved).toBeTruthy();
|
||||
expect(result3.length).toBe(1);
|
||||
expect(result3.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should return a failed resource if an invalid config has been selected',
|
||||
inject(function(IronicNode) {
|
||||
var queryResult = IronicNode.query({id: 'meaningless'});
|
||||
expect(angular.isArray(queryResult)).toBeTruthy();
|
||||
expect(queryResult.$promise).toBeDefined();
|
||||
expect(queryResult.$resolved).toBeFalsy();
|
||||
|
||||
var createResult = IronicNode.create({id: 'meaningless'});
|
||||
expect(angular.isObject(createResult)).toBeTruthy();
|
||||
expect(createResult.$promise).toBeDefined();
|
||||
expect(createResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(createResult.$resolved).toBeTruthy();
|
||||
expect(createResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var updateResult = IronicNode.update({id: 'meaningless'});
|
||||
expect(angular.isObject(updateResult)).toBeTruthy();
|
||||
expect(updateResult.$promise).toBeDefined();
|
||||
expect(updateResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(updateResult.$resolved).toBeTruthy();
|
||||
expect(updateResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var readResult = IronicNode.read({id: 'meaningless'});
|
||||
expect(angular.isObject(readResult)).toBeTruthy();
|
||||
expect(readResult.$promise).toBeDefined();
|
||||
expect(readResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(readResult.$resolved).toBeTruthy();
|
||||
expect(readResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var removeResult = IronicNode.remove({id: 'meaningless'});
|
||||
expect(angular.isObject(removeResult)).toBeTruthy();
|
||||
expect(removeResult.$promise).toBeDefined();
|
||||
expect(removeResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(removeResult.$resolved).toBeTruthy();
|
||||
expect(removeResult.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse query error responses',
|
||||
inject(function(IronicNode, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/nodes')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicNode.query({});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD regular responses',
|
||||
inject(function(IronicNode, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/nodes/1')
|
||||
.respond(200, {uuid: 1});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicNode.read({uuid: 1});
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(1);
|
||||
expect(result.uuid).toBe(1);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD error responses',
|
||||
inject(function(IronicNode, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/nodes/1')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicNode.read({uuid: 1});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
});
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, LP
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for ironic's ngResource IronicNode implementation.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Node Resource',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope;
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
}));
|
||||
|
||||
/**
|
||||
* Assertion helper, make sure a list of transitions contains one we're looking for.
|
||||
*
|
||||
* @param {Array} transitions The transitions array to check.
|
||||
* @param {String} from The name of the originating state.
|
||||
* @param {String} actor The name of the actor.
|
||||
* @param {String} action The name of the transition action name.
|
||||
* @param {String} target The name of the target state.
|
||||
* @return {void}
|
||||
*/
|
||||
function assertHasTransition (transitions, from, actor, action, target) {
|
||||
expect(transitions).toContain({
|
||||
from_state: from,
|
||||
event: action,
|
||||
target_state: target,
|
||||
actor: actor
|
||||
});
|
||||
}
|
||||
|
||||
it('should implement the query method',
|
||||
inject(function(IronicNodePowerTransition) {
|
||||
expect(IronicNodePowerTransition.query).toBeDefined();
|
||||
|
||||
// CRUD methods not supported on this resource.
|
||||
expect(IronicNodePowerTransition.create).not.toBeDefined();
|
||||
expect(IronicNodePowerTransition.read).not.toBeDefined();
|
||||
expect(IronicNodePowerTransition.update).not.toBeDefined();
|
||||
expect(IronicNodePowerTransition.remove).not.toBeDefined();
|
||||
}));
|
||||
|
||||
it('should return a "resource-like" array"',
|
||||
inject(function(IronicNodePowerTransition) {
|
||||
var transitions = IronicNodePowerTransition.query();
|
||||
$rootScope.$apply();
|
||||
expect(transitions.$resolved).toBeTruthy();
|
||||
expect(transitions.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should permit filtering.',
|
||||
inject(function(IronicNodePowerTransition) {
|
||||
var transitions = IronicNodePowerTransition.query({
|
||||
from_state: 'power on'
|
||||
});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(transitions.length).toEqual(2);
|
||||
|
||||
var conductorTransitions = IronicNodePowerTransition.query({
|
||||
from_state: 'rebooting',
|
||||
actor: 'conductor'
|
||||
});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(conductorTransitions.length).toEqual(1);
|
||||
}));
|
||||
|
||||
it('should permit query promise handlers.',
|
||||
inject(function(IronicNodePowerTransition) {
|
||||
var success = false;
|
||||
IronicNodePowerTransition.query({
|
||||
from_state: 'power on'
|
||||
}, function() {
|
||||
success = true;
|
||||
});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(success).toBeTruthy();
|
||||
}));
|
||||
|
||||
it('should return the expected transition graph.',
|
||||
inject(function(IronicNodePowerTransition) {
|
||||
var transitions = IronicNodePowerTransition.query();
|
||||
$rootScope.$apply();
|
||||
|
||||
var USER = "user";
|
||||
var CONDUCTOR = "conductor";
|
||||
|
||||
// Power states
|
||||
assertHasTransition(transitions, "power off", USER, "power on", "power on");
|
||||
assertHasTransition(transitions, "power on", USER, "power off", "power off");
|
||||
assertHasTransition(transitions, "power on", USER, "reboot", "rebooting");
|
||||
assertHasTransition(transitions, "rebooting", CONDUCTOR, "power on", "power on");
|
||||
}));
|
||||
});
|
@ -1,185 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for Ironic's IronicNodeProvision resource.
|
||||
*/
|
||||
describe('IronicNodeProvision',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope, $httpBackend;
|
||||
|
||||
// Load common configuration mocks.
|
||||
beforeEach(module('openstack.mock.$$configuration'));
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
describe('Interface', function() {
|
||||
it('should implement the update method',
|
||||
inject(function(IronicNodeProvision) {
|
||||
expect(IronicNodeProvision.update).toBeDefined();
|
||||
})
|
||||
);
|
||||
|
||||
it('should not implement the query, create, read, or remove method',
|
||||
inject(function(IronicNodeProvision) {
|
||||
expect(IronicNodeProvision.query).not.toBeDefined();
|
||||
expect(IronicNodeProvision.create).not.toBeDefined();
|
||||
expect(IronicNodeProvision.read).not.toBeDefined();
|
||||
expect(IronicNodeProvision.remove).not.toBeDefined();
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('basic behavior', function() {
|
||||
|
||||
var testManageBody = {
|
||||
node_ident: 'test_id',
|
||||
target: 'manage'
|
||||
};
|
||||
|
||||
it('should switch API requests if the configuration changes.',
|
||||
inject(function(IronicNodeProvision, $$selectedConfiguration) {
|
||||
|
||||
// Select #1
|
||||
var config1 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config1.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectPUT('http://ironic.example.com:1000/nodes/test_id/states/provision')
|
||||
.respond(202);
|
||||
var result1 = IronicNodeProvision.update(testManageBody);
|
||||
expect(result1.$promise).toBeDefined();
|
||||
expect(result1.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result1.$resolved).toBeTruthy();
|
||||
expect(result1.node_ident).toBe(testManageBody.node_ident);
|
||||
expect(result1.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch configs.
|
||||
var config2 = $$selectedConfiguration.set('test_config_2');
|
||||
$rootScope.$apply();
|
||||
expect(config2.ironic.apiRoot).toBe('http://ironic.example.com:2000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectPUT('http://ironic.example.com:2000/nodes/test_id/states/provision')
|
||||
.respond(202);
|
||||
var result2 = IronicNodeProvision.update(testManageBody);
|
||||
expect(result2.$promise).toBeDefined();
|
||||
expect(result2.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result2.$resolved).toBeTruthy();
|
||||
expect(result2.node_ident).toBe(testManageBody.node_ident);
|
||||
expect(result2.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch it back.
|
||||
var config3 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config3.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectPUT('http://ironic.example.com:1000/nodes/test_id/states/provision')
|
||||
.respond(202);
|
||||
var result3 = IronicNodeProvision.update(testManageBody);
|
||||
expect(result3.$promise).toBeDefined();
|
||||
expect(result3.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result3.$resolved).toBeTruthy();
|
||||
expect(result3.node_ident).toBe(testManageBody.node_ident);
|
||||
expect(result3.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should return a \'resource-like\' object',
|
||||
inject(function(IronicNodeProvision, $$selectedConfiguration) {
|
||||
// Select #1
|
||||
var config1 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config1.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectPUT('http://ironic.example.com:1000/nodes/test_id/states/provision')
|
||||
.respond(202);
|
||||
var result1 = IronicNodeProvision.update(testManageBody);
|
||||
expect(result1.$promise).toBeDefined();
|
||||
expect(result1.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result1.$resolved).toBeTruthy();
|
||||
expect(result1.node_ident).toBe(testManageBody.node_ident);
|
||||
expect(result1.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should return a failed resource if an invalid config has been selected',
|
||||
inject(function(IronicNodeProvision) {
|
||||
var updateResult = IronicNodeProvision.update(testManageBody);
|
||||
expect(angular.isObject(updateResult)).toBeTruthy();
|
||||
expect(updateResult.$promise).toBeDefined();
|
||||
expect(updateResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(updateResult.$resolved).toBeTruthy();
|
||||
expect(updateResult.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse error responses',
|
||||
inject(function(IronicNodeProvision, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectPUT('http://ironic.example.com:1000/nodes/test_id/states/provision')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicNodeProvision.update(testManageBody);
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
});
|
||||
});
|
@ -1,159 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's ngResource IronicNode implementation.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Node Resource',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope;
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
}));
|
||||
|
||||
/**
|
||||
* Assertion helper, make sure a list of transitions contains one we're looking for.
|
||||
*
|
||||
* @param {Array} transitions The transitions array to check.
|
||||
* @param {String} from The name of the originating state.
|
||||
* @param {String} actor The name of the actor.
|
||||
* @param {String} action The name of the transition action name.
|
||||
* @param {String} target The name of the target state.
|
||||
* @return {void}
|
||||
*/
|
||||
function assertHasTransition (transitions, from, actor, action, target) {
|
||||
expect(transitions).toContain({
|
||||
from_state: from,
|
||||
event: action,
|
||||
target_state: target,
|
||||
actor: actor
|
||||
});
|
||||
}
|
||||
|
||||
it('should implement the query method',
|
||||
inject(function(IronicNodeProvisionTransition) {
|
||||
expect(IronicNodeProvisionTransition.query).toBeDefined();
|
||||
|
||||
// CRUD methods not supported on this resource.
|
||||
expect(IronicNodeProvisionTransition.create).not.toBeDefined();
|
||||
expect(IronicNodeProvisionTransition.read).not.toBeDefined();
|
||||
expect(IronicNodeProvisionTransition.update).not.toBeDefined();
|
||||
expect(IronicNodeProvisionTransition.remove).not.toBeDefined();
|
||||
}));
|
||||
|
||||
it('should return a "resource-like" array"',
|
||||
inject(function(IronicNodeProvisionTransition) {
|
||||
var transitions = IronicNodeProvisionTransition.query();
|
||||
$rootScope.$apply();
|
||||
expect(transitions.$resolved).toBeTruthy();
|
||||
expect(transitions.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should permit filtering.',
|
||||
inject(function(IronicNodeProvisionTransition) {
|
||||
var transitions = IronicNodeProvisionTransition.query({
|
||||
from_state: 'manageable'
|
||||
});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(transitions.length).toEqual(3);
|
||||
|
||||
var conductorTransitions = IronicNodeProvisionTransition.query({
|
||||
from_state: 'manageable',
|
||||
actor: 'conductor'
|
||||
});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(conductorTransitions.length).toEqual(0);
|
||||
}));
|
||||
|
||||
it('should permit query promise handlers.',
|
||||
inject(function(IronicNodeProvisionTransition) {
|
||||
var success = false;
|
||||
IronicNodeProvisionTransition.query({
|
||||
from_state: 'manageable'
|
||||
}, function() {
|
||||
success = true;
|
||||
});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(success).toBeTruthy();
|
||||
}));
|
||||
|
||||
it('should return the expected transition graph.',
|
||||
inject(function(IronicNodeProvisionTransition) {
|
||||
var transitions = IronicNodeProvisionTransition.query();
|
||||
$rootScope.$apply();
|
||||
|
||||
var USER = "user";
|
||||
var CONDUCTOR = "conductor";
|
||||
|
||||
// ENROLL state
|
||||
assertHasTransition(transitions, "enroll", USER, "manage", "verifying");
|
||||
|
||||
// VERIFYING state
|
||||
assertHasTransition(transitions, "verifying", CONDUCTOR, "done", "manageable");
|
||||
assertHasTransition(transitions, "verifying", CONDUCTOR, "fail", "enroll");
|
||||
|
||||
// MANAGEABLE state
|
||||
assertHasTransition(transitions, "manageable", USER, "provide", "cleaning");
|
||||
assertHasTransition(transitions, "manageable", USER, "clean", "cleaning");
|
||||
assertHasTransition(transitions, "manageable", USER, "inspect", "inspecting");
|
||||
|
||||
// INSPECTING state
|
||||
assertHasTransition(transitions, "inspecting", CONDUCTOR, "done", "manageable");
|
||||
assertHasTransition(transitions, "inspecting", CONDUCTOR, "fail", "inspect failed");
|
||||
|
||||
// INSPECT FAILED state
|
||||
assertHasTransition(transitions, "inspect failed", USER, "inspect", "inspecting");
|
||||
assertHasTransition(transitions, "inspect failed", USER, "manage", "manageable");
|
||||
|
||||
// CLEANING state
|
||||
assertHasTransition(transitions, "cleaning", CONDUCTOR, "manage", "manageable");
|
||||
assertHasTransition(transitions, "cleaning", CONDUCTOR, "wait", "clean wait");
|
||||
assertHasTransition(transitions, "cleaning", CONDUCTOR, "fail", "clean failed");
|
||||
assertHasTransition(transitions, "cleaning", CONDUCTOR, "done", "available");
|
||||
|
||||
// CLEAN WAIT state
|
||||
assertHasTransition(transitions, "clean wait", CONDUCTOR, "resume", "cleaning");
|
||||
assertHasTransition(transitions, "clean wait", CONDUCTOR, "abort", "clean failed");
|
||||
assertHasTransition(transitions, "clean wait", CONDUCTOR, "fail", "clean failed");
|
||||
|
||||
// CLEAN FAILED state
|
||||
assertHasTransition(transitions, "clean failed", USER, "manage", "manageable");
|
||||
|
||||
// AVAILABLE state
|
||||
assertHasTransition(transitions, "available", USER, "manage", "manageable");
|
||||
assertHasTransition(transitions, "available", USER, "active", "deploying");
|
||||
|
||||
// DEPLOYING state
|
||||
assertHasTransition(transitions, "deploying", CONDUCTOR, "wait", "wait call-back");
|
||||
assertHasTransition(transitions, "deploying", CONDUCTOR, "done", "active");
|
||||
assertHasTransition(transitions, "deploying", CONDUCTOR, "fail", "deploy failed");
|
||||
|
||||
// ACTIVE state
|
||||
assertHasTransition(transitions, "active", USER, "rebuild", "deploying");
|
||||
assertHasTransition(transitions, "active", USER, "delete", "deleting");
|
||||
|
||||
// DEPLOY FAILED state
|
||||
assertHasTransition(transitions, "deploy failed", USER, "rebuild", "deploying");
|
||||
assertHasTransition(transitions, "deploy failed", USER, "active", "deploying");
|
||||
assertHasTransition(transitions, "deploy failed", USER, "delete", "deleting");
|
||||
|
||||
// WAIT CALL_BACK state
|
||||
assertHasTransition(transitions, "wait call-back", CONDUCTOR, "resume", "deploying");
|
||||
assertHasTransition(transitions, "wait call-back", CONDUCTOR, "delete", "deleting");
|
||||
|
||||
// DELETING state
|
||||
assertHasTransition(transitions, "deleting", CONDUCTOR, "error", "error");
|
||||
assertHasTransition(transitions, "deleting", CONDUCTOR, "clean", "cleaning");
|
||||
|
||||
// ERROR state
|
||||
assertHasTransition(transitions, "error", USER, "delete", "deleting");
|
||||
assertHasTransition(transitions, "error", USER, "rebuild", "deploying");
|
||||
}));
|
||||
});
|
@ -1,217 +0,0 @@
|
||||
/**
|
||||
* Unit tests for ironic's ngResource IronicPort implementation.
|
||||
*/
|
||||
describe('Unit: OpenStack Ironic Port Resource',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope, $httpBackend;
|
||||
|
||||
// Load common configuration mocks.
|
||||
beforeEach(module('openstack.mock.$$configuration'));
|
||||
|
||||
// We are testing the ironic.api module.
|
||||
beforeEach(module('ironic.api'));
|
||||
|
||||
beforeEach(inject(function($injector) {
|
||||
// Set up the mock http service
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
it('should implement a basic CRUD interface',
|
||||
inject(function(IronicPort) {
|
||||
expect(IronicPort.query).toBeDefined();
|
||||
expect(IronicPort.create).toBeDefined();
|
||||
expect(IronicPort.read).toBeDefined();
|
||||
expect(IronicPort.update).toBeDefined();
|
||||
expect(IronicPort.remove).toBeDefined();
|
||||
}));
|
||||
|
||||
it('should switch API requests if the configuration changes.',
|
||||
inject(function(IronicPort, $$selectedConfiguration) {
|
||||
|
||||
// Select #1
|
||||
var config1 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config1.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/ports')
|
||||
.respond(200, {ports: [{}]});
|
||||
var result1 = IronicPort.query({});
|
||||
expect(result1.$promise).toBeDefined();
|
||||
expect(result1.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result1.$resolved).toBeTruthy();
|
||||
expect(result1.length).toBe(1);
|
||||
expect(result1.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch configs.
|
||||
var config2 = $$selectedConfiguration.set('test_config_2');
|
||||
$rootScope.$apply();
|
||||
expect(config2.ironic.apiRoot).toBe('http://ironic.example.com:2000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:2000/ports')
|
||||
.respond(200, {ports: [{}, {}]});
|
||||
var result2 = IronicPort.query({});
|
||||
expect(result2.$promise).toBeDefined();
|
||||
expect(result2.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result2.$resolved).toBeTruthy();
|
||||
expect(result2.length).toBe(2);
|
||||
expect(result2.$promise.$$state.status).toBe(1);
|
||||
|
||||
// Switch it back.
|
||||
var config3 = $$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
expect(config3.ironic.apiRoot).toBe('http://ironic.example.com:1000');
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expect('GET', 'http://ironic.example.com:1000/ports')
|
||||
.respond(200, {ports: [{}]});
|
||||
var result3 = IronicPort.query({});
|
||||
expect(result3.$promise).toBeDefined();
|
||||
expect(result3.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result3.$resolved).toBeTruthy();
|
||||
expect(result3.length).toBe(1);
|
||||
expect(result3.$promise.$$state.status).toBe(1);
|
||||
}));
|
||||
|
||||
it('should return a failed resource if an invalid config has been selected',
|
||||
inject(function(IronicPort) {
|
||||
var queryResult = IronicPort.query({id: 'meaningless'});
|
||||
expect(angular.isArray(queryResult)).toBeTruthy();
|
||||
expect(queryResult.$promise).toBeDefined();
|
||||
expect(queryResult.$resolved).toBeFalsy();
|
||||
|
||||
var createResult = IronicPort.create({id: 'meaningless'});
|
||||
expect(angular.isObject(createResult)).toBeTruthy();
|
||||
expect(createResult.$promise).toBeDefined();
|
||||
expect(createResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(createResult.$resolved).toBeTruthy();
|
||||
expect(createResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var updateResult = IronicPort.update({id: 'meaningless'});
|
||||
expect(angular.isObject(updateResult)).toBeTruthy();
|
||||
expect(updateResult.$promise).toBeDefined();
|
||||
expect(updateResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(updateResult.$resolved).toBeTruthy();
|
||||
expect(updateResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var readResult = IronicPort.read({id: 'meaningless'});
|
||||
expect(angular.isObject(readResult)).toBeTruthy();
|
||||
expect(readResult.$promise).toBeDefined();
|
||||
expect(readResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(readResult.$resolved).toBeTruthy();
|
||||
expect(readResult.$promise.$$state.status).toBe(2);
|
||||
|
||||
var removeResult = IronicPort.remove({id: 'meaningless'});
|
||||
expect(angular.isObject(removeResult)).toBeTruthy();
|
||||
expect(removeResult.$promise).toBeDefined();
|
||||
expect(removeResult.$resolved).toBeFalsy();
|
||||
|
||||
$rootScope.$apply();
|
||||
expect(removeResult.$resolved).toBeTruthy();
|
||||
expect(removeResult.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse query error responses',
|
||||
inject(function(IronicPort, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/ports')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicPort.query({});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD regular responses',
|
||||
inject(function(IronicPort, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/ports/1')
|
||||
.respond(200, {uuid: 1});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicPort.read({uuid: 1});
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(1);
|
||||
expect(result.uuid).toBe(1);
|
||||
}));
|
||||
|
||||
it('should correctly parse CRUD error responses',
|
||||
inject(function(IronicPort, $$selectedConfiguration) {
|
||||
$$selectedConfiguration.set('test_config_1');
|
||||
$rootScope.$apply();
|
||||
|
||||
// Try a request
|
||||
$httpBackend.expectGET('http://ironic.example.com:1000/ports/1')
|
||||
.respond(400, {
|
||||
error_message: angular.toJson({
|
||||
debuginfo: null,
|
||||
faultcode: 'Client',
|
||||
faultstring: 'Test fault string'
|
||||
})
|
||||
});
|
||||
|
||||
// Issue a request and attach a listener for the error response.
|
||||
var result = IronicPort.read({uuid: 1});
|
||||
result.$promise.then(function() {
|
||||
expect(true).toBeFalsy(); // This must fail, we're checking for an error.
|
||||
}, function(error) {
|
||||
expect(error.data.error_message.faultcode).toBe('Client');
|
||||
});
|
||||
|
||||
// Check and resolve the promise.
|
||||
expect(result.$promise).toBeDefined();
|
||||
expect(result.$resolved).toBeFalsy();
|
||||
$httpBackend.flush();
|
||||
expect(result.$resolved).toBeTruthy();
|
||||
expect(result.$promise.$$state.status).toBe(2);
|
||||
}));
|
||||
});
|
@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Unit tests for the ironic api module.
|
||||
*/
|
||||
describe('Unit: Ironic.API Module',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $rootScope;
|
||||
|
||||
beforeEach(module('ironic.api'));
|
||||
beforeEach(module(function($$configurationProvider) {
|
||||
$$configurationProvider.$enableDefault(true);
|
||||
}));
|
||||
beforeEach(inject(function($injector) {
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
}));
|
||||
|
||||
it('should exist', function() {
|
||||
expect(angular.module('ironic.api')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should automatically register a root API endpoint with $$configuration',
|
||||
inject(function($$configuration) {
|
||||
var config = $$configuration.read('default');
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(config.id).toBe('default');
|
||||
expect(config.ironic).toBeDefined();
|
||||
expect(config.ironic.apiRoot).toBeDefined();
|
||||
|
||||
// Localhost is where we're running these tests.
|
||||
expect(config.ironic.apiRoot).toBe('http://localhost:6385');
|
||||
})
|
||||
);
|
||||
});
|
@ -1,364 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for the provision action modal controller.
|
||||
*/
|
||||
describe('ProvisionActionModalController',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $controller, $httpBackend, mockInjectionProperties, $rootScope;
|
||||
|
||||
beforeEach(function() {
|
||||
module('ironic.api.mock.IronicNode');
|
||||
module('template.mock');
|
||||
module('ironic');
|
||||
});
|
||||
|
||||
beforeEach(inject(function(_$controller_, $injector) {
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$controller = _$controller_;
|
||||
|
||||
mockInjectionProperties = {
|
||||
$scope: {},
|
||||
$uibModalInstance: {
|
||||
close: function() {
|
||||
},
|
||||
dismiss: function() {
|
||||
}
|
||||
},
|
||||
actionName: 'manage',
|
||||
nodeIds: ['test_node_1', 'test_node_2']
|
||||
};
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
describe('Controller Properties', function() {
|
||||
|
||||
afterEach(function() {
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it('does not pollute the $scope',
|
||||
function() {
|
||||
$controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(mockInjectionProperties.$scope).toEqual({});
|
||||
});
|
||||
|
||||
it('starts with the updating flag disabled',
|
||||
function() {
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.updating).toBeFalsy();
|
||||
});
|
||||
|
||||
it('starts with the someUpdated flag disabled',
|
||||
function() {
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
});
|
||||
|
||||
it('starts with the someNodesExcluded flag disabled',
|
||||
function() {
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.someNodesExcluded).toBeFalsy();
|
||||
});
|
||||
|
||||
it('starts with an empty, unresolved list of nodes',
|
||||
function() {
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.nodes).toBeDefined();
|
||||
expect(controller.nodes.$resolved).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Applies the action name to the controller scope',
|
||||
function() {
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.actionName).toBe('manage');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Controller Initialization', function() {
|
||||
it('Initializes the controller with a resolving list of nodes', function() {
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.nodes).toBeDefined();
|
||||
expect(controller.nodes.length).toBe(0);
|
||||
expect(controller.nodes.$resolved).toBeFalsy();
|
||||
expect(controller.nodes.$promise).toBeDefined();
|
||||
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.nodes.length).toBe(2);
|
||||
expect(controller.nodes.$resolved).toBeTruthy();
|
||||
expect(controller.someNodesExcluded).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Creates a context object for each passed node',
|
||||
function() {
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.nodes.length).toBe(2);
|
||||
angular.forEach(controller.nodes, function(ctx) {
|
||||
expect(ctx.node).toBeDefined();
|
||||
expect(ctx.error).toBeNull();
|
||||
expect(ctx.changed).toBe(false);
|
||||
expect(ctx.state).toBe('ready');
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not activate the someExcluded flag if all nodes are valid',
|
||||
function() {
|
||||
mockInjectionProperties.nodeIds = ['test_node_1', 'test_node_2'];
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.nodes.length).toBe(2);
|
||||
expect(controller.someNodesExcluded).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Should activate the someExcluded flag if invalid node states are detected',
|
||||
function() {
|
||||
mockInjectionProperties.nodeIds = ['test_node_1', 'test_node_3'];
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.nodes.length).toBe(1);
|
||||
expect(controller.someNodesExcluded).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('apply()', function() {
|
||||
|
||||
var mockError = {
|
||||
error_message: {
|
||||
faultstring: "faultstring",
|
||||
faultcode: "faultcode"
|
||||
}
|
||||
};
|
||||
|
||||
it('modifies nothing if invoked with no nodes.',
|
||||
function() {
|
||||
mockInjectionProperties.nodeIds = [];
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
|
||||
controller.apply();
|
||||
$rootScope.$apply(); // Resolve promises
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
});
|
||||
|
||||
it('dismisses the modal if invoked with no nodes.',
|
||||
function() {
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
mockInjectionProperties.nodeIds = [];
|
||||
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
controller.apply();
|
||||
expect(controller.updating).toBeTruthy();
|
||||
$rootScope.$apply();
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(spyDismiss.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
it('correctly flips the updating flag',
|
||||
function() {
|
||||
// Preload the controller
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_1/states/provision')
|
||||
.respond(202);
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_2/states/provision')
|
||||
.respond(202);
|
||||
expect(controller.updating).toBeFalsy();
|
||||
controller.apply();
|
||||
expect(controller.updating).toBeTruthy();
|
||||
$httpBackend.flush();
|
||||
expect(controller.updating).toBeFalsy();
|
||||
});
|
||||
|
||||
it('flips the someUpdated flag if some nodes are updated and others are not',
|
||||
function() {
|
||||
// Preload the controller
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_1/states/provision')
|
||||
.respond(400, {});
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_2/states/provision')
|
||||
.respond(202);
|
||||
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
controller.apply();
|
||||
expect(controller.nodes[0].state).toBe('updating');
|
||||
expect(controller.nodes[1].state).toBe('updating');
|
||||
expect(controller.updating).toBeTruthy();
|
||||
$httpBackend.flush();
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeTruthy();
|
||||
|
||||
expect(controller.nodes[0].state).toBe('error');
|
||||
expect(controller.nodes[1].state).toBe('complete');
|
||||
expect(spyDismiss.calls.count()).toEqual(0);
|
||||
expect(spyClose.calls.count()).toEqual(0);
|
||||
});
|
||||
|
||||
it('changes a node\'s context state to "updating" and "complete".',
|
||||
function() {
|
||||
// Preload the controller
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_1/states/provision')
|
||||
.respond(202);
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_2/states/provision')
|
||||
.respond(202);
|
||||
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
controller.apply();
|
||||
expect(controller.nodes[0].state).toBe('updating');
|
||||
expect(controller.nodes[1].state).toBe('updating');
|
||||
expect(controller.updating).toBeTruthy();
|
||||
$httpBackend.flush();
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeTruthy();
|
||||
expect(controller.nodes[0].state).toBe('complete');
|
||||
expect(controller.nodes[1].state).toBe('complete');
|
||||
});
|
||||
|
||||
it('Correctly reports a returned error if a request fails.',
|
||||
function() {
|
||||
// Preload the controller
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_1/states/provision')
|
||||
.respond(400, mockError);
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_2/states/provision')
|
||||
.respond(400, mockError);
|
||||
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
controller.apply();
|
||||
expect(controller.nodes[0].state).toBe('updating');
|
||||
expect(controller.nodes[1].state).toBe('updating');
|
||||
expect(controller.updating).toBeTruthy();
|
||||
$httpBackend.flush();
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
expect(controller.nodes[0].state).toBe('error');
|
||||
expect(controller.nodes[0].error).toBeDefined();
|
||||
expect(controller.nodes[1].state).toBe('error');
|
||||
expect(controller.nodes[1].error).toBeDefined();
|
||||
});
|
||||
|
||||
it('invokes $uibModalInstance.close() if all nodes have been updated.',
|
||||
function() {
|
||||
// Preload the controller
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_1/states/provision')
|
||||
.respond(202);
|
||||
$httpBackend
|
||||
.expectPUT('http://ironic.example.com:1000/nodes/test_node_2/states/provision')
|
||||
.respond(202);
|
||||
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeFalsy();
|
||||
controller.apply();
|
||||
expect(controller.nodes[0].state).toBe('updating');
|
||||
expect(controller.nodes[1].state).toBe('updating');
|
||||
expect(controller.updating).toBeTruthy();
|
||||
$httpBackend.flush();
|
||||
expect(controller.updating).toBeFalsy();
|
||||
expect(controller.someUpdated).toBeTruthy();
|
||||
expect(controller.nodes[0].state).toBe('complete');
|
||||
expect(controller.nodes[1].state).toBe('complete');
|
||||
|
||||
expect(spyDismiss.calls.count()).toEqual(0);
|
||||
expect(spyClose.calls.count()).toEqual(1);
|
||||
expect(spyClose.calls.mostRecent().args[0][0]).toEqual(controller.nodes[0].node.uuid);
|
||||
expect(spyClose.calls.mostRecent().args[0][1]).toEqual(controller.nodes[1].node.uuid);
|
||||
});
|
||||
});
|
||||
|
||||
describe('close()', function() {
|
||||
it('invokes dismiss() if nothing updated',
|
||||
function() {
|
||||
// Preload the controller
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
|
||||
controller.someUpdated = false;
|
||||
controller.close();
|
||||
|
||||
expect(spyDismiss.calls.count()).toEqual(1);
|
||||
expect(spyClose.calls.count()).toEqual(0);
|
||||
});
|
||||
|
||||
it('invokes close() with updated nodes if something updated',
|
||||
function() {
|
||||
// Preload the controller
|
||||
var controller = $controller('ProvisionActionModalController', mockInjectionProperties);
|
||||
$httpBackend.flush();
|
||||
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
|
||||
controller.someUpdated = true;
|
||||
controller.nodes[0].state = 'complete';
|
||||
controller.nodes[0].changed = true;
|
||||
controller.close();
|
||||
|
||||
expect(spyDismiss.calls.count()).toEqual(0);
|
||||
expect(spyClose.calls.count()).toEqual(1);
|
||||
expect(spyClose.calls.mostRecent().args[0]).toEqual([controller.nodes[0].node.uuid]);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,262 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for the RemoveNodeModalController.
|
||||
*/
|
||||
describe('RemoveNodeModalController',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $controller, $httpBackend, mockInjectionProperties, $rootScope, $q;
|
||||
|
||||
beforeEach(function() {
|
||||
module('ironic.api.mock.IronicNode');
|
||||
module('template.mock');
|
||||
module('ironic');
|
||||
|
||||
mockInjectionProperties = {
|
||||
$scope: {},
|
||||
$uibModalInstance: {
|
||||
close: function() {
|
||||
},
|
||||
dismiss: function() {
|
||||
}
|
||||
},
|
||||
nodes: []
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(inject(function(_$controller_, $injector) {
|
||||
$httpBackend = $injector.get('$httpBackend');
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$q = $injector.get('$q');
|
||||
$controller = _$controller_;
|
||||
}));
|
||||
|
||||
afterEach(inject(function($$persistentStorage) {
|
||||
// Clear any config selections we've made.
|
||||
$$persistentStorage.remove('$$selectedConfiguration');
|
||||
|
||||
// Assert no outstanding requests.
|
||||
$httpBackend.verifyNoOutstandingExpectation();
|
||||
$httpBackend.verifyNoOutstandingRequest();
|
||||
}));
|
||||
|
||||
describe('Controller Properties', function() {
|
||||
it('does not pollute the $scope',
|
||||
function() {
|
||||
$controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(mockInjectionProperties.$scope).toEqual({});
|
||||
});
|
||||
|
||||
it('starts not deleting anything',
|
||||
function() {
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
});
|
||||
|
||||
it('starts not having deleted anything',
|
||||
function() {
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Creates a scope object for each passed node',
|
||||
function() {
|
||||
mockInjectionProperties.nodes = [{node: 'node1'}, {node: 'node2'}];
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
|
||||
expect(controller.nodes.length).toBe(2);
|
||||
angular.forEach(controller.nodes, function(ctx) {
|
||||
expect(ctx.node).toBeDefined();
|
||||
expect(ctx.error).toBeNull();
|
||||
expect(ctx.state).toBe('present');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('close()', function() {
|
||||
it('invokes dismiss() if nothing deleted',
|
||||
function() {
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
controller.someDeleted = false;
|
||||
controller.close();
|
||||
|
||||
expect(spyDismiss.calls.count()).toEqual(1);
|
||||
expect(spyClose.calls.count()).toEqual(0);
|
||||
});
|
||||
|
||||
it('invokes close() if something deleted',
|
||||
function() {
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
controller.someDeleted = true;
|
||||
controller.close();
|
||||
|
||||
expect(spyDismiss.calls.count()).toEqual(0);
|
||||
expect(spyClose.calls.count()).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove()', function() {
|
||||
|
||||
var mockError = {
|
||||
data: {
|
||||
error_message: {
|
||||
faultstring: "faultstring",
|
||||
faultcode: "faultcode"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function removeMock (success) {
|
||||
return function(successHandler, failureHandler) {
|
||||
var promise = success ? $q.resolve() : $q.reject(mockError);
|
||||
promise.then(successHandler, failureHandler);
|
||||
return promise;
|
||||
};
|
||||
}
|
||||
|
||||
it('deletes nothing if invoked with no nodes.',
|
||||
function() {
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
|
||||
controller.remove();
|
||||
$rootScope.$apply(); // Resolve promises
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
});
|
||||
|
||||
it('dismisses the modal if invoked with no nodes..',
|
||||
function() {
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
controller.remove();
|
||||
expect(controller.deleting).toBeTruthy();
|
||||
$rootScope.$apply(); // Resolve promises
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(spyDismiss.calls.count()).toEqual(1);
|
||||
});
|
||||
|
||||
it('correctly flips the deleting flag',
|
||||
function() {
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
controller.remove();
|
||||
expect(controller.deleting).toBeTruthy();
|
||||
$rootScope.$apply(); // Resolve promises
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
});
|
||||
|
||||
it('flips the someDeleted flag if some nodes are deleted and others are not',
|
||||
function() {
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
mockInjectionProperties.nodes = [
|
||||
{$remove: removeMock(true)},
|
||||
{$remove: removeMock(false)}
|
||||
];
|
||||
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
controller.remove();
|
||||
expect(controller.nodes[0].state).toBe('removing');
|
||||
expect(controller.nodes[1].state).toBe('removing');
|
||||
expect(controller.deleting).toBeTruthy();
|
||||
$rootScope.$apply();
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeTruthy();
|
||||
|
||||
expect(controller.nodes[0].state).toBe('removed');
|
||||
expect(controller.nodes[1].state).toBe('error');
|
||||
expect(spyDismiss.calls.count()).toEqual(0);
|
||||
expect(spyClose.calls.count()).toEqual(0);
|
||||
});
|
||||
|
||||
it('changes a node\'s context state to "removing" and "removed".',
|
||||
function() {
|
||||
mockInjectionProperties.nodes = [
|
||||
{$remove: removeMock(true)}
|
||||
];
|
||||
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
controller.remove();
|
||||
expect(controller.nodes[0].state).toBe('removing');
|
||||
expect(controller.deleting).toBeTruthy();
|
||||
$rootScope.$apply();
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeTruthy();
|
||||
expect(controller.nodes[0].state).toBe('removed');
|
||||
});
|
||||
|
||||
it('Correctly reports a returned error if a node is not deleted.',
|
||||
function() {
|
||||
mockInjectionProperties.nodes = [
|
||||
{$remove: removeMock(false)}
|
||||
];
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
controller.remove();
|
||||
expect(controller.nodes[0].state).toBe('removing');
|
||||
expect(controller.deleting).toBeTruthy();
|
||||
$rootScope.$apply();
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
expect(controller.nodes[0].state).toBe('error');
|
||||
expect(controller.nodes[0].error).toBeDefined();
|
||||
});
|
||||
|
||||
it('invokes $uibModalInstance.close() if all nodes have been deleted.',
|
||||
function() {
|
||||
var spyDismiss = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var spyClose = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
mockInjectionProperties.nodes = [
|
||||
{$remove: removeMock(true)},
|
||||
{$remove: removeMock(true)}
|
||||
];
|
||||
|
||||
var controller = $controller('RemoveNodeModalController', mockInjectionProperties);
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeFalsy();
|
||||
controller.remove();
|
||||
expect(controller.nodes[0].state).toBe('removing');
|
||||
expect(controller.nodes[1].state).toBe('removing');
|
||||
expect(controller.deleting).toBeTruthy();
|
||||
$rootScope.$apply();
|
||||
expect(controller.deleting).toBeFalsy();
|
||||
expect(controller.someDeleted).toBeTruthy();
|
||||
expect(controller.nodes[0].state).toBe('removed');
|
||||
expect(controller.nodes[1].state).toBe('removed');
|
||||
|
||||
expect(spyDismiss.calls.count()).toEqual(0);
|
||||
expect(spyClose.calls.count()).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Hewlett Packard Enterprise Development Company, LP
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for the unknown action modal controller.
|
||||
*/
|
||||
describe('Unit: Ironic-webclient UnknownActionModalController',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $controller;
|
||||
var mockInjectionProperties = {
|
||||
$scope: {},
|
||||
$uibModalInstance: {
|
||||
close: function() {
|
||||
},
|
||||
dismiss: function() {
|
||||
}
|
||||
},
|
||||
actionName: 'test'
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
module('template.mock');
|
||||
module('ironic');
|
||||
});
|
||||
|
||||
beforeEach(inject(function(_$controller_) {
|
||||
$controller = _$controller_;
|
||||
}));
|
||||
|
||||
describe('Controller Properties', function() {
|
||||
it('does not pollute the $scope',
|
||||
function() {
|
||||
$controller('UnknownActionModalController', mockInjectionProperties);
|
||||
expect(mockInjectionProperties.$scope).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Controller Initialization', function() {
|
||||
|
||||
it('passes the actionName to the controller scope',
|
||||
function() {
|
||||
var controller = $controller('UnknownActionModalController', mockInjectionProperties);
|
||||
expect(controller.actionName).toEqual('test');
|
||||
});
|
||||
});
|
||||
|
||||
describe('$scope.close', function() {
|
||||
it('calls dismiss when close() is called.',
|
||||
function() {
|
||||
var spy = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var controller = $controller('UnknownActionModalController', mockInjectionProperties);
|
||||
|
||||
controller.close();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.calls.count()).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,98 +0,0 @@
|
||||
/**
|
||||
* Unit tests for the application root module.
|
||||
*/
|
||||
describe('Unit: Ironic-webclient Add-Configuration Controller',
|
||||
function() {
|
||||
'use strict';
|
||||
|
||||
var $controller;
|
||||
var mockInjectionProperties = {
|
||||
$scope: {},
|
||||
$uibModalInstance: {
|
||||
close: function() {
|
||||
},
|
||||
dismiss: function() {
|
||||
}
|
||||
},
|
||||
configuration: [{id: 'test'}]
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
// Load the ironic module.
|
||||
module('ironic');
|
||||
|
||||
// Load the controller provider.
|
||||
inject(function(_$controller_) {
|
||||
$controller = _$controller_;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Controller Properties', function() {
|
||||
it('does not pollute the $scope', function() {
|
||||
var $scope = {};
|
||||
$controller('ConfigurationAddController', mockInjectionProperties);
|
||||
expect($scope).toEqual({});
|
||||
});
|
||||
|
||||
it('sets the configuration property to the injected configuration',
|
||||
function() {
|
||||
var controller = $controller('ConfigurationAddController', mockInjectionProperties);
|
||||
expect(controller.configuration).toBe(mockInjectionProperties.configuration);
|
||||
});
|
||||
|
||||
it('sets the newConfiguration property to a valid cloud configuration with an ironic apiBase',
|
||||
function() {
|
||||
var controller = $controller('ConfigurationAddController', mockInjectionProperties);
|
||||
expect(controller.newConfiguration.ironic).toEqual({apiRoot: ''});
|
||||
expect(controller.newConfiguration.name).toBeDefined();
|
||||
});
|
||||
|
||||
it('sets the $scope.location to a hash of the current URL',
|
||||
inject(function($location) {
|
||||
spyOn($location, 'host').and.returnValue('example.com');
|
||||
spyOn($location, 'protocol').and.returnValue('https');
|
||||
spyOn($location, 'port').and.returnValue(1234);
|
||||
|
||||
var controller = $controller('ConfigurationAddController', mockInjectionProperties);
|
||||
expect(controller.location).toEqual({
|
||||
host: 'example.com',
|
||||
protocol: 'https',
|
||||
port: 1234
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe('$scope.close', function() {
|
||||
it('calls dismiss when close() is called.',
|
||||
function() {
|
||||
var spy = spyOn(mockInjectionProperties.$uibModalInstance, 'dismiss');
|
||||
var controller = $controller('ConfigurationAddController', mockInjectionProperties);
|
||||
controller.close();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.calls.count()).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('$scope.save', function() {
|
||||
it('resolves the modal promise with a valid configuration when close() is called',
|
||||
function() {
|
||||
var spy = spyOn(mockInjectionProperties.$uibModalInstance, 'close');
|
||||
var controller = $controller('ConfigurationAddController', mockInjectionProperties);
|
||||
|
||||
// Simulate form input
|
||||
controller.newConfiguration.name = 'Test Name';
|
||||
controller.save();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
|
||||
// The ID should have been automatically populated from the name, in order to ensure
|
||||
// the existence of a key.
|
||||
expect(spy.calls.mostRecent().args[0]).toEqual({
|
||||
id: 'Test Name',
|
||||
name: 'Test Name',
|
||||
ironic: {
|
||||
apiRoot: ''
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user