--- /dev/null
+
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+import React, {Component} from 'react';
+import ReactDOM from 'react-dom';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../node_modules/open-iconic/svg/trash.svg'
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import './instantiateInputParams.scss';
+
+export default class InstantiateInputParams extends Component {
+ constructor(props) {
+ super(props);
+ }
+ nsConfigHTML = (props) => {
+ return (
+ <div className="configure-nsd_section">
+ <div className="inputControls">
+ <TextInput label="Instance Name" type="text" pattern="^[a-zA-Z0-9_]*$" style={{textAlign:'left'}} onChange={props.updateName} value={props.name}/>
+ <label>Select VIM Account
+ <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} onChange={props.nsFn.updateSelectedCloudAccount} />
+ </label>
+ {
+ isOpenMano(props.selectedCloudAccount) ? this.dataCentersHTML(props.dataCenters[selectedCloudAccount.name], props.nsFn.updateSelectedDataCenter) : null
+ }
+ </div>
+ </div>
+ )
+ }
+ vnfCloudAccountsHTML = (props) => {
+ let nsd = props.nsd;
+ let dataCenters = props.dataCenters;
+ return (
+ <div className="configure-nsd_section">
+ <h3 className="launchpadCard_title">NS/VNF ACCOUNT PLACEMENTS</h3>
+ {
+
+ //selectedNSDid
+ nsd['constituent-vnfd'] && nsd['constituent-vnfd'].map(function(v, i) {
+ let defaultValue = false;
+ if(props.vnfdCloudAccounts && props.vnfdCloudAccounts.hasOwnProperty(v['member-vnf-index'])) {
+ defaultValue = props.vnfdCloudAccounts[v['member-vnf-index']]
+ }
+ return (
+ <div className="inputControls" key={i}>
+ <h4 className="inputControls-title">VNFD: {v.name}</h4>
+ <label>Select VIM Account
+ <SelectOption options={constructCloudAccountOptions(props.cloudAccounts)} initial={true} onChange={props.vnfFn.updateSelectedCloudAccount.bind(v['member-vnf-index'])} defaultValue={defaultValue} />
+ </label>
+ {
+ isOpenMano(defaultValue) ? dataCentersHTML(dataCenters[defaultValue.account.name], props.vnfFn.updateSelectedDataCenter(v['member-vnf-index'])) : null
+ }
+ {
+ (props.configAgentAccounts && props.configAgentAccounts.length > 0) ?
+ <label>Select Config Agent Account
+ <SelectOption options={props.configAgentAccounts && props.configAgentAccounts.map(function(c) {
+ return {
+ label: c.name,
+ value: c.name
+ }
+ })} initial={true} onChange={props.vnfFn.updateSelectedConfigAgent(v['member-vnf-index'])} defaultValue={false} />
+ </label> : null
+ }
+ </div>
+ )
+ })
+ }
+ </div>
+ )
+ }
+ inputParametersHTML = (props) => {
+ let inputParameters = props.inputParameters;
+ return inputParameters && inputParameters.map(function(input, i) {
+ return (
+ <div className="configure-nsd_section" key={i}>
+ <h3 className="launchpadCard_title">Input Parameters</h3>
+ <div className="inputControls">
+ <TextInput label={ input.label || input.xpath } type="text" onChange={props.updateInputParam.bind(self, i)} />
+ </div>
+ </div>
+ )
+ })
+ }
+ nsPlacementGroupsHTML = (props) => {
+ let nsPlacementGroups = props.nsPlacementGroups;
+ let displayPlacementGroups = props.displayPlacementGroups;
+ if (nsPlacementGroups && nsPlacementGroups.length > 0 && displayPlacementGroups) {
+ return (
+ <div className="configure-nsd_section">
+ <h3 className="launchpadCard_title">NS Placement Groups</h3>
+ {
+ nsPlacementGroups.map(function(input, i) {
+ return (
+ <div key={i} className="configure-nsd_section-info">
+ <div className="placementGroup_description">
+ <div className="placementGroup_description-name">
+ <strong>{input.name}</strong> contains: {
+ input['member-vnfd'].map((m,i) => {
+ let s = m.name;
+ if(i>0) {
+ s = ', ' + m.name
+ };
+ return s;
+ })
+ }
+ </div>
+ <div><em>{input.requirement}</em></div>
+ <div><strong>Strategy:</strong> {input.strategy}</div>
+ </div>
+ <label>
+ <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span> </span>
+ <div style={{display:'none'}}>
+ <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
+ <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
+ </div>
+ </label>
+ <label>
+ <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
+ <div style={{display:'none'}}>
+ <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, 'server-group')} />
+ <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
+ </div>
+ </label>
+ <div className="host-aggregate">
+ <label>
+ <span> Host Aggregates <span onClick={props.nsFn.addHostAggregate.bind(self, i)} className="addInput" ><img src={imgAdd} />Add</span></span>
+ {
+ input['host-aggregate'].length > 0 ?
+ input['host-aggregate'].map((h,j) => {
+ let key = h.key || '';
+ let value = h.value || '';
+ return (
+
+ <div className="input_group" key={j}>
+ <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
+ <TextInput type="text" onChange={props.nsFn.placementGroupUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
+ <span onClick={props.nsFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
+ </div>
+ )
+ }) : ''
+ }
+ </label>
+ </div>
+ </div>
+ );
+ })
+ }
+ </div>
+ );
+ }
+ }
+ vnfPlacementGroupsHTML = (props) => {
+ let vnfPlacementGroups = props.vnfPlacementGroups;
+ let displayPlacementGroups = props.displayPlacementGroups;
+ if (vnfPlacementGroups && vnfPlacementGroups.length > 0 && displayPlacementGroups) {
+ return vnfPlacementGroups.map(function(input, i) {
+ return (
+ <div className="configure-nsd_section" key={i}>
+ <h3 className="launchpadCard_title">{input['vnf-name']} VNF Placement Group</h3>
+ <div className="configure-nsd_section-info">
+ <div className="placementGroup_description">
+ <div className="placementGroup_description-name">
+ <strong>{input.name}</strong> contains: {
+ input['member-vdus'].map((m,i) => {
+ let s = m['member-vdu-ref'];
+ if(i>0) {
+ s = ', ' + m['member-vdu-ref']
+ };
+ return s;
+ })
+ }
+ </div>
+ <div><em>{input.requirement}</em></div>
+ <div><strong>Strategy</strong>: {input.strategy}</div>
+ </div>
+ <label>
+ <span> Availability Zone <span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
+ <div style={{display:'none'}}>
+ <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'availability-zone')} />
+ <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
+ </div>
+ </label>
+ <label>
+ <span> Affinity/Anti-affinity Server Group<span onClick={showInput} className="addInput"><img src={imgAdd} />Add</span></span>
+ <div style={{display:'none'}}>
+ <TextInput type="text" onChange={props.vnfFn.placementGroupUpdate.bind(self, i, 'server-group')} />
+ <span onClick={hideInput} className="removeInput"><img src={imgRemove} />Remove</span>
+ </div>
+ </label>
+ <div className="host-aggregate">
+ <label>
+ <span> Host Aggregates <span onClick={props.vnfFn.addHostAggregate.bind(self, i)} className="addInput"><img src={imgAdd} />Add</span></span>
+ {
+ input['host-aggregate'].length > 0 ?
+ input['host-aggregate'].map((h,j) => {
+ let key = h.key || '';
+ let value = h.value || '';
+ return (
+
+ <div className="input_group" key={j}>
+ <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'key')} placeholder="KEY" value={key} />
+ <TextInput type="text" onChange={props.vnfFn.hostAggregateUpdate.bind(self, i, j, 'value')} placeholder="VALUE" value={value} />
+ <span onClick={props.vnfFn.removeHostAggregate.bind(self, i, j)} className="removeInput"><img src={imgRemove} />Remove</span>
+ </div>
+
+ )
+ }) : ''
+ }
+ </label>
+ </div>
+ </div>
+ </div>
+ );
+ });
+ }
+ }
+ vldsHTML = (props) => {
+ let self = this;
+ let ipProfileList = props.ipProfileList;
+ let vlds = props.vlds;
+ return vlds && (
+ <div className="configure-nsd_section">
+ <h3 className="launchpadCard_title">VLDs</h3>
+ {vlds && vlds.map(function(v, i) {
+ let currentType = v.type;
+ let isVIM = (currentType == 'vim-network-name');
+ let isUnknown = (currentType == 'unknown') || ((currentType != 'vim-network-name') && (currentType != 'ip-profile-ref'));
+ return (
+ <div key={self.props.nsd.id + '-' + i} className="inputControls">
+ <h4 className="inputControls-title">VLD: {v['short-name']}</h4>
+ <div className="inputControls-radioGroup">
+ <label className="inputControls-radio" style={{display: ipProfileList ? 'flex' : 'none'}}>
+ <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={!isVIM && !isUnknown} value='ip-profile-ref' />
+ IP Profile
+ </label>
+ <label className="inputControls-radio">
+ <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isVIM && !isUnknown} value='vim-network-name' />
+ VIM Network Name
+ </label>
+ <label className="inputControls-radio">
+ <input type="radio" name={'vld-' + i } onChange={self.props.vldFn.updateType(i)} checked={isUnknown} value='unknown' />
+ Unknown
+ </label>
+ </div>
+ {
+ isUnknown ? null : isVIM ?
+ <TextInput label="Network Name" onChange={self.props.vldFn.updateValue(i, currentType)} value={v[currentType]} /> :
+ <div>
+ <SelectOption
+ label="IP PROFILE NAME"
+ options={ipProfileList && ipProfileList.map(function(ip) {
+ return {
+ label: ip.name,
+ value: ip.name
+ }
+ })}
+ initial={
+ v['ip-profile-ref'] ? false : true
+ }
+ defaultValue={v['ip-profile-ref']}
+ onChange={self.props.vldFn.updateValue(i, currentType)}>
+ </SelectOption>
+
+ </div>
+ }
+ </div>
+ )
+ })}
+ </div>
+ );
+ }
+ ipProfilesHTML = (props) => {
+ let ipProfileList = props.ipProfileList;
+ return ipProfileList &&
+ (
+ <div className="configure-nsd_section">
+ <h3 className="launchpadCard_title">IP Profiles</h3>
+ {
+ //IP Config
+ ipProfileList && ipProfileList.map(function(ip, j) {
+ let ipl = ip['ip-profile-params'];
+ return (
+ <div className="inputControls" key={j}>
+ <div className="inputControls-title" >
+ {ip.name}
+ </div>
+ <div className="inputControls-radioGroup">
+ <label className="inputControls-radio">
+ <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv4'} value='ipv4' />
+ ipv4
+ </label>
+ <label className="inputControls-radio">
+ <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'ipv6'} value='ipv6' />
+ ipv6
+ </label>
+ <label className="inputControls-radio">
+ <input type="radio" name={'ip-profile-' + j } onChange={props.ipProfileFn.updateVersion(j)} checked={ipl['ip-version'] == 'unknown'} value='unknown' />
+ unknown
+ </label>
+ </div>
+ <TextInput
+ label="subnet address"
+ onChange={props.ipProfileFn.updateProfile(j, 'subnet-address')}
+ value={ipl['subnet-address']}
+ />
+ <TextInput
+ label="gateway address"
+ onChange={props.ipProfileFn.updateProfile(j, 'gateway-address')}
+ value={ipl['gateway-address']}
+ />
+ <TextInput
+ label="security group"
+ onChange={props.ipProfileFn.updateProfile(j, 'security-group')}
+ value={ipl['security-group']}
+ />
+ <label>
+ <div style={{display:'flex'}}>
+ DNS SERVERS <span onClick={props.dnsFn.addDNS(j)} className="addInput"><img src={imgAdd} />Add</span>
+ </div>
+ {
+ ipl['dns-server'] && ipl['dns-server'].map(function(dns, k) {
+ return (
+ <div key={k} style={{display:'flex'}}>
+ <TextInput
+ onChange={props.ipProfileFn.updateProfile(j,k)}
+ value={ipl['dns-server'][k]}
+ />
+ <span onClick={props.dnsFn.removeDNS(j,k)} className="removeInput">
+ <img src={imgRemove} />Remove</span>
+ </div>
+ )
+ })
+ }
+ </label>
+ <div className="inputControls-radioGroup">
+ <label className="inputControls-radio">
+ DHCP ENABLED
+ <input type="radio"
+ name={'ip-profile-dhcp' + j }
+ onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
+ checked={ipl.hasOwnProperty('dhcp-params') && ipl['dhcp-params'].enabled}
+ value={true} />
+ YES
+ </label>
+ <label className="inputControls-radio">
+ <input type="radio"
+ name={'ip-profile-dhcp' + j }
+ onChange={props.ipProfileFn.updateDHCP(j, 'enabled')}
+ checked={!ipl.hasOwnProperty('dhcp-params') || !ipl['dhcp-params'].enabled}
+ value={false} />
+ NO
+ </label>
+ </div>
+ {
+ (ipl['dhcp-params'] && ipl['dhcp-params'].enabled) ? dhcpHTML(props, ipl, j) : null
+ }
+ </div>
+ )
+ })
+ }
+ </div>);
+ function dhcpHTML(props, ipl, j){
+ return (<div>
+ <TextInput
+ label="DCHP Start Address"
+ onChange={props.ipProfileFn.updateDHCP(j, 'start-address')}
+ value={ipl['dhcp-params'] && ipl['dhcp-params']['start-address']}
+ />
+ <TextInput
+ label="DCHP Count"
+ onChange={props.ipProfileFn.updateDHCP(j, 'count')}
+ value={ipl['dhcp-params'] && ipl['dhcp-params']['count']}
+ />
+ </div>
+ );
+ }
+ }
+ sshKeysHTML = (props) => {
+ let sshKeysList = props.sshKeysList;
+ let sshKeysRef = props.sshKeysRef;
+ if(sshKeysList && sshKeysList.length > 0) {
+ return (
+ <div className="configure-nsd_section">
+ <h3 className="launchpadCard_title">SSH Authorized Keys</h3>
+
+ {
+ sshKeysRef.map(function(ref, i) {
+ return (
+ <div key={i} className="inputControls inputControls-sshkeys">
+ <label>
+ <div>
+ <SelectOption
+ label="Key Pair"
+ options={sshKeysList && sshKeysList.map(function(k) {
+ return {
+ label: k.name,
+ value: k
+ }
+ })}
+ ref="keyPairSelection"
+ initial={false}
+ defaultValue={sshKeysList[0].name}
+ onChange={self.props.updateSshKeyRef(i)}>
+ </SelectOption>
+ </div>
+ </label>
+ <label>
+ <span onClick={self.props.updateSshKeyRef(i, true)} className="removeInput">
+ <img src={imgRemove} />
+ Remove
+ </span>
+ </label>
+ </div>
+ )
+ })
+ }
+ <div className="inputControls inputControls-sshkeys ">
+ <label style={{display: 'flex', 'flexDirection': 'row'}}>
+ SSH KEY PAIR
+ <span onClick={self.props.updateSshKeyRef().bind(null, {target:{value: JSON.stringify(sshKeysList[0])}})} className="addInput">
+ <img src={imgAdd} />
+ ADD
+ </span>
+ </label>
+ </div>
+ </div>
+ );
+ }
+ }
+ usersHTML = (props) => {
+ let usersFn = props.usersFn;
+ let usersList = props.usersList && props.usersList.map(function(u, i) {
+ return (
+ <div className="input_group input_group-users" key={i}>
+ <div className="inputControls">
+ <div style={{fontWeight: 'bold', display: 'flex'}}>USER <span onClick={usersFn.remove(i)} className="removeInput"><img src={imgRemove} />Remove</span></div>
+ <TextInput onChange={usersFn.update(i, 'name')} label="USERNAME" value={i.name} />
+ <TextInput onChange={usersFn.update(i, 'gecos')} label="REAL NAME" value={i.gecos} />
+ <TextInput onChange={usersFn.update(i, 'passwd')} type="password" label="PASSWORD" value={i.passwd} />
+ </div>
+ </div>
+ )
+ });
+ return (
+ <div className="configure-nsd_section">
+ <h3 className="launchpadCard_title">USERS</h3>
+ {usersList}
+ <div className="inputControls inputControls-sshkeys ">
+ <span onClick={usersFn.add} className="addInput">
+ <img src={imgAdd} onClick={usersFn.add} />
+ ADD USER
+ </span>
+ </div>
+ </div>
+ )
+ }
+
+ render() {
+ const props = this.props;
+ let html;
+ let self = this;
+
+ html = (
+ <div className="instantiateInputParams">
+ {
+ //NS NAMEA AND CLOUD
+ this.nsConfigHTML(props)
+ }
+ {
+ //VNF VIM ACCOUNTS
+ this.vnfCloudAccountsHTML(props)
+ }
+ {
+ //INPUT PARAMETERS
+ this.inputParametersHTML(props)
+ }
+ {
+ //NS PLACEMENTGROUPS
+ this.nsPlacementGroupsHTML(props)
+ }
+ {
+ //VNF PLACEMENTGROUPS
+ this.vnfPlacementGroupsHTML(props)
+ }
+ {
+ //VLD CONFIGURATION
+ this.vldsHTML(props)
+ }
+ {
+ //IP PROFILE CONFIGURATION
+ this.ipProfilesHTML(props)
+ }
+ {
+ //SSH KEY ASSIGNMENTS
+ this.sshKeysHTML(props)
+ }
+ {
+ //USER MANAGEMENT
+ this.usersHTML(props)
+ }
+ </div>
+ )
+ return html;
+ }
+}
+function showInput(e){
+ let target = e.target;
+ if(target.parentElement.classList.contains("addInput")) {
+ target = target.parentElement;
+ }
+ target.style.display = 'none';
+ target.parentElement.nextElementSibling.style.display = 'flex';
+ // e.target.parentElement.nextElementSibling.children[1].style.display = 'initial';
+}
+function hideInput(e){
+ let target = e.target;
+ if(target.parentElement.classList.contains("removeInput")) {
+ target = target.parentElement;
+ }
+ target.parentElement.style.display = 'none';
+ target.parentElement.previousElementSibling.children[1].style.display = 'inline';
+ target.previousSibling.value = '';
+}
+function addDNS(){}
+function removeDNS(){}
+function constructCloudAccountOptions(cloudAccounts){
+ let CloudAccountOptions = cloudAccounts && cloudAccounts.map(function(ca, index) {
+ return {
+ label: ca.name,
+ value: ca
+ }
+ });
+ return CloudAccountOptions;
+}
+function dataCentersHTML(state, onChange) {
+ //Build DataCenter options
+ //Relook at this, why is it an object?
+ let dataCenters = state.dataCenters || [];
+ let DataCenterOptions = {};
+ if(dataCenters){
+ for (let d in dataCenters) {
+ DataCenterOptions[d] = dataCenters[d].map(function(dc, index) {
+ return {
+ label: dc.name,
+ value: dc.uuid
+ }
+ });
+ }
+ }
+ if (dataCenters.length > 0) {
+ return (
+ <label>Select Data Center
+ <SelectOption options={DataCenterOptions} onChange={onChange} />
+ </label>
+ )
+ }
+}
+function isOpenMano(account) {
+ if (account) {
+ let a = account;
+ if (a.constructor.name == 'String') {
+ a = JSON.parse(a);
+ }
+ if(a.hasOwnProperty('account')) {
+ a = a.account;
+ }
+ return a['account-type'] == 'openmano';
+ } else {
+ return false;
+ }
+}
+function updateNewSshKeyRefSelection(e) {
+ this.setState({
+ newRefSelection: e.target.value
+ })
+}
+function resetRef() {
+ this.setState({
+ newRefSelection: null
+ })
+}
+InstantiateInputParams.defaultProps = {
+ data: [],
+ sshKeysList: [],
+ sshKeysRef: [],
+ users: {}
+}