summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimur Sufiev <tsufiev@mirantis.com>2015-07-24 13:00:18 +0300
committerTimur Sufiev <tsufiev@mirantis.com>2015-08-05 10:12:11 +0000
commitb9e6ccb3eae763f88e8dc800cbe25bd7f748769c (patch)
tree5918a0a906b7d2e981e398d554baf4767bc83c46
parent7fc50585becb17c680bcbf299ba393c8bdc6581f (diff)
Initial import of data schema from Rackspace HotBuilder
Notes
Notes (review): Verified+2: Jenkins Code-Review+2: Timur Sufiev <tsufiev@mirantis.com> Workflow+1: Timur Sufiev <tsufiev@mirantis.com> Submitted-by: Jenkins Submitted-at: Wed, 05 Aug 2015 10:38:42 +0000 Reviewed-on: https://review.openstack.org/205478 Project: stackforge/merlin Branch: refs/heads/master
-rw-r--r--.eslintignore3
-rw-r--r--extensions/hotbuilder/static/hotbuilder/js/hotbuilder.models.js1125
2 files changed, 1123 insertions, 5 deletions
diff --git a/.eslintignore b/.eslintignore
index b36fc47..395e244 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
1merlin/static/merlin/libs 1merlin/static/merlin/libs
2merlin/static/merlin/js/custom-libs \ No newline at end of file 2merlin/static/merlin/js/custom-libs
3extensions/hotbuilder/static/hotbuilder/js/hotbuilder.models.js \ No newline at end of file
diff --git a/extensions/hotbuilder/static/hotbuilder/js/hotbuilder.models.js b/extensions/hotbuilder/static/hotbuilder/js/hotbuilder.models.js
index 249ea83..2e04bc8 100644
--- a/extensions/hotbuilder/static/hotbuilder/js/hotbuilder.models.js
+++ b/extensions/hotbuilder/static/hotbuilder/js/hotbuilder.models.js
@@ -1,10 +1,1127 @@
1/** 1// Copyright 2014 Rackspace
2 * Created by tsufiev on 2/24/15. 2//
3 */ 3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
4(function() { 14(function() {
5 'use strict'; 15 'use strict';
6 16
7 angular 17 angular
8 .module('hotbuilder'); 18 .module('hotbuilder')
19 .factory('ModelsService', ModelsService);
20
21 ModelsService.$inject = ['merlin.field.models', 'merlin.utils'];
22
23 function ModelsService(fields, utils) {
24 var hot = {};
25
26 var elementSchema,
27 rpElementSchema,
28 primitiveExtension = {
29 create: function (json, parameters) {
30 var self = Barricade.Primitive.create.call(this, json,
31 parameters);
32 hot.Primitive.call(self);
33 return self;
34 }
35 };
36
37 hot.Primitive = Barricade.Blueprint.create(function () {});
38
39 hot.Primitive._schema = {}; // QUICK HACK
40
41 hot.Primitive.Factory = function (json, parameters) {
42 var type = Barricade.getType(json);
43
44 if (json === undefined || type === String) {
45 return hot.Primitive.string.create(json, parameters);
46 } else if (type === Boolean) {
47 return hot.Primitive.bool.create(json, parameters);
48 } else if (type === Number) {
49 return hot.Primitive.number.create(json, parameters);
50 } else if (type === Array) {
51 return hot.Primitive.array.create(json, parameters);
52 } else if (type === Object) {
53 return hot.Primitive.object.create(json, parameters);
54 }
55 };
56
57 elementSchema = {
58 '@class': hot.Primitive,
59 '@factory': hot.Primitive.Factory
60 };
61
62 hot.Primitive.string = Barricade.Primitive.extend(primitiveExtension,
63 {'@type': String});
64 hot.Primitive.bool = Barricade.Primitive.extend(primitiveExtension,
65 {'@type': Boolean});
66 hot.Primitive.number = Barricade.Primitive.extend(primitiveExtension,
67 {'@type': Number});
68 hot.Primitive.array = Barricade.Array.extend({
69 create: function (json, parameters) {
70 var self = Barricade.Array.create.call(this, json, parameters);
71 hot.Primitive.call(self);
72 return self;
73 }
74 }, {
75 '@type': Array,
76 '*': elementSchema
77 });
78
79 hot.Primitive.object = Barricade.MutableObject.extend({
80 create: function (json, parameters) {
81 var self = Barricade.MutableObject
82 .create.call(this, json, parameters);
83 hot.Primitive.call(self);
84 return self;
85 }
86 }, {
87 '@type': Object,
88 '?': elementSchema
89 });
90
91 hot.ResourcePropertyWrapper = Barricade.Base.extend({
92 create: function (json, parameters) {
93 var self = this.extend({}),
94 value = hot.IntrinsicFunctionFactory(json, parameters);
95
96 if (!parameters) {
97 parameters = {};
98 }
99
100 Barricade.Observable.call(self);
101 Barricade.Identifiable.call(self, parameters.id);
102
103 if (value) {
104 self.setValue(value);
105 } else {
106 self.setValue(json, parameters);
107 }
108
109 return self;
110 },
111 getValue: function () {
112 return this._value;
113 },
114 setValue: function (newValue, newParameters) {
115 var self = this;
116
117 function onChange() { self.emit('change', this); }
118 function onChildChange() { self.emit('childChange', this); }
119 function onReplace(newVal) { self.setValue(newVal); }
120
121 if (this._value) {
122 this._value.emit('removeFrom', this);
123 }
124
125 if (this._safeInstanceof(newValue, hot.IntrinsicFunction) ||
126 this._safeInstanceof(newValue, this._innerClass)) {
127 this._value = newValue;
128 } else {
129 this._value = this._innerClass.create(newValue,
130 newParameters);
131 }
132
133 this._value.on('change', onChange);
134 this._value.on('childChange', onChildChange);
135 this._value.on('replace', onReplace);
136
137 this._value.on('removeFrom', function (container) {
138 self._value.off('change', onChange);
139 self._value.off('childChange', onChildChange);
140 self._value.off('replace', onReplace);
141 });
142
143 this.emit('change', 'set', this._value);
144 },
145 toNormal: function () {
146 this.setValue();
147 },
148 toIntrinsicFunction: function () {
149 this.setValue(hot.GetParameter.create());
150 },
151 hasDescription: function () {
152 return ('_description' in this) && !this._description.isEmpty();
153 },
154 getDescription: function () {
155 return this._description.get();
156 },
157 hasDependency: function () {
158 return this._value.hasDependency();
159 },
160 resolveWith: function (obj) {
161 return this.getValue().resolveWith(obj);
162 },
163 isEmpty: function () {
164 return !!this._value;
165 },
166 isUsed: function () {
167 return this.isRequired() || this._value.isUsed();
168 },
169 setIsUsed: function (isUsed) {
170 return this._value.setIsUsed(isUsed);
171 },
172 getIntrinsicFunctions: function () {
173 function searchValue(value) {
174 var intrinsics = [];
175 if (value.instanceof(hot.ResourcePropertyWrapper)) {
176 return value.getIntrinsicFunctions();
177 } else if (value.instanceof(hot.IntrinsicFunction)) {
178 if (value.instanceof(hot.StringReplace)) {
179 return [value].concat(value.getIntrinsicFunctions());
180 }
181 return [value];
182 } else if (value.instanceof(Barricade.Container)) {
183 value.each(function (i, element) {
184 intrinsics = intrinsics.concat(searchValue(element));
185 });
186 return intrinsics;
187 }
188 return [];
189 }
190 return searchValue(this.getValue());
191 },
192 toJSON: function (options) {
193 return this._value.toJSON(options);
194 }
195 });
196
197 // Extension for Resource properties that have schemaless containers
198 hot.Primitive.FactoryForResourceProperty = function (json, parameters) {
199 var type = Barricade.getType(json);
200
201 function getInnerClass() {
202 if (json === undefined || type === String) {
203 return hot.Primitive.string;
204 } else if (type === Boolean) {
205 return hot.Primitive.bool;
206 } else if (type === Number) {
207 return hot.Primitive.number;
208 } else if (type === Array) {
209 return hot.Primitive.arrayOfRP;
210 } else if (type === Object) {
211 return hot.Primitive.objectOfRP;
212 }
213 }
214
215 return hot.ResourcePropertyWrapper.extend({
216 _innerClass: getInnerClass()
217 }, {}).create(json, parameters);
218 };
219
220 rpElementSchema = {
221 '@class': hot.ResourcePropertyWrapper,
222 '@factory': hot.Primitive.FactoryForResourceProperty
223 };
224
225 hot.Primitive.arrayOfRP = hot.Primitive.array.extend({}, {
226 '*': rpElementSchema
227 });
228
229 hot.Primitive.objectOfRP = hot.Primitive.object.extend({}, {
230 '?': rpElementSchema
231 });
232
233 function constraintFactory(constraintObj) {
234 var types = {
235 'range': function (constraint) {
236 var min = constraint.min,
237 max = constraint.max;
238
239 function getMessage() {
240 if (min === undefined) {
241 return 'Value must be less than ' + max;
242 } else if (max === undefined) {
243 return 'Value must be greater than ' + min;
244 }
245 return 'Value must be between ' +
246 min + ' and ' + max;
247 }
248
249 return function (val) {
250 return ((min === undefined || val >= min) &&
251 (max === undefined || val <= max)) ||
252 getMessage();
253 };
254 },
255 'length': function (constraint) {
256 var min = constraint.min,
257 max = constraint.max;
258
259 function getMessage() {
260 if (min === undefined) {
261 return 'Must have fewer than ' +
262 max + ' letters';
263 } else if (max === undefined) {
264 return 'Must have more than ' +
265 min + ' letters';
266 }
267 return 'Must have between ' +
268 min + ' and ' + max + ' letters';
269 }
270
271 return function (val) {
272 return ((min === undefined || val.length >= min) &&
273 (max === undefined || val.length <= max)) ||
274 getMessage();
275 };
276 },
277 'allowed_values': function (constraint) {
278 return function (val) {
279 return (constraint.indexOf(val) > -1) ||
280 ('Value must be one of ' + constraint.join(', '));
281 };
282 },
283 'allowed_pattern': function (constraint) {
284 var regex = new RegExp(constraint);
285 return function (val) {
286 return regex.test(val) ||
287 ('Must match pattern: ' + constraint);
288 };
289 },
290 'custom_constraint': function () {
291 return function () { return true; };
292 }
293 };
294
295 for (var t in types) {
296 if (constraintObj.hasOwnProperty(t)) {
297 return types[t](constraintObj[t]);
298 }
299 }
300
301 console.log('Constraint type not found: ', constraintObj);
302 return function () { return true; };
303 }
304
305 hot.ResourcePropertyFactory = function (json, parameters) {
306 if (!json.hasOwnProperty('schema')) {
307 if (json.type === 'list') {
308 return hot.ResourceProperty_list2.create(json, parameters);
309 } else if (json.type === 'map') {
310 return hot.ResourceProperty_map2.create(json, parameters);
311 }
312 }
313 return hot['ResourceProperty_' + json.type].create(json, parameters);
314 };
315
316 hot.ResourceProperty = Barricade.ImmutableObject.extend({
317 getSchema: function () {
318 var schema = {},
319 wrapperSchema = {},
320 types = {
321 'map': Object,
322 'list': Array,
323 'string': String,
324 'number': Number,
325 'integer': Number,
326 'boolean': Boolean
327 };
328
329 wrapperSchema['@required'] = this.get('required').get();
330 schema['@type'] = types[this.get('type').get()];
331 schema['@required'] = this.get('required').get();
332 schema['@constraints'] =
333 this.get('constraints').get().map(constraintFactory);
334
335 if (schema['@type'] === Object) {
336 if (this.get('schema')) {
337 this.get('schema').each(function (i, prop) {
338 schema[prop.getID()] = prop.getSchema();
339 });
340 } else {
341 schema['?'] = rpElementSchema;
342 }
343 } else if (schema['@type'] === Array) {
344 if (this.get('schema')) {
345 schema['*'] = this.get('schema').get('*').getSchema();
346 } else {
347 schema['*'] = rpElementSchema;
348 }
349 }
350
351 return {
352 '@class': hot.ResourcePropertyWrapper.extend({
353 _innerClass: Barricade.create(schema),
354 _description: this.get('description')
355 }, wrapperSchema)
356 };
357 }
358 }, {
359 '@type': Object,
360 'type': {'@type': String},
361 'description': {'@type': String},
362 'required': {'@type': Boolean},
363 'constraints': {'@type': Array},
364 'update_allowed': {'@type': Boolean}
365 });
366
367 hot.ResourceProperty_map = hot.ResourceProperty.extend({}, {
368 'default': {'@type': Object},
369 'schema': {
370 '@type': Object,
371 '?': {
372 '@class': hot.ResourceProperty,
373 '@factory': hot.ResourcePropertyFactory
374 }
375 }
376 });
377
378 hot.ResourceProperty_list = hot.ResourceProperty.extend({}, {
379 'default': {'@type': Array},
380 'schema': {
381 '@type': Object,
382 '*': {
383 '@class': hot.ResourceProperty,
384 '@factory': hot.ResourcePropertyFactory
385 }
386 }
387 });
388
389 hot.ResourceProperty_list2 = hot.ResourceProperty.extend({}, {
390 'default': {'@type': Array}});
391 hot.ResourceProperty_map2 = hot.ResourceProperty.extend({}, {
392 'default': {'@type': Object}});
393 hot.ResourceProperty_string = hot.ResourceProperty.extend({}, {
394 'default': {'@type': String}});
395 hot.ResourceProperty_number = hot.ResourceProperty.extend({}, {
396 'default': {'@type': Number}});
397 hot.ResourceProperty_integer = hot.ResourceProperty.extend({}, {
398 'default': {'@type': Number}});
399 hot.ResourceProperty_boolean = hot.ResourceProperty.extend({}, {
400 'default': {'@type': Boolean}});
401
402 hot.ResourceAttribute = Barricade.create({
403 '@type': Object,
404 'description': {'@type': String}
405 });
406
407 hot.ResourceType = Barricade.ImmutableObject.extend({
408 getSchema: function () {
409 var propertySchema = {
410 '@type': Object,
411 '@required': false
412 };
413
414 this.get('properties').each(function (i, self) {
415 propertySchema[self.getID()] = self.getSchema();
416 });
417
418 if (this.getID() === 'OS::Heat::ResourceGroup') {
419 propertySchema.resource_def = {
420 '@type': Object,
421 'type': {
422 '@class': hot.ResourcePropertyWrapper.extend({
423 _innerClass: Barricade.create({'@type': String})
424 }, {'@required': true})
425 },
426 'properties': {
427 '@type': Object,
428 '@ref': {
429 to: hot.ResourceProperties,
430 needs: function () {
431 return hot.ResourceProperties;
432 },
433 getter: function (data) {
434 var type = data.needed.get('resource_def')
435 .get('type').getValue();
436 if (type.instanceof(hot.GetParameter)) {
437 type = type.get('get_param');
438 }
439 return type;
440 },
441 processor: function (data) {
442 var type = data.val;
443 if (type.instanceof(hot.Parameter)) {
444 type = type.get('default');
445 }
446 return hot.ResourcePropertiesFactory(
447 data.standIn.get(), undefined, type.get());
448 }
449 }
450 }
451 };
452 }
453
454 return propertySchema;
455 }
456 }, {
457 '@type': Object,
458 'attributes': {
459 '@type': Object,
460 '?': {'@class': hot.ResourceAttribute}
461 },
462 'properties': {
463 '@type': Object,
464 '?': {
465 '@class': hot.ResourceProperty,
466 '@factory': hot.ResourcePropertyFactory
467 }
468 }
469 });
470
471 hot.ResourceTypes = Barricade.create({
472 '@type': Object,
473 '?': {'@class': hot.ResourceType}
474 });
475
476 hot.IntrinsicFunctionFactory = function (json, parameters) {
477 if (Barricade.getType(json) === Object) {
478 if (json.hasOwnProperty('get_resource')) {
479 return hot.GetResource.create(json, parameters);
480
481 } else if (json.hasOwnProperty('get_attr')) {
482 return hot.GetAttribute.create(json, parameters);
483
484 } else if (json.hasOwnProperty('get_param')) {
485 if (json.get_param === 'OS::stack_name' ||
486 json.get_param === 'OS::stack_id' ||
487 json.get_param === 'OS::project_id') {
488 return hot.GetParameterSpecial.create(json, parameters);
489 }
490 return hot.GetParameter.create(json, parameters);
491
492 } else if (json.hasOwnProperty('get_file')) {
493 return hot.GetFile.create(json, parameters);
494
495 } else if (json.hasOwnProperty('str_replace')) {
496 return hot.StringReplace.create(json, parameters);
497
498 } else if (json.hasOwnProperty('resource_facade')) {
499 return hot.ResourceFacade.create(json, parameters);
500 }
501 }
502
503 return false;
504 };
505
506 hot.IntrinsicFunction = Barricade.ImmutableObject.extend({}, {
507 '@type': Object,
508 '@required': false
509 });
510
511 hot.GetResource = hot.IntrinsicFunction.extend({}, {
512 '@toJSON': function () {
513 if (this.get('get_resource').getPrimitiveType() === String) {
514 console.error('Resource was not available');
515 return {get_resource: ''};
516 } else {
517 return {get_resource: this.get('get_resource').getID()};
518 }
519 },
520 'get_resource': {
521 '@type': String,
522 '@ref': {
523 to: function () { return hot.Resource; },
524 needs: function () { return hot.Template; },
525 getter: function (data) {
526 return data.needed.get('resources')
527 .getByID(data.standIn.get());
528 }
529 }
530 }
531 });
532
533 hot.GetAttribute = hot.IntrinsicFunction.extend({}, {
534 'get_attr': {
535 // handle a nicely-formatted object instead of
536 // an array with different types in it, the first
537 // two of which should really be references
538 '@type': Object,
539 '@inputMassager': function (json) {
540 if (!json) {
541 json = ['', ''];
542 }
543
544 return {
545 resource: json[0],
546 attribute: json[1],
547 value: json.slice(2)
548 };
549 },
550 '@toJSON': function () {
551 var resourceID;
552
553 if (this.get('resource').getPrimitiveType() === String) {
554 resourceID = '';
555 console.error('Resource was not available');
556 } else {
557 resourceID = this.get('resource').getID();
558 }
559 return [
560 resourceID,
561 this.get('attribute').get()
562 ].concat(this.get('value').get());
563 },
564
565 'resource': {
566 '@type': String,
567 '@ref': {
568 to: function () { return hot.Resource; },
569 needs: function () { return hot.Template; },
570 getter: function (data) {
571 return data.needed.get('resources')
572 .getByID(data.standIn.get());
573 }
574 }
575 },
576 'attribute': {'@type': String},
577 'value': {'@type': Array}
578 }
579 });
580
581 hot.GetParameter = hot.IntrinsicFunction.extend({}, {
582 '@toJSON': function () {
583 if (this.get('get_param').getPrimitiveType() === String) {
584 console.error('Parameter was not available');
585 return {get_param: ''};
586 } else {
587 return {get_param: this.get('get_param').getID()};
588 }
589 },
590 'get_param': {
591 '@type': String,
592 '@ref': {
593 to: function () { return hot.Parameter; },
594 needs: function () { return hot.Template; },
595 getter: function (data) {
596 return data.needed.get('parameters')
597 .getByID(data.standIn.get());
598 }
599 }
600 }
601 });
602
603 // For OS::stack_name, OS::stack_id, and OS::project_id pseudo parameters
604 hot.GetParameterSpecial = hot.IntrinsicFunction.extend({}, {
605 'get_param': {'@type': String}
606 });
607
608 hot.GetFile = hot.IntrinsicFunction.extend({}, {
609 'get_file': {'@type': String}
610 });
611
612 hot.StringReplace = hot.IntrinsicFunction.extend({
613 getParams: function () {
614 return this.get('str_replace').get('params');
615 },
616 getTemplate: function () {
617 return this.get('str_replace').get('template');
618 },
619 getIntrinsicFunctions: function () {
620 return this.getParams().toArray().reduce(function (arr, current) {
621 return arr.concat(current.getIntrinsicFunctions());
622 }, []);
623 }
624 }, {
625 'str_replace': {
626 '@type': Object,
627 'template': {'@type': String},
628 'params': {
629 '@type': Object,
630 '?': {
631 '@class': hot.ResourcePropertyWrapper.extend({
632 _innerClass: Barricade.create({'@type': String})
633 }, {})
634 }
635 }
636 }
637 });
638
639 hot.ResourceFacade = hot.IntrinsicFunction.extend({}, {
640 'resource_facade': {'@type': String}
641 });
642
643 hot.ResourceProperties = Barricade.ImmutableObject.extend({
644 canConnectTo: function (typeName) {
645 return typeName in this._automaticConnections;
646 },
647 getConnector: function (typeName) {
648 return this._automaticConnections[typeName];
649 }
650 });
651
652 hot.ResourcePropertiesFactory = function (json, parameters, type) {
653 var propertyClass = hot.ResourceProperties.Normal[type] ||
654 hot.ResourceProperties.Custom[type] ||
655 hot.ResourceProperties.Null,
656 propertiesOut;
657
658 return propertyClass.create(json, parameters);
659 };
660
661 hot.Resource = Barricade.ImmutableObject.extend({
662 _endsWith: function (str, suffix) {
663 return str.indexOf(suffix, str.length - suffix.length) !== -1;
664 },
665 _getTypeValue: function (typeObj) {
666 return typeObj.getValue().instanceof(hot.GetParameter)
667 ? typeObj.getValue().get('get_param').get('default').get()
668 : typeObj.getValue().get();
669 },
670 getProperties: function () {
671 return this.get('properties');
672 },
673 getProperty: function (property) {
674 return this.getProperties().get(property);
675 },
676 isResourceGroup: function () {
677 return this._getTypeValue(this.get('type')) ===
678 'OS::Heat::ResourceGroup';
679 },
680 isProviderResource: function () {
681 var type = this.getType();
682 return this._endsWith(type, '.yaml') ||
683 this._endsWith(type, '.template');
684 },
685 getType: function () {
686 return this._getTypeValue(this.isResourceGroup()
687 ? this.getProperty('resource_def').get('type')
688 : this.get('type'));
689 },
690 getShortType: function () {
691 var type = this.getType();
692 if (this.isProviderResource()) {
693 return type.split('/').pop().split('.')[0];
694 }
695 return type.split('::')[2];
696 },
697 getAttributes: function () {
698 var attributes = this.getProperties().getBackingType()
699 .get('attributes').toArray();
700 if (this.isResourceGroup()) {
701 return attributes.concat(
702 this.getProperty('resource_def').get('properties')
703 .getBackingType().get('attributes').toArray());
704 }
705 return attributes;
706 },
707 getAttributeNames: function () {
708 return this.getAttributes().map(function (attribute) {
709 return attribute.getID();
710 });
711 },
712 getIntrinsicFunctions: function () {
713 function getIntrinsics(value) {
714 var intrinsics = [];
715 if (value.instanceof(hot.ResourcePropertyWrapper)) {
716 return value.getIntrinsicFunctions();
717 } else if (value.instanceof(Barricade.Container)) {
718 value.each(function (i, element) {
719 intrinsics = intrinsics.concat(getIntrinsics(element));
720 });
721 return intrinsics;
722 }
723 return [];
724 }
725 return getIntrinsics(this.getProperties());
726 },
727 canConnectTo: function (resource, checkBothWays) {
728 return this.getProperties().canConnectTo(resource.getType()) ||
729 (checkBothWays !== false && resource.canConnectTo(this, false));
730 },
731 connectTo: function (res, tryBothWays) {
732 var connector = this.getProperties().getConnector(res.getType());
733 if (connector) {
734 connector(this, res);
735 } else if (tryBothWays !== false) {
736 res.connectTo(this, false);
737 }
738 },
739 _docsBaseURL: "http://docs.rs-heat.com/raxdox/",
740 getDocsLink: function () {
741 var resourceType = this.getType(),
742 nameTokens = resourceType.split('::'),
743 resourceBase;
744 if (nameTokens[0] === 'OS') {
745 resourceBase = "openstack";
746 } else if (nameTokens[0] === 'Rackspace') {
747 resourceBase = "rackspace";
748 } else {
749 console.warn("Resource type not found: %s", nameTokens[0]);
750 return this._docsBaseURL;
751 }
752 return this._docsBaseURL + resourceBase + '.html#' +
753 resourceType;
754 }
755 }, {
756 '@type': Object,
757
758 'type': {
759 '@class': hot.ResourcePropertyWrapper.extend({
760 _innerClass: Barricade.create({'@type': String})
761 }, {'@required': true})
762 },
763 'properties': {
764 '@type': Object,
765 '@ref': {
766 to: hot.ResourceProperties,
767 needs: function () { return hot.Resource; },
768 getter: function (data) {
769 var type = data.needed.get('type').getValue();
770 if (type.instanceof(hot.GetParameter)) {
771 type = type.get('get_param');
772 }
773 return type;
774 },
775 processor: function (data) {
776 var type = data.val;
777
778 if (type.instanceof(hot.Parameter)) {
779 type = type.get('default');
780 }
781
782 return hot.ResourcePropertiesFactory(
783 data.standIn.get(), undefined, type.get());
784 }
785 }
786 },
787 'metadata': {
788 '@type': String,
789 '@required': false
790 },
791 'depends_on': {
792 '@type': Array,
793 '@required': false,
794 '@inputMassager': function (json) {
795 if (typeof json === "string") {
796 return [json];
797 } else {
798 return json;
799 }
800 },
801 '@toJSON': function (options) {
802 if (this.toArray().length === 1) {
803 return this.get(0).toJSON(options);
804 }
805 return Barricade.Array.toJSON.call(this, options);
806 },
807 '*': {'@type': String}
808 },
809 'update_policy': {
810 '@type': Object,
811 '@required': false,
812 '?': {'@type': String}
813 },
814 'deletion_policy': {
815 '@type': String,
816 '@required': false
817 }
818 });
819
820
821 hot.ParameterDefault = Barricade.Primitive.extend({}, {
822 '@required': false
823 });
824
825 (function () {
826 var pd = hot.ParameterDefault;
827 hot.StringParameterDefault = pd.extend({}, {'@type': String});
828 hot.NumberParameterDefault = pd.extend({}, {'@type': Number});
829 hot.ArrayParameterDefault = pd.extend({}, {'@type': Array});
830 hot.ObjectParameterDefault = pd.extend({}, {'@type': Object});
831 hot.BooleanParameterDefault = pd.extend({}, {'@type': Boolean});
832 }());
833
834 hot.ParameterConstraintFactory = function (json, parameters) {
835 var key,
836 types = {
837 'length': hot.LengthParameterConstraint,
838 'range': hot.RangeParameterConstraint,
839 'allowed_values': hot.AllowedValuesParameterConstraint,
840 'allowed_pattern': hot.AllowedPatternParameterConstraint,
841 'custom_constraint': hot.CustomParameterConstraint,
842 };
843
844 if (!json) {
845 return hot.LengthParameterConstraint.create(json, parameters);
846 }
847
848 for (key in types) {
849 if (types.hasOwnProperty(key) && json.hasOwnProperty(key)) {
850 return types[key].create(json, parameters);
851 }
852 }
853
854 console.error('unknown constraint type');
855 };
856
857 hot.ParameterConstraint = Barricade.ImmutableObject.extend({}, {
858 '@type': Object,
859 'description': {
860 '@type': String,
861 '@required': false
862 }
863 });
864
865 hot.LengthParameterConstraint = hot.ParameterConstraint.extend({}, {
866 'length': {
867 '@type': Object,
868 'min': {
869 '@type': Number,
870 '@required': false
871 },
872 'max': {
873 '@type': Number,
874 '@required': false
875 }
876 }
877 });
878
879 hot.RangeParameterConstraint = hot.ParameterConstraint.extend({}, {
880 'range': {
881 '@type': Object,
882 'min': {
883 '@type': Number,
884 '@required': false
885 },
886 'max': {
887 '@type': Number,
888 '@required': false
889 }
890 }
891 });
892
893 hot.AllowedValuesParameterConstraint = hot.ParameterConstraint.extend({}, {
894 'allowed_values': {'@type': Array}});
895 hot.AllowedPatternParameterConstraint = hot.ParameterConstraint.extend({}, {
896 'allowed_pattern': {'@type': String}});
897 hot.CustomParameterConstraint = hot.ParameterConstraint.extend({}, {
898 'custom_constraint': {'@type': String}});
899
900 hot.Parameter = Barricade.create({
901 '@type': Object,
902
903 'type': {'@type': String},
904 'label': {
905 '@type': String,
906 '@required': false
907 },
908 'description': {
909 '@type': String,
910 '@required': false
911 },
912 'default': {
913 '@type': Object,
914 '@required': false,
915 // default can be various types, so wrap it in an object to
916 // make Barricade happy
917 '@inputMassager': function (json) {
918 return {value: json};
919 },
920 '@ref': {
921 to: hot.ParameterDefault,
922 needs: function () { return hot.Parameter; },
923 getter: function (data) {
924 return data.needed.get('type');
925 },
926 processor: function (data) {
927 var types = {
928 'string': hot.StringParameterDefault,
929 '': hot.StringParameterDefault,
930 'number': hot.NumberParameterDefault,
931 'comma_delimited_list':
932 hot.ArrayParameterDefault,
933 'json': hot.ObjectParameterDefault,
934 'boolean': hot.BooleanParameterDefault,
935 },
936 type = data.val.get();
937
938 return types[type].create(data.standIn.get().value);
939 }
940 }
941 },
942 'hidden': {
943 '@type': Boolean,
944 '@required': false,
945 },
946 'constraints': {
947 '@type': Array,
948 '@required': false,
949 '*': {
950 '@class': hot.ParameterConstraint,
951 '@factory': hot.ParameterConstraintFactory
952 }
953 }
954 });
955
956 hot.ParameterGroup = Barricade.create({
957 '@type': Object,
958 'label': {'@type': String},
959 'description': {
960 '@type': String,
961 '@required': false
962 },
963 'parameters': {
964 '@type': Array,
965 '@toJSON': function () {
966 return this.toArray().map(function (param) {
967 return param.getID();
968 });
969 },
970 '*': {
971 '@type': String,
972 '@ref': {
973 to: hot.Parameter,
974 needs: function () { return hot.Template; },
975 getter: function (data) {
976 return data.needed.get('parameters')
977 .getByID(data.standIn.get());
978 }
979 }
980 }
981 },
982 });
983
984 hot.Output = Barricade.create({
985 '@type': Object,
986 'description': {'@type': String},
987 'value': {
988 '@class': hot.ResourcePropertyWrapper.extend({
989 _innerClass: Barricade.create({'@type': String})
990 }, {})
991 }
992 });
993
994 hot.Template = Barricade.create({
995 '@type': Object,
996
997 'heat_template_version': {'@type': String},
998 'description': {
999 '@type': String,
1000 '@required': false
1001 },
1002 'parameter_groups': {
1003 '@type': Array,
1004 '@required': false,
1005 '*': {'@class': hot.ParameterGroup}
1006 },
1007 'parameters': {
1008 '@type': Object,
1009 '@required': false,
1010 '?': {'@class': hot.Parameter}
1011 },
1012 'resources': {
1013 '@type': Object,
1014 '?': {'@class': hot.Resource}
1015 },
1016 'outputs': {
1017 '@type': Object,
1018 '@required': false,
1019 '?': {'@class': hot.Output}
1020 }
1021 });
1022
1023 //hot.ProviderTemplate = Barricade.ImmutableObject.extend({
1024 // getSchema: function () {
1025 // function getActualType(type) {
1026 // var types = {
1027 // json: 'map',
1028 // comma_delimited_list: 'list'
1029 // };
1030 // return types[type] || type;
1031 // }
1032 //
1033 // return {
1034 // properties: this.get('parameters').toArray().reduce(
1035 // function (objOut, param) {
1036 // objOut[param.getID()] = {
1037 // description: param.get('description').get(),
1038 // type: getActualType(param.get('type').get())
1039 // };
1040 // return objOut;
1041 // }, {}),
1042 // attributes: this.get('outputs').toArray().reduce(
1043 // function (objOut, output) {
1044 // objOut[output.getID()] = {
1045 // description: output.get('description').get()
1046 // };
1047 // return objOut;
1048 // }, {})
1049 // };
1050 // }
1051 //}, {
1052 // '@type': Object,
1053 //
1054 // 'heat_template_version': {'@type': String},
1055 // 'description': {'@type': String, '@required': false},
1056 // 'parameter_groups': {'@type': Array, '@required': false},
1057 // 'resources': {'@type': Object},
1058 // 'parameters': {
1059 // '@type': Object,
1060 // '?': {'@class': hot.Parameter}
1061 // },
1062 // 'outputs': {
1063 // '@type': Object,
1064 // '@required': false,
1065 // '?': {
1066 // '@class': hot.Output.extend({}, {
1067 // 'value': {
1068 // '@class': hot.Primitive,
1069 // '@factory': hot.Primitive.Factory
1070 // }
1071 // })
1072 // }
1073 // }
1074 //});
1075
1076 //// Used to find URLs of templates to load and turn into child templates
1077 //hot.ProviderTemplateHelper = hot.Template.extend({
1078 // getProviderTemplateURLs: function () {
1079 // return this.get('resources').toArray().filter(function (res) {
1080 // return res.isProviderResource();
1081 // }).map(function (res) {
1082 // return res.getType();
1083 // });
1084 // }
1085 //}, {
1086 // // Essentially, remove any unncessary reference resolving
1087 // '@type': Object,
1088 // 'parameter_groups': {'@type': Array, '@required': false},
1089 // 'resources': {
1090 // '@type': Object,
1091 // '?': {
1092 // '@class': hot.Resource.extend({}, {
1093 // 'properties': {'@type': Object, '@required': false},
1094 // 'depends_on': {
1095 // '@type': Array,
1096 // '@required': false,
1097 // '@inputMassager': function (json) {
1098 // return json instanceof Array ? json : [json];
1099 // }
1100 // }
1101 // })
1102 // }
1103 // },
1104 // 'outputs': {'@type': Object, '@required': false}
1105 //});
1106
1107 hot.createResourceClass = function (resourceType) {
1108 return hot.ResourceProperties.extend({
1109 getBackingType: function () {
1110 return resourceType;
1111 },
1112 _automaticConnections:
1113 HOTUI_RESOURCE_CONNECTIONS[resourceType.getID()] || {}
1114 },
1115 resourceType.getSchema());
1116 };
1117
1118 //hot.createProviderResourceClass = function (providerTemplateJSON) {
1119 // var pTemplate = hot.ProviderTemplate.create(providerTemplateJSON),
1120 // resType = hot.ResourceType.create(pTemplate.getSchema());
1121 // return hot.createResourceClass(resType);
1122 //};
1123
1124 return hot;
1125 }
9 1126
10})(); 1127})();