Rift.IO OSM R1 Initial Submission
[osm/UI.git] / skyquake / plugins / launchpad / src / instantiate / instantiateInputParams.jsx
1
2 /*
3  * 
4  *   Copyright 2016 RIFT.IO Inc
5  *
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
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
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';
26
27 export default class InstantiateInputParams extends Component {
28   constructor(props) {
29     super(props);
30   }
31   nsConfigHTML = (props) => {
32     return (
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}/>
36           <label>Select VIM Account
37             <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} onChange={props.nsFn.updateSelectedCloudAccount} />
38           </label>
39           {
40             isOpenMano(props.selectedCloudAccount) ? this.dataCentersHTML(props.dataCenters[selectedCloudAccount.name], props.nsFn.updateSelectedDataCenter) : null
41           }
42         </div>
43       </div>
44     )
45   }
46   vnfCloudAccountsHTML = (props) => {
47     let nsd = props.nsd;
48     let dataCenters = props.dataCenters;
49     return (
50       <div className="configure-nsd_section">
51         <h3 className="launchpadCard_title">NS/VNF ACCOUNT PLACEMENTS</h3>
52         {
53
54             //selectedNSDid
55               nsd['constituent-vnfd'] && nsd['constituent-vnfd'].map(function(v, i) {
56                 let defaultValue = false;
57                 if(props.vnfdCloudAccounts && props.vnfdCloudAccounts.hasOwnProperty(v['member-vnf-index'])) {
58                   defaultValue = props.vnfdCloudAccounts[v['member-vnf-index']]
59                 }
60                 return (
61                     <div className="inputControls" key={i}>
62                     <h4 className="inputControls-title">VNFD: {v.name}</h4>
63                       <label>Select VIM Account
64                         <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} initial={true} onChange={props.vnfFn.updateSelectedCloudAccount.bind(v['member-vnf-index'])} defaultValue={defaultValue} />
65                       </label>
66                       {
67                         isOpenMano(defaultValue) ? dataCentersHTML(dataCenters[defaultValue.account.name], props.vnfFn.updateSelectedDataCenter(v['member-vnf-index'])) : null
68                       }
69                       {
70                         (props.configAgentAccounts && props.configAgentAccounts.length > 0) ?
71                         <label>Select Config Agent Account
72                           <SelectOption options={props.configAgentAccounts && props.configAgentAccounts.map(function(c) {
73                             return {
74                               label: c.name,
75                               value: c.name
76                             }
77                           })} initial={true} onChange={props.vnfFn.updateSelectedConfigAgent(v['member-vnf-index'])} defaultValue={false} />
78                         </label> : null
79                       }
80                     </div>
81                 )
82               })
83         }
84       </div>
85     )
86   }
87   inputParametersHTML = (props) => {
88     let inputParameters = props.inputParameters;
89     return inputParameters && inputParameters.map(function(input, i) {
90         return (
91                 <div className="configure-nsd_section" key={i}>
92                   <h3 className="launchpadCard_title">Input Parameters</h3>
93                   <div className="inputControls">
94                       <TextInput label={ input.label || input.xpath } type="text" onChange={props.updateInputParam.bind(self, i)} />
95                   </div>
96                 </div>
97         )
98       })
99   }
100   nsPlacementGroupsHTML = (props) => {
101     let nsPlacementGroups = props.nsPlacementGroups;
102     let displayPlacementGroups = props.displayPlacementGroups;
103     if (nsPlacementGroups && nsPlacementGroups.length > 0 && displayPlacementGroups) {
104       return (
105         <div className="configure-nsd_section">
106           <h3 className="launchpadCard_title">NS Placement Groups</h3>
107             {
108               nsPlacementGroups.map(function(input, i) {
109                 return (
110                   <div  key={i} className="configure-nsd_section-info">
111                     <div className="placementGroup_description">
112                       <div className="placementGroup_description-name">
113                         <strong>{input.name}</strong> contains: {
114                           input['member-vnfd'].map((m,i) => {
115                             let s = m.name;
116                             if(i>0) {
117                               s = ', ' + m.name
118                             };
119                             return s;
120                           })
121                         }
122                       </div>
123                       <div><em>{input.requirement}</em></div>
124                       <div><strong>Strategy:</strong> {input.strategy}</div>
125                     </div>
126                     <label>
127                       <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span> </span>
128                       <div  style={{display:'none'}}>
129                       <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
130                       <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
131                       </div>
132                     </label>
133                     <label>
134                       <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
135                       <div style={{display:'none'}}>
136                         <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'server-group')} />
137                         <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
138                       </div>
139                     </label>
140                     <div className="host-aggregate">
141                       <label>
142                         <span> Host Aggregates <span onClick={props.nsFn.addHostAggregate.bind(self, i)} className="addInput"  ><img src={imgAdd} />Add</span></span>
143                       {
144                         input['host-aggregate'].length > 0 ?
145                           input['host-aggregate'].map((h,j) => {
146                             let key = h.key || '';
147                             let value = h.value || '';
148                             return (
149
150                                   <div className="input_group" key={j}>
151                                     <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
152                                     <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, j, 'value')} placeholder="VALUE"  value={value} />
153                                     <span onClick={props.nsFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
154                                   </div>
155                             )
156                           }) : ''
157                       }
158                       </label>
159                     </div>
160                     </div>
161                 );
162               })
163             }
164        </div>
165      );
166     }
167   }
168   vnfPlacementGroupsHTML = (props) => {
169     let vnfPlacementGroups = props.vnfPlacementGroups;
170     let displayPlacementGroups = props.displayPlacementGroups;
171     if (vnfPlacementGroups && vnfPlacementGroups.length > 0 && displayPlacementGroups) {
172       return vnfPlacementGroups.map(function(input, i) {
173             return (
174               <div className="configure-nsd_section" key={i}>
175                 <h3 className="launchpadCard_title">{input['vnf-name']} VNF Placement Group</h3>
176                   <div className="configure-nsd_section-info">
177                     <div className="placementGroup_description">
178                       <div className="placementGroup_description-name">
179                         <strong>{input.name}</strong> contains: {
180                           input['member-vdus'].map((m,i) => {
181                             let s = m['member-vdu-ref'];
182                             if(i>0) {
183                               s = ', ' + m['member-vdu-ref']
184                             };
185                             return s;
186                           })
187                         }
188                       </div>
189                       <div><em>{input.requirement}</em></div>
190                       <div><strong>Strategy</strong>: {input.strategy}</div>
191                     </div>
192                     <label>
193                       <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
194                       <div  style={{display:'none'}}>
195                         <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
196                            <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
197                       </div>
198                     </label>
199                     <label>
200                       <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
201                       <div  style={{display:'none'}}>
202                         <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'server-group')} />
203                          <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
204                       </div>
205                     </label>
206                     <div className="host-aggregate">
207                     <label>
208                       <span> Host Aggregates <span onClick={props.vnfFn.addHostAggregate.bind(self, i)} className="addInput"><img src={imgAdd} />Add</span></span>
209                       {
210                         input['host-aggregate'].length > 0 ?
211                           input['host-aggregate'].map((h,j) => {
212                             let key = h.key || '';
213                             let value = h.value || '';
214                             return (
215
216                                   <div className="input_group" key={j}>
217                                     <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
218                                     <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'value')} placeholder="VALUE"  value={value} />
219                                     <span onClick={props.vnfFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
220                                   </div>
221
222                             )
223                           }) : ''
224                       }
225                       </label>
226                     </div>
227                     </div>
228                 </div>
229             );
230           });
231     }
232   }
233   vldsHTML = (props) => {
234     let self = this;
235     let ipProfileList = props.ipProfileList;
236     let vlds = props.vlds;
237     return vlds && (
238       <div className="configure-nsd_section">
239         <h3 className="launchpadCard_title">VLDs</h3>
240             {vlds && vlds.map(function(v, i) {
241                   let currentType = v.type;
242                   let isVIM = (currentType == 'vim-network-name');
243                   let isUnknown = (currentType == 'unknown') || ((currentType != 'vim-network-name') && (currentType != 'ip-profile-ref'));
244                   return (
245                     <div key={self.props.nsd.id + '-' + i} className="inputControls">
246                         <h4 className="inputControls-title">VLD: {v['short-name']}</h4>
247                         <div  className="inputControls-radioGroup">
248                           <label className="inputControls-radio" style={{display: ipProfileList ? 'flex' : 'none'}}>
249                             <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={!isVIM && !isUnknown} value='ip-profile-ref' />
250                             IP Profile
251                           </label>
252                           <label className="inputControls-radio">
253                             <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isVIM && !isUnknown} value='vim-network-name' />
254                             VIM Network Name
255                           </label>
256                           <label className="inputControls-radio">
257                             <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isUnknown} value='unknown' />
258                             Unknown
259                           </label>
260                         </div>
261                           {
262                             isUnknown ? null : isVIM ?
263                             <TextInput label="Network Name" onChange={self.props.vldFn.updateValue(i, currentType)} value={v[currentType]} /> :
264                             <div>
265                               <SelectOption
266                               label="IP PROFILE NAME"
267                                 options={ipProfileList && ipProfileList.map(function(ip) {
268                                   return {
269                                     label: ip.name,
270                                     value: ip.name
271                                   }
272                                 })}
273                                 initial={
274                                   v['ip-profile-ref'] ? false : true
275                                 }
276                                 defaultValue={v['ip-profile-ref']}
277                                 onChange={self.props.vldFn.updateValue(i, currentType)}>
278                               </SelectOption>
279
280                             </div>
281                           }
282                     </div>
283                   )
284                 })}
285       </div>
286     );
287   }
288   ipProfilesHTML = (props) => {
289     let ipProfileList = props.ipProfileList;
290     return ipProfileList &&
291       (
292       <div className="configure-nsd_section">
293         <h3 className="launchpadCard_title">IP Profiles</h3>
294         {
295           //IP Config
296           ipProfileList && ipProfileList.map(function(ip, j) {
297             let ipl = ip['ip-profile-params'];
298               return (
299                 <div className="inputControls" key={j}>
300                   <div className="inputControls-title" >
301                     {ip.name}
302                   </div>
303                   <div  className="inputControls-radioGroup">
304                     <label className="inputControls-radio">
305                       <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv4'} value='ipv4' />
306                       ipv4
307                     </label>
308                     <label className="inputControls-radio">
309                       <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv6'} value='ipv6' />
310                       ipv6
311                     </label>
312                     <label className="inputControls-radio">
313                       <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'unknown'} value='unknown' />
314                       unknown
315                     </label>
316                   </div>
317                   <TextInput
318                     label="subnet address"
319                     onChange={props.ipProfileFn.updateProfile(j, 'subnet-address')}
320                     value={ipl['subnet-address']}
321                     />
322                   <TextInput
323                     label="gateway address"
324                     onChange={props.ipProfileFn.updateProfile(j, 'gateway-address')}
325                     value={ipl['gateway-address']}
326                     />
327                   <TextInput
328                     label="security group"
329                     onChange={props.ipProfileFn.updateProfile(j, 'security-group')}
330                     value={ipl['security-group']}
331                     />
332                     <label>
333                       <div style={{display:'flex'}}>
334                         DNS SERVERS <span onClick={props.dnsFn.addDNS(j)} className="addInput"><img src={imgAdd} />Add</span>
335                       </div>
336                       {
337                         ipl['dns-server'] && ipl['dns-server'].map(function(dns, k) {
338                           return (
339                             <div key={k} style={{display:'flex'}}>
340                               <TextInput
341                                   onChange={props.ipProfileFn.updateProfile(j,k)}
342                                   value={ipl['dns-server'][k]}
343                                   />
344                               <span onClick={props.dnsFn.removeDNS(j,k)} className="removeInput">
345                                 <img src={imgRemove} />Remove</span>
346                             </div>
347                           )
348                         })
349                       }
350                     </label>
351                   <div  className="inputControls-radioGroup">
352                     <label className="inputControls-radio">
353                     DHCP ENABLED
354                       <input type="radio"
355                         name={'ip-profile-dhcp' + j }
356                         onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
357                         checked={ipl.hasOwnProperty('dhcp-params') && ipl['dhcp-params'].enabled}
358                         value={true} />
359                       YES
360                     </label>
361                     <label className="inputControls-radio">
362                       <input type="radio"
363                         name={'ip-profile-dhcp' + j }
364                         onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
365                         checked={!ipl.hasOwnProperty('dhcp-params') || !ipl['dhcp-params'].enabled}
366                         value={false} />
367                       NO
368                     </label>
369                   </div>
370                   {
371                     (ipl['dhcp-params'] && ipl['dhcp-params'].enabled) ? dhcpHTML(props, ipl, j) : null
372                   }
373                 </div>
374               )
375           })
376         }
377         </div>);
378     function dhcpHTML(props, ipl, j){
379       return (<div>
380                   <TextInput
381                     label="DCHP Start Address"
382                     onChange={props.ipProfileFn.updateDHCP(j, 'start-address')}
383                     value={ipl['dhcp-params'] && ipl['dhcp-params']['start-address']}
384                     />
385                   <TextInput
386                     label="DCHP Count"
387                     onChange={props.ipProfileFn.updateDHCP(j, 'count')}
388                     value={ipl['dhcp-params'] && ipl['dhcp-params']['count']}
389                     />
390                 </div>
391                 );
392     }
393   }
394   sshKeysHTML = (props) => {
395     let sshKeysList = props.sshKeysList;
396     let sshKeysRef = props.sshKeysRef;
397     if(sshKeysList && sshKeysList.length > 0) {
398       return (
399         <div className="configure-nsd_section">
400           <h3 className="launchpadCard_title">SSH Authorized Keys</h3>
401
402             {
403               sshKeysRef.map(function(ref, i) {
404                 return (
405                   <div key={i} className="inputControls inputControls-sshkeys">
406                     <label>
407                       <div>
408                       <SelectOption
409                         label="Key Pair"
410                         options={sshKeysList && sshKeysList.map(function(k) {
411                           return {
412                             label: k.name,
413                             value: k
414                           }
415                         })}
416                         ref="keyPairSelection"
417                         initial={false}
418                         defaultValue={sshKeysList[0].name}
419                         onChange={self.props.updateSshKeyRef(i)}>
420                       </SelectOption>
421                       </div>
422                     </label>
423                     <label>
424                       <span onClick={self.props.updateSshKeyRef(i, true)} className="removeInput">
425                         <img src={imgRemove} />
426                         Remove
427                       </span>
428                     </label>
429                   </div>
430                 )
431               })
432             }
433             <div className="inputControls inputControls-sshkeys ">
434               <label style={{display: 'flex', 'flexDirection': 'row'}}>
435               SSH KEY PAIR
436                 <span onClick={self.props.updateSshKeyRef().bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
437                   <img src={imgAdd} />
438                   ADD
439                 </span>
440               </label>
441             </div>
442         </div>
443       );
444     }
445   }
446   usersHTML = (props) => {
447     let usersFn = props.usersFn;
448     let usersList = props.usersList && props.usersList.map(function(u, i) {
449       return (
450         <div className="input_group input_group-users" key={i}>
451           <div className="inputControls">
452           <div style={{fontWeight: 'bold', display: 'flex'}}>USER <span onClick={usersFn.remove(i)} className="removeInput"><img src={imgRemove} />Remove</span></div>
453             <TextInput onChange={usersFn.update(i, 'name')} label="USERNAME" value={i.name} />
454             <TextInput onChange={usersFn.update(i, 'gecos')} label="REAL NAME" value={i.gecos} />
455             <TextInput onChange={usersFn.update(i, 'passwd')} type="password" label="PASSWORD" value={i.passwd} />
456           </div>
457         </div>
458       )
459     });
460     return (
461       <div className="configure-nsd_section">
462         <h3 className="launchpadCard_title">USERS</h3>
463         {usersList}
464         <div className="inputControls inputControls-sshkeys ">
465             <span onClick={usersFn.add} className="addInput">
466               <img src={imgAdd} onClick={usersFn.add} />
467               ADD USER
468             </span>
469         </div>
470       </div>
471     )
472   }
473
474   render() {
475     const props = this.props;
476     let html;
477     let self = this;
478
479     html = (
480         <div className="instantiateInputParams">
481           {
482             //NS NAMEA AND CLOUD
483             this.nsConfigHTML(props)
484           }
485           {
486             //VNF VIM ACCOUNTS
487             this.vnfCloudAccountsHTML(props)
488           }
489           {
490             //INPUT PARAMETERS
491             this.inputParametersHTML(props)
492           }
493           {
494             //NS PLACEMENTGROUPS
495             this.nsPlacementGroupsHTML(props)
496           }
497           {
498             //VNF PLACEMENTGROUPS
499             this.vnfPlacementGroupsHTML(props)
500           }
501           {
502             //VLD CONFIGURATION
503             this.vldsHTML(props)
504           }
505           {
506             //IP PROFILE CONFIGURATION
507             this.ipProfilesHTML(props)
508           }
509           {
510             //SSH KEY ASSIGNMENTS
511             this.sshKeysHTML(props)
512           }
513           {
514             //USER MANAGEMENT
515             this.usersHTML(props)
516           }
517         </div>
518     )
519     return html;
520   }
521 }
522 function showInput(e){
523   let target = e.target;
524   if(target.parentElement.classList.contains("addInput")) {
525     target = target.parentElement;
526   }
527   target.style.display = 'none';
528   target.parentElement.nextElementSibling.style.display = 'flex';
529   // e.target.parentElement.nextElementSibling.children[1].style.display = 'initial';
530 }
531 function hideInput(e){
532   let target = e.target;
533   if(target.parentElement.classList.contains("removeInput")) {
534     target = target.parentElement;
535   }
536   target.parentElement.style.display = 'none';
537   target.parentElement.previousElementSibling.children[1].style.display = 'inline';
538   target.previousSibling.value = '';
539 }
540 function addDNS(){}
541 function removeDNS(){}
542 function constructCloudAccountOptions(cloudAccounts){
543   let CloudAccountOptions = cloudAccounts && cloudAccounts.map(function(ca, index) {
544     return {
545       label: ca.name,
546       value: ca
547     }
548   });
549   return CloudAccountOptions;
550 }
551 function dataCentersHTML(state, onChange) {
552   //Build DataCenter options
553   //Relook at this, why is it an object?
554   let dataCenters = state.dataCenters || [];
555   let DataCenterOptions = {};
556   if(dataCenters){
557     for (let d in dataCenters) {
558       DataCenterOptions[d] = dataCenters[d].map(function(dc, index) {
559         return {
560           label: dc.name,
561           value: dc.uuid
562         }
563       });
564     }
565   }
566   if (dataCenters.length > 0) {
567     return (
568       <label>Select Data Center
569         <SelectOption options={DataCenterOptions} onChange={onChange} />
570       </label>
571     )
572   }
573 }
574 function isOpenMano(account) {
575   if (account) {
576     let a = account;
577     if (a.constructor.name == 'String') {
578       a = JSON.parse(a);
579     }
580     if(a.hasOwnProperty('account')) {
581       a = a.account;
582     }
583     return a['account-type'] == 'openmano';
584   } else {
585     return false;
586   }
587 }
588 function updateNewSshKeyRefSelection(e) {
589   this.setState({
590     newRefSelection: e.target.value
591   })
592 }
593 function resetRef() {
594     this.setState({
595     newRefSelection: null
596   })
597 }
598 InstantiateInputParams.defaultProps = {
599   data: [],
600   sshKeysList: [],
601   sshKeysRef: [],
602   users: {}
603 }