4 * Copyright 2016 RIFT.IO Inc
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 import React, {Component} from 'react';
20 import ReactDOM from 'react-dom';
21 import SelectOption from 'widgets/form_controls/selectOption.jsx';
22 import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
23 import imgRemove from '../../node_modules/open-iconic/svg/trash.svg'
24 import TextInput from 'widgets/form_controls/textInput.jsx';
25 import './instantiateInputParams.scss';
27 export default class InstantiateInputParams extends Component {
31 nsConfigHTML = (props) => {
33 <div className="configure-nsd_section">
34 <div className="inputControls">
35 <TextInput label="Instance Name" type="text" pattern="^[a-zA-Z0-9_]*$" style={{textAlign:'left'}} onChange={props.updateName} value={props.name}/>
37 !isOpenMano(props.ro) ?
39 <label>Select VIM Account
40 <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} onChange={props.nsFn.updateSelectedCloudAccount} />
46 isOpenMano(props.ro) ?
47 dataCentersHTML(props.dataCenters[props.ro.name],
48 props.nsFn.updateSelectedDataCenter)
55 vnfCloudAccountsHTML = (props) => {
57 let dataCenters = props.dataCenters;
59 <div className="configure-nsd_section">
60 <h3 className="launchpadCard_title">NS/VNF ACCOUNT PLACEMENTS</h3>
64 nsd['constituent-vnfd'] && nsd['constituent-vnfd'].map(function(v, i) {
65 let defaultValue = false;
66 if(props.vnfdCloudAccounts && props.vnfdCloudAccounts.hasOwnProperty(v['member-vnf-index'])) {
67 defaultValue = props.vnfdCloudAccounts[v['member-vnf-index']]
70 <div className="inputControls" key={i}>
71 <h4 className="inputControls-title">VNFD: {v.name}</h4>
73 !isOpenMano(props.ro) ?
75 <label>Select VIM Account
76 <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} initial={true} onChange={props.vnfFn.updateSelectedCloudAccount.bind(null, v['member-vnf-index'])} defaultValue={defaultValue} />
82 isOpenMano(props.ro) ?
84 props.dataCenters[props.ro.name],
85 props.vnfFn.updateSelectedDataCenter.bind(null, v['member-vnf-index']), true)
89 (props.configAgentAccounts && props.configAgentAccounts.length > 0) ?
90 <label>Select Config Agent Account
91 <SelectOption options={props.configAgentAccounts && props.configAgentAccounts.map(function(c) {
96 })} initial={true} onChange={props.vnfFn.updateSelectedConfigAgent(v['member-vnf-index'])} defaultValue={false} />
106 inputParametersHTML = (props) => {
107 let inputParameters = props.inputParameters;
108 const handleChange = (i, event) => props.updateInputParam(i, event.target.value);
109 let nsInputParamsHTML = [];
110 inputParameters && inputParameters.map(function(input, i) {
111 nsInputParamsHTML.push(
112 <div className="inputControls" key={i}>
113 <TextInput label={ input.label || input.xpath } value={input.value || input['default-value']} type="text" onChange={handleChange.bind(this, i)} />
118 <div className="configure-nsd_section" >
119 <h3 className="launchpadCard_title">NS Input Parameters</h3>
127 nsPlacementGroupsHTML = (props) => {
128 let nsPlacementGroups = props.nsPlacementGroups;
129 let displayPlacementGroups = props.displayPlacementGroups;
130 if (nsPlacementGroups && nsPlacementGroups.length > 0 && displayPlacementGroups) {
132 <div className="configure-nsd_section">
133 <h3 className="launchpadCard_title">NS Placement Groups</h3>
135 nsPlacementGroups.map(function(input, i) {
137 <div key={i} className="configure-nsd_section-info">
138 <div className="placementGroup_description">
139 <div className="placementGroup_description-name">
140 <strong>{input.name}</strong> contains: {
141 input['member-vnfd'].map((m,i) => {
150 <div><em>{input.requirement}</em></div>
151 <div><strong>Strategy:</strong> {input.strategy}</div>
154 <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span> </span>
155 <div style={{display:'none'}}>
156 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
157 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
161 <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
162 <div style={{display:'none'}}>
163 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'server-group')} />
164 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
167 <div className="host-aggregate">
169 <span> Host Aggregates <span onClick={props.nsFn.addHostAggregate.bind(self, i)} className="addInput" ><img src={imgAdd} />Add</span></span>
171 input['host-aggregate'].length > 0 ?
172 input['host-aggregate'].map((h,j) => {
173 let key = h.key || '';
174 let value = h.value || '';
177 <div className="input_group" key={j}>
178 <TextInput type="text" onChange={props.nsFn.hostAggregateUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
179 <TextInput type="text" onChange={props.nsFn.hostAggregateUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
180 <span onClick={props.nsFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
195 vnfPlacementGroupsHTML = (props) => {
196 let vnfPlacementGroups = props.vnfPlacementGroups;
197 let displayPlacementGroups = props.displayPlacementGroups;
198 if (vnfPlacementGroups && vnfPlacementGroups.length > 0 && displayPlacementGroups) {
199 return vnfPlacementGroups.map(function(input, i) {
201 <div className="configure-nsd_section" key={i}>
202 <h3 className="launchpadCard_title">{input['vnf-name']} VNF Placement Group</h3>
203 <div className="configure-nsd_section-info">
204 <div className="placementGroup_description">
205 <div className="placementGroup_description-name">
206 <strong>{input.name}</strong> contains: {
207 input['member-vdus'].map((m,i) => {
208 let s = m['member-vdu-ref'];
210 s = ', ' + m['member-vdu-ref']
216 <div><em>{input.requirement}</em></div>
217 <div><strong>Strategy</strong>: {input.strategy}</div>
220 <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
221 <div style={{display:'none'}}>
222 <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
223 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
227 <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
228 <div style={{display:'none'}}>
229 <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'server-group')} />
230 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
233 <div className="host-aggregate">
235 <span> Host Aggregates <span onClick={props.vnfFn.addHostAggregate.bind(self, i)} className="addInput"><img src={imgAdd} />Add</span></span>
237 input['host-aggregate'].length > 0 ?
238 input['host-aggregate'].map((h,j) => {
239 let key = h.key || '';
240 let value = h.value || '';
243 <div className="input_group" key={j}>
244 <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
245 <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
246 <span onClick={props.vnfFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
260 vldsHTML = (props) => {
262 let ipProfileList = props.ipProfileList;
263 let vlds = props.vlds;
265 <div className="configure-nsd_section">
266 <h3 className="launchpadCard_title">VLDs</h3>
267 {vlds && vlds.map(function(v, i) {
268 let currentType = v.type;
269 let isVIM = (currentType == 'vim-network-name');
270 let isUnknown = (currentType == 'none') || ((currentType != 'vim-network-name') && (currentType != 'ip-profile-ref'));
272 <div key={self.props.nsd.id + '-' + i} className="inputControls">
273 <h4 className="inputControls-title">VLD: {v['short-name'] ? v['short-name'] : v['name']}</h4>
274 <label><span>Specify VLD Parameters</span></label>
275 <div className="inputControls-radioGroup">
276 <label className="inputControls-radio" style={{display: ipProfileList ? 'flex' : 'none'}}>
277 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={!isVIM && !isUnknown} value='ip-profile-ref' />
280 <label className="inputControls-radio">
281 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isVIM && !isUnknown} value='vim-network-name' />
284 <label className="inputControls-radio">
285 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isUnknown} value='none' />
290 isUnknown ? null : isVIM ?
291 <TextInput label="Network Name" onChange={self.props.vldFn.updateValue(i, currentType)} value={v[currentType]} /> :
294 label="IP PROFILE NAME"
295 options={ipProfileList && ipProfileList.map(function(ip) {
302 v['ip-profile-ref'] ? false : true
304 defaultValue={v['ip-profile-ref']}
305 onChange={self.props.vldFn.updateValue(i, currentType)}>
316 ipProfilesHTML = (props) => {
317 let vldHasIPprofile = false;
318 props.vlds && props.vlds.map(function(v){
319 if(v.type == 'ip-profile-ref') {
320 vldHasIPprofile = true;
323 let ipProfileList = props.ipProfileList;
324 return ipProfileList && vldHasIPprofile &&
326 <div className="configure-nsd_section">
327 <h3 className="launchpadCard_title">IP Profiles</h3>
330 ipProfileList && ipProfileList.map(function(ip, j) {
331 let ipl = ip['ip-profile-params'];
333 <div className="inputControls" key={j}>
334 <div className="inputControls-title" >
337 <div className="inputControls-radioGroup">
338 <label className="inputControls-radio">
339 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv4'} value='ipv4' />
342 <label className="inputControls-radio">
343 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv6'} value='ipv6' />
346 <label className="inputControls-radio">
347 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'unknown'} value='unknown' />
352 label="subnet address"
353 onChange={props.ipProfileFn.updateProfile(j, 'subnet-address')}
354 value={ipl['subnet-address']}
357 label="gateway address"
358 onChange={props.ipProfileFn.updateProfile(j, 'gateway-address')}
359 value={ipl['gateway-address']}
362 label="security group"
363 onChange={props.ipProfileFn.updateProfile(j, 'security-group')}
364 value={ipl['security-group']}
367 label="subnet prefix pool"
368 onChange={props.ipProfileFn.updateProfile(j, 'subnet-prefix-pool')}
369 value={ipl['subnet-prefix-pool']}
372 <div style={{display:'flex'}}>
373 DNS SERVERS <span onClick={props.dnsFn.addDNS(j)} className="addInput"><img src={imgAdd} />Add</span>
376 ipl['dns-server'] && ipl['dns-server'].map(function(dns, k) {
378 <div key={k} style={{display:'flex'}}>
380 onChange={props.dnsFn.updateDNS(j,k)}
381 value={ipl['dns-server'][k].address}
383 <span onClick={props.dnsFn.removeDNS(j,k)} className="removeInput">
384 <img src={imgRemove} />Remove</span>
390 <div className="inputControls-radioGroup">
391 <label className="inputControls-radio">
394 name={'ip-profile-dhcp' + j }
395 onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
396 checked={ipl.hasOwnProperty('dhcp-params') && ipl['dhcp-params'].enabled}
400 <label className="inputControls-radio">
402 name={'ip-profile-dhcp' + j }
403 onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
404 checked={!ipl.hasOwnProperty('dhcp-params') || !ipl['dhcp-params'].enabled}
410 (ipl['dhcp-params'] && ipl['dhcp-params'].enabled) ? dhcpHTML(props, ipl, j) : null
417 function dhcpHTML(props, ipl, j){
420 label="DHCP Start Address"
421 onChange={props.ipProfileFn.updateDHCP(j, 'start-address')}
422 value={ipl['dhcp-params'] && ipl['dhcp-params']['start-address']}
426 onChange={props.ipProfileFn.updateDHCP(j, 'count')}
427 value={ipl['dhcp-params'] && ipl['dhcp-params']['count']}
433 sshKeysHTML = (props) => {
434 let sshKeysList = props.sshKeysList;
435 let sshKeysRef = props.sshKeysRef;
436 if(sshKeysList && sshKeysList.length > 0) {
438 <div className="configure-nsd_section">
439 <h3 className="launchpadCard_title">SSH Authorized Keys</h3>
442 sshKeysRef.map(function(ref, i) {
443 let keyref = JSON.stringify(ref)
445 <div key={keyref.name + '-' + i} className="inputControls inputControls-sshkeys">
450 options={sshKeysList && sshKeysList.map(function(k) {
456 ref="keyPairSelection"
458 defaultValue={keyref.name || sshKeysList[0].name}
459 onChange={props.sshFn.updateKeyRef(i)}>
464 <span onClick={props.sshFn.updateKeyRef(i, true)} className="removeInput">
465 <img src={imgRemove} />
473 <div className="inputControls inputControls-sshkeys ">
474 <label style={{display: 'flex', 'flexDirection': 'row'}}>
476 <span onClick={props.sshFn.updateKeyRef().bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
486 usersHTML = (props) => {
487 let usersFn = props.usersFn;
488 let sshKeysList = props.sshKeysList;
489 let usersList = props.usersList && props.usersList.map(function(u, i) {
490 let sshKeysRef = u['ssh-authorized-key'];
492 <div className="input_group input_group-users" key={i}>
493 <div className="inputControls">
494 <div style={{fontWeight: 'bold', display: 'flex'}}>USER <span onClick={usersFn.remove(i)} className="removeInput"><img src={imgRemove} />Remove</span></div>
495 <TextInput onChange={usersFn.update(i, 'name')} label="USERNAME" value={i.name} />
496 <TextInput onChange={usersFn.update(i, 'user-info')} label="REAL NAME" value={i.gecos} />
498 sshKeysRef.map(function(ref, j) {
499 let keyref = JSON.stringify(ref)
501 <div key={keyref.name + '-' + i + '-' + j} className="inputControls inputControls-sshkeys">
506 options={sshKeysList && sshKeysList.map(function(k) {
512 ref="keyPairSelection"
515 onChange={usersFn.updateSSHkeyRef(i, j)}>
520 sshKeysRef.length > 0 ?
522 <span onClick={usersFn.updateSSHkeyRef(i, j, true)} className="removeInput">
523 <img src={imgRemove} />
534 <div className="inputControls inputControls-sshkeys ">
535 <label style={{display: 'flex', 'flexDirection': 'row', 'alignItems': 'center'}}>
537 <span onClick={usersFn.updateSSHkeyRef(i).bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
548 <div className="configure-nsd_section">
549 <h3 className="launchpadCard_title">USERS</h3>
551 <div className="inputControls inputControls-sshkeys inputControls-addUser ">
552 <span onClick={usersFn.add(sshKeysList)} className="addInput">
562 const props = this.props;
567 <div className="instantiateInputParams">
570 this.nsConfigHTML(props)
574 this.vnfCloudAccountsHTML(props)
578 this.inputParametersHTML(props)
582 this.nsPlacementGroupsHTML(props)
585 //VNF PLACEMENTGROUPS
586 this.vnfPlacementGroupsHTML(props)
593 //IP PROFILE CONFIGURATION
594 this.ipProfilesHTML(props)
597 //SSH KEY ASSIGNMENTS
598 this.sshKeysHTML(props)
602 this.usersHTML(props)
609 function showInput(e){
610 let target = e.target;
611 if(target.parentElement.classList.contains("addInput")) {
612 target = target.parentElement;
614 target.style.display = 'none';
615 target.parentElement.nextElementSibling.style.display = 'flex';
616 // e.target.parentElement.nextElementSibling.children[1].style.display = 'initial';
618 function hideInput(e){
619 let target = e.target;
620 if(target.parentElement.classList.contains("removeInput")) {
621 target = target.parentElement;
623 target.parentElement.style.display = 'none';
624 target.parentElement.previousElementSibling.children[1].style.display = 'inline';
625 target.previousSibling.value = '';
628 function removeDNS(){}
629 function constructCloudAccountOptions(cloudAccounts){
630 let CloudAccountOptions = cloudAccounts && cloudAccounts.map(function(ca, index) {
636 return CloudAccountOptions;
638 function dataCentersHTML(dataCenters, onChange, initial) {
639 //Build DataCenter options
640 //Relook at this, why is it an object?
641 let DataCenterOptions = [];
642 DataCenterOptions = dataCenters && dataCenters.map(function(dc, index) {
648 if (dataCenters && dataCenters.length > 0) {
650 <label>Select Data Center
651 <SelectOption initial={!!initial} options={DataCenterOptions} onChange={onChange} />
656 function isOpenMano(account) {
659 if (a.constructor.name == 'String') {
662 return a['account-type'] == 'openmano';
667 function updateNewSshKeyRefSelection(e) {
669 newRefSelection: e.target.value
672 function resetRef() {
674 newRefSelection: null
677 InstantiateInputParams.defaultProps = {