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="noticeSubText noticeSubText_right">
37 <div className="inputControls">
38 <TextInput label="Instance Name" required={true} type="text" pattern="^[a-zA-Z0-9_]*$" style={{textAlign:'left'}} onChange={props.updateName} value={props.name}/>
39 <label>Resource Orchestrator
40 <SelectOption options={constructROOptions(props.resourceOrchestrators)} onChange={props.nsFn.updateSelectedRoAccount} />
43 (props.selectedResourceOrchestrator.datacenters && props.selectedResourceOrchestrator.datacenters.datacenters) ?
46 <SelectOption options={constructDataCenterOptions(props.selectedResourceOrchestrator.datacenters.datacenters)} onChange={props.nsFn.updateSelectedDataCenter} />
49 : <span>No datacenters configured</span>
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['vnf-name']}</h4>
73 (props.selectedResourceOrchestrator.datacenters && props.selectedResourceOrchestrator.datacenters.datacenters) ?
76 <SelectOption options={constructDataCenterOptions(props.selectedResourceOrchestrator.datacenters.datacenters)} onChange={props.vnfFn.updateSelectedDataCenter.bind(null, v['member-vnf-index'])} initial={true} />
79 : <span>No datacenters configured</span>
82 (props.configAgentAccounts && props.configAgentAccounts.length > 0) ?
83 <label>Config Agent Account
84 <SelectOption options={props.configAgentAccounts && props.configAgentAccounts.map(function(c) {
89 })} initial={true} onChange={props.vnfFn.updateSelectedConfigAgent(v['member-vnf-index'])} defaultValue={false} />
99 //"vnfd-catalog/vnfd[id=../../../constituent-vnfd[0]/vnfd-id-ref]/version";
101 inputParametersHTML = (props) => {
102 let inputParameters = props.inputParameters;
103 const handleChange = (i, event) => props.updateInputParam(i, event.target.value);
104 let nsInputParamsHTML = [];
105 inputParameters && inputParameters.map(function(input, i) {
106 nsInputParamsHTML.push(
107 <div className="inputControls" key={i}>
108 <TextInput label={ input.label || input.xpath } value={input.value || input['default-value']} type="text" onChange={handleChange.bind(this, i)} />
113 <div className="configure-nsd_section" >
114 <h3 className="launchpadCard_title">NS Input Parameters</h3>
122 //"vnfd-catalog/vnfd[id=../../../constituent-vnfd[0]/vnfd-id-ref]/version";
124 vnfInputParametersHTML = (props) => {
125 let vnfInputParams = props.vnfInputParams;
126 const handleChange = (vnfIndex, parameterIndex, event) => props.updateVnfInputParam(vnfIndex, parameterIndex, event.target.value);
127 let vnfInputParamsHTML = [];
128 vnfInputParams && vnfInputParams.map(function(input, i) {
129 vnfInputParamsHTML.push(
130 <div className="configure-nsd_section" key={i}>
131 <h3 className="launchpadCard_title">{`VNF Input Parameters: ${input['name']}:${input['member-vnf-index-ref']}`}</h3>
133 input['input-parameter'].filter(function(p){
134 let regex = /vnfd\[(?:vnfd:)?id\s*=\s*'?"?(\S+?)'?"?\s*\]/
135 // if has id, then it belongs in a vnfd section
136 if (p.xpath.match(regex)) {
137 // look for matching vnfd
138 if ((p.xpath.match(regex)[1] == input['vnfd-id-ref'])) {
146 }).map(function(p, j){
147 let param = vnfInputParams[i]['input-parameter'][j];
148 return (<div className="inputControls" key={j}>
149 <TextInput label={(p.label || p.xpath)} value={param.value || param['default-value']} type="text" onChange={handleChange.bind(this, i, j)} />
157 return <div>{vnfInputParamsHTML}</div>;
159 nsPlacementGroupsHTML = (props) => {
160 let nsPlacementGroups = props.nsPlacementGroups;
161 let displayPlacementGroups = props.displayPlacementGroups;
162 if (nsPlacementGroups && nsPlacementGroups.length > 0 && displayPlacementGroups) {
164 <div className="configure-nsd_section">
165 <h3 className="launchpadCard_title">NS Placement Groups</h3>
167 nsPlacementGroups.map(function(input, i) {
169 <div key={i} className="configure-nsd_section-info">
170 <div className="placementGroup_description">
171 <div className="placementGroup_description-name">
172 <strong>{input.name}</strong> contains: {
173 input['member-vnfd'].map((m,i) => {
182 <div><em>{input.requirement}</em></div>
183 <div><strong>Strategy:</strong> {input.strategy}</div>
186 <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span> </span>
187 <div style={{display:'none'}}>
188 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
189 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
193 <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
194 <div style={{display:'none'}}>
195 <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'server-group')} />
196 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
199 <div className="host-aggregate">
201 <span> Host Aggregates <span onClick={props.nsFn.addHostAggregate.bind(self, i)} className="addInput" ><img src={imgAdd} />Add</span></span>
203 input['host-aggregate'].length > 0 ?
204 input['host-aggregate'].map((h,j) => {
205 let key = h.key || '';
206 let value = h.value || '';
209 <div className="input_group" key={j}>
210 <TextInput type="text" onChange={props.nsFn.hostAggregateUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
211 <TextInput type="text" onChange={props.nsFn.hostAggregateUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
212 <span onClick={props.nsFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
227 vnfPlacementGroupsHTML = (props) => {
228 let vnfPlacementGroups = props.vnfPlacementGroups;
229 let displayPlacementGroups = props.displayPlacementGroups;
230 if (vnfPlacementGroups && vnfPlacementGroups.length > 0 && displayPlacementGroups) {
231 return vnfPlacementGroups.map(function(input, i) {
233 <div className="configure-nsd_section" key={i}>
234 <h3 className="launchpadCard_title">{input['vnf-name']} VNF Placement Group</h3>
235 <div className="configure-nsd_section-info">
236 <div className="placementGroup_description">
237 <div className="placementGroup_description-name">
238 <strong>{input.name}</strong> contains: {
239 input['member-vdus'].map((m,i) => {
240 let s = m['member-vdu-ref'];
242 s = ', ' + m['member-vdu-ref']
248 <div><em>{input.requirement}</em></div>
249 <div><strong>Strategy</strong>: {input.strategy}</div>
252 <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
253 <div style={{display:'none'}}>
254 <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
255 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
259 <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
260 <div style={{display:'none'}}>
261 <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'server-group')} />
262 <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
265 <div className="host-aggregate">
267 <span> Host Aggregates <span onClick={props.vnfFn.addHostAggregate.bind(self, i)} className="addInput"><img src={imgAdd} />Add</span></span>
269 input['host-aggregate'].length > 0 ?
270 input['host-aggregate'].map((h,j) => {
271 let key = h.key || '';
272 let value = h.value || '';
275 <div className="input_group" key={j}>
276 <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
277 <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
278 <span onClick={props.vnfFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
292 vldsHTML = (props) => {
294 let ipProfileList = props.ipProfileList;
295 let vlds = props.vlds;
297 <div className="configure-nsd_section">
298 <h3 className="launchpadCard_title">VLDs</h3>
299 {vlds && vlds.map(function(v, i) {
300 let currentType = v.type;
301 let isVIM = (currentType == 'vim-network-name');
302 let isUnknown = (currentType == 'none') || ((currentType != 'vim-network-name') && (currentType != 'ip-profile-ref'));
304 <div key={self.props.nsd.id + '-' + i} className="inputControls">
305 <h4 className="inputControls-title">VLD: {v['short-name'] ? v['short-name'] : v['name']}</h4>
306 <label><span>Specify VLD Parameters</span></label>
307 <div className="inputControls-radioGroup">
308 <label className="inputControls-radio" style={{display: ipProfileList ? 'flex' : 'none'}}>
309 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={!isVIM && !isUnknown} value='ip-profile-ref' />
312 <label className="inputControls-radio">
313 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isVIM && !isUnknown} value='vim-network-name' />
316 <label className="inputControls-radio">
317 <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isUnknown} value='none' />
322 isUnknown ? null : isVIM ?
324 <TextInput label="Network Name" onChange={self.props.vldFn.updateValue(i, currentType)} value={v[currentType]} />
326 v['mgmt-network'].toUpperCase() == "TRUE" ?
327 <TextInput label="IPV4 NAT POOL NAME" placeholder={self.props.dataCenterID} onChange={self.props.vldFn.updateValue(i, 'ipv4-nat-pool-name')} value={v['ipv4-nat-pool-name']} />
333 label="IP PROFILE NAME"
334 options={ipProfileList && ipProfileList.map(function(ip) {
341 v['ip-profile-ref'] ? false : true
343 defaultValue={v['ip-profile-ref']}
344 onChange={self.props.vldFn.updateValue(i, currentType)}>
355 ipProfilesHTML = (props) => {
356 let vldHasIPprofile = false;
357 props.vlds && props.vlds.map(function(v){
358 if(v.type == 'ip-profile-ref') {
359 vldHasIPprofile = true;
362 let ipProfileList = props.ipProfileList;
363 return ipProfileList && vldHasIPprofile &&
365 <div className="configure-nsd_section">
366 <h3 className="launchpadCard_title">IP Profiles</h3>
369 ipProfileList && ipProfileList.map(function(ip, j) {
370 let ipl = ip['ip-profile-params'];
372 <div className="inputControls" key={j}>
373 <div className="inputControls-title" >
376 <div className="inputControls-radioGroup">
377 <label className="inputControls-radio">
378 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv4'} value='ipv4' />
381 <label className="inputControls-radio">
382 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv6'} value='ipv6' />
385 <label className="inputControls-radio">
386 <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'unknown'} value='unknown' />
391 label="subnet address"
392 onChange={props.ipProfileFn.updateProfile(j, 'subnet-address')}
393 value={ipl['subnet-address']}
396 label="gateway address"
397 onChange={props.ipProfileFn.updateProfile(j, 'gateway-address')}
398 value={ipl['gateway-address']}
401 label="security group"
402 onChange={props.ipProfileFn.updateProfile(j, 'security-group')}
403 value={ipl['security-group']}
406 label="subnet prefix pool"
407 onChange={props.ipProfileFn.updateProfile(j, 'subnet-prefix-pool')}
408 value={ipl['subnet-prefix-pool']}
411 <div style={{display:'flex'}}>
412 DNS SERVERS <span onClick={props.dnsFn.addDNS(j)} className="addInput"><img src={imgAdd} />Add</span>
415 ipl['dns-server'] && ipl['dns-server'].map(function(dns, k) {
417 <div key={k} style={{display:'flex'}}>
419 onChange={props.dnsFn.updateDNS(j,k)}
420 value={ipl['dns-server'][k].address}
422 <span onClick={props.dnsFn.removeDNS(j,k)} className="removeInput">
423 <img src={imgRemove} />Remove</span>
429 <div className="inputControls-radioGroup">
430 <label className="inputControls-radio">
433 name={'ip-profile-dhcp' + j }
434 onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
435 checked={ipl.hasOwnProperty('dhcp-params') && ipl['dhcp-params'].enabled}
439 <label className="inputControls-radio">
441 name={'ip-profile-dhcp' + j }
442 onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
443 checked={!ipl.hasOwnProperty('dhcp-params') || !ipl['dhcp-params'].enabled}
449 (ipl['dhcp-params'] && ipl['dhcp-params'].enabled) ? dhcpHTML(props, ipl, j) : null
456 function dhcpHTML(props, ipl, j){
459 label="DHCP Start Address"
460 onChange={props.ipProfileFn.updateDHCP(j, 'start-address')}
461 value={ipl['dhcp-params'] && ipl['dhcp-params']['start-address']}
465 onChange={props.ipProfileFn.updateDHCP(j, 'count')}
466 value={ipl['dhcp-params'] && ipl['dhcp-params']['count']}
472 sshKeysHTML = (props) => {
473 let sshKeysList = props.sshKeysList;
474 let sshKeysRef = props.sshKeysRef;
475 if(sshKeysList && sshKeysList.length > 0) {
477 <div className="configure-nsd_section">
478 <h3 className="launchpadCard_title">SSH Authorized Keys</h3>
481 sshKeysRef.map(function(ref, i) {
482 let keyref = JSON.stringify(ref)
484 <div key={keyref.name + '-' + i} className="inputControls inputControls-sshkeys">
489 options={sshKeysList && sshKeysList.map(function(k) {
495 ref="keyPairSelection"
497 defaultValue={keyref.name || sshKeysList[0].name}
498 onChange={props.sshFn.updateKeyRef(i)}>
503 <span onClick={props.sshFn.updateKeyRef(i, true)} className="removeInput">
504 <img src={imgRemove} />
512 <div className="inputControls inputControls-sshkeys ">
513 <label style={{display: 'flex', 'flexDirection': 'row'}}>
515 <span onClick={props.sshFn.updateKeyRef().bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
525 usersHTML = (props) => {
526 let usersFn = props.usersFn;
527 let sshKeysList = props.sshKeysList;
528 let usersList = props.usersList && props.usersList.map(function(u, i) {
529 let sshKeysRef = u['ssh-authorized-key'];
531 <div className="input_group input_group-users" key={i}>
532 <div className="inputControls">
533 <div style={{fontWeight: 'bold', display: 'flex'}}>USER <span onClick={usersFn.remove(i)} className="removeInput"><img src={imgRemove} />Remove</span></div>
535 <TextInput onChange={usersFn.update(i, 'name')} label="USERNAME" value={i.name} />
536 <TextInput onChange={usersFn.update(i, 'user-info')} label="REAL NAME" value={i.gecos} />
538 sshKeysRef.map(function(ref, j) {
539 let keyref = JSON.stringify(ref)
541 <div key={keyref.name + '-' + i + '-' + j} className="inputControls inputControls-sshkeys">
546 options={sshKeysList && sshKeysList.map(function(k) {
552 ref="keyPairSelection"
555 onChange={usersFn.updateSSHkeyRef(i, j)}>
560 sshKeysRef.length > 0 ?
562 <span onClick={usersFn.updateSSHkeyRef(i, j, true)} className="removeInput">
563 <img src={imgRemove} />
574 <div className="inputControls inputControls-sshkeys ">
575 <label style={{display: 'flex', 'flexDirection': 'row', 'alignItems': 'center'}}>
577 <span onClick={usersFn.updateSSHkeyRef(i).bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
588 <div className="configure-nsd_section">
589 <h3 className="launchpadCard_title">USERS</h3>
591 <div className="inputControls inputControls-sshkeys inputControls-addUser ">
592 <span onClick={usersFn.add(sshKeysList)} className="addInput">
602 const props = this.props;
607 <div className="instantiateInputParams">
610 this.nsConfigHTML(props)
614 this.vnfCloudAccountsHTML(props)
618 this.inputParametersHTML(props)
621 //VNF INPUT PARAMETERS
622 this.vnfInputParametersHTML(props)
626 // self.props.selectedResourceOrchestrator['ro-account-type'] == 'rift-ro' ?
628 this.nsPlacementGroupsHTML(props) : null
632 // self.props.selectedResourceOrchestrator['ro-account-type'] == 'rift-ro' ?
633 //VNF PLACEMENTGROUPS
634 this.vnfPlacementGroupsHTML(props) : null
641 //IP PROFILE CONFIGURATION
642 this.ipProfilesHTML(props)
645 //SSH KEY ASSIGNMENTS
646 this.sshKeysHTML(props)
650 this.usersHTML(props)
657 function showInput(e){
658 let target = e.target;
659 if(target.parentElement.classList.contains("addInput")) {
660 target = target.parentElement;
662 target.style.display = 'none';
663 target.parentElement.nextElementSibling.style.display = 'flex';
664 // e.target.parentElement.nextElementSibling.children[1].style.display = 'initial';
666 function hideInput(e){
667 let target = e.target;
668 if(target.parentElement.classList.contains("removeInput")) {
669 target = target.parentElement;
671 target.parentElement.style.display = 'none';
672 target.parentElement.previousElementSibling.children[1].style.display = 'inline';
673 target.previousSibling.value = '';
676 function removeDNS(){}
677 function constructROOptions(resourceOrchestrators){
678 let ROOptions = resourceOrchestrators && resourceOrchestrators.map(function(ro, index) {
686 function constructCloudAccountOptions(cloudAccounts){
687 let CloudAccountOptions = cloudAccounts && cloudAccounts.map(function(ca, index) {
693 return CloudAccountOptions;
695 function constructDataCenterOptions(dataCenters){
696 let DataCenterOptions = dataCenters && dataCenters.map(function(dc, index) {
702 return DataCenterOptions;
704 function dataCentersHTML(dataCenters, onChange, initial) {
705 //Build DataCenter options
706 //Relook at this, why is it an object?
707 let DataCenterOptions = [];
708 DataCenterOptions = dataCenters && dataCenters.map(function(dc, index) {
714 if (dataCenters && dataCenters.length > 0) {
717 <SelectOption initial={!!initial} options={DataCenterOptions} onChange={onChange} />
722 function updateNewSshKeyRefSelection(e) {
724 newRefSelection: e.target.value
727 function resetRef() {
729 newRefSelection: null
732 InstantiateInputParams.defaultProps = {