1<template> 2 <div class="IVSH_REGIONS" v-if="defaultVal && defaultVal.length>0"> 3 <div class="IVSH_REGION" v-for="(IVSHMEM_VMO, index) in defaultVal"> 4 <div class="IVSH_REGION_CONTENT"> 5 <b style="margin-bottom: 2rem">InterVM shared memory region</b> 6 7 <b-row class="align-items-center my-2 mt-4"> 8 <b-col md="2"> 9 <label> 10 <n-popover trigger="hover" placement="top-start"> 11 <template #trigger> 12 <IconInfo/> 13 </template> 14 <span v-html="this.IVSHMEMRegionType.properties.NAME.description"></span> 15 </n-popover>Region name: 16 </label> 17 </b-col> 18 <b-col md="4"> 19 <b-form-input :state="validateIvshrgName(IVSHMEM_VMO.NAME)" v-model="IVSHMEM_VMO.NAME" placeholder="Must be 1-27 characters and only letters, digits and '_'."/> 20 <b-form-invalid-feedback> 21 Name must be between 1-27 characters and contain only letters, digits and "_". 22 </b-form-invalid-feedback> 23 </b-col> 24 </b-row> 25 26 <b-row class="align-items-center my-2"> 27 <b-col md="2"> 28 <label> 29 <n-popover trigger="hover" placement="top-start"> 30 <template #trigger> 31 <IconInfo/> 32 </template> 33 <span v-html="this.IVSHMEMRegionType.properties.PROVIDED_BY.description"></span> 34 </n-popover>Emulated by: 35 </label> 36 </b-col> 37 <b-col md="4"> 38 <b-form-select v-model="IVSHMEM_VMO.PROVIDED_BY" :options="providerType"></b-form-select> 39 </b-col> 40 </b-row> 41 42 <b-row class="align-items-center my-2"> 43 <b-col md="2"> 44 <label> 45 <n-popover trigger="hover" placement="top-start"> 46 <template #trigger> 47 <IconInfo/> 48 </template> 49 <span v-html="this.IVSHMEMRegionType.properties.IVSHMEM_SIZE.description"></span> 50 </n-popover>Size (MB): 51 </label> 52 </b-col> 53 <b-col md="4"> 54 <b-form-select v-model="IVSHMEM_VMO.IVSHMEM_SIZE" :options="IVSHMEMSize"></b-form-select> 55 </b-col> 56 </b-row> 57 58 <b-row class="align-items-center my-2"> 59 <b-col md="2"> 60 <label> 61 <n-popover trigger="hover" placement="top-start"> 62 <template #trigger> 63 <IconInfo/> 64 </template> 65 <span v-html="this.IVSHMEMRegionType.properties.IVSHMEM_REGION_ID.description"></span> 66 </n-popover>IVSHMEM Region ID: 67 </label> 68 </b-col> 69 <b-col md="4"> 70 <b-form-input v-model="IVSHMEM_VMO.IVSHMEM_REGION_ID"/> 71 </b-col> 72 </b-row> 73 74 <div class="m-3 mt-4 d-flex flex-column gap-2"> 75 <b>Shared VMs</b> 76 <p>Select all VMs that will use this shared memory region</p> 77 <b-row> 78 <b-col sm="2" offset-sm="6"> 79 <n-popover trigger="hover" placement="top-start"> 80 <template #trigger> 81 <IconInfo/> 82 </template> 83 <span v-html="this.IVSHMEM_VM.properties.VBDF.description"></span> 84 </n-popover>Virtual BDF: 85 </b-col> 86 </b-row> 87 <b-row class="justify-content-between align-items-center" 88 v-for="(IVSHMEM_VM,index) in IVSHMEM_VMO.IVSHMEM_VMS.IVSHMEM_VM"> 89 <b-col sm="2"> 90 <label> 91 <n-popover trigger="hover" placement="top-start"> 92 <template #trigger> 93 <IconInfo/> 94 </template> 95 <span v-html="this.IVSHMEM_VM.properties.VM_NAME.description"></span> 96 </n-popover>VM name: 97 </label> 98 </b-col> 99 <b-col sm="3"> 100 <b-form-select :state="validation(IVSHMEM_VM.VM_NAME)" v-model="IVSHMEM_VM.VM_NAME" :options="vmNames"></b-form-select> 101 <b-form-invalid-feedback> 102 must have value 103 </b-form-invalid-feedback> 104 </b-col> 105 <b-col sm="3"> 106 <b-form-input :state="validateVBDF(IVSHMEM_VM.VBDF)" v-model="IVSHMEM_VM.VBDF" placeholder="00:[device].[function], e.g. 00:0c.0. All fields are in hexadecimal."/> 107 <b-form-invalid-feedback> 108 {{ this.VBDFType["err:pattern"] }} 109 </b-form-invalid-feedback> 110 </b-col> 111 <b-col sm="3"> 112 <div class="ToolSet"> 113 <div @click="removeSharedVM(IVSHMEM_VMO.IVSHMEM_VMS.IVSHMEM_VM,index)"> 114 <Icon size="18px"> 115 <Minus/> 116 </Icon> 117 </div> 118 <div @click="addSharedVM(IVSHMEM_VMO.IVSHMEM_VMS.IVSHMEM_VM,index)"> 119 <Icon size="18px"> 120 <Plus/> 121 </Icon> 122 </div> 123 </div> 124 </b-col> 125 </b-row> 126 127 </div> 128 </div> 129 <div class="ToolSet"> 130 <div @click="removeIVSHMEM_VMO(index)"> 131 <Icon size="18px"> 132 <Minus/> 133 </Icon> 134 </div> 135 <div @click="addIVSHMEM_VMO(index)"> 136 <Icon size="18px"> 137 <Plus/> 138 </Icon> 139 </div> 140 </div> 141 142 </div> 143 144 </div> 145 <div v-else> 146 <div class="ToolSet"> 147 <div @click="addIVSHMEM_VMO"> 148 <Icon size="18px"> 149 <Plus/> 150 </Icon> 151 </div> 152 </div> 153 </div> 154</template> 155 156<script> 157import _ from 'lodash'; 158import {Icon} from "@vicons/utils"; 159import {Plus, Minus} from '@vicons/fa' 160import {fieldProps, vueUtils} from '@lljj/vue3-form-naive'; 161import IconInfo from '@lljj/vjsf-utils/icons/IconInfo.vue'; 162 163export default { 164 name: 'IVSHMEM_REGION', 165 components: {Icon, Plus, Minus, IconInfo}, 166 props: { 167 ...fieldProps, 168 // Todo: use ui:fieldProps to pass getScenarioData function 169 fieldProps: { 170 type: null, 171 default: null 172 } 173 }, 174 computed: { 175 vmNames() { 176 let currentScenarioData = window.getCurrentScenarioData() 177 let vmNames = [] 178 for (let i = 0; i < currentScenarioData.vm.length; i++) { 179 vmNames.push(currentScenarioData.vm[i].name) 180 } 181 return vmNames 182 } 183 }, 184 data() { 185 return { 186 providerType: this.rootSchema.definitions['ProviderType']['enum'], 187 IVSHMEMSize: this.rootSchema.definitions['IVSHMEMSize']['enum'], 188 IVSHMEMRegionType: this.rootSchema.definitions['IVSHMEMRegionType'], 189 IVSHMEM_VM: this.rootSchema.definitions['IVSHMEMVM'], 190 VBDFType: this.rootSchema.definitions['VBDFType'], 191 defaultVal: vueUtils.getPathVal(this.rootFormData, this.curNodePath) 192 }; 193 }, 194 watch: { 195 rootFormData: { 196 handler(newValue, oldValue) { 197 this.defaultVal = vueUtils.getPathVal(newValue, this.curNodePath) 198 }, 199 deep: true 200 }, 201 defaultVal: { 202 handler(newValue, oldValue) { 203 // Note: `newValue` will be equal to `oldValue` here 204 // on nested mutations as long as the object itself 205 // hasn't been replaced. 206 vueUtils.setPathVal(this.rootFormData, this.curNodePath, newValue); 207 }, 208 deep: true 209 } 210 }, 211 methods: { 212 validateIvshrgName(value) { 213 var regexp = new RegExp(this.IVSHMEMRegionType.properties.NAME.pattern); 214 return (value != null) && regexp.test(value); 215 }, 216 validateVBDF(value) { 217 var regexp = new RegExp(this.VBDFType.pattern); 218 return (value != null) && regexp.test(value); 219 }, 220 validation(value) { 221 return (value != null) && (value.length !== 0); 222 }, 223 addSharedVM(vms, index) { 224 // add new item after current item 225 vms.splice(index + 1, 0, { 226 "VM_NAME": "", 227 "VBDF": "" 228 }) 229 }, 230 removeSharedVM(vms, index) { 231 if (vms.length <= 2) { 232 return 233 } 234 vms.splice(index, 1) 235 }, 236 removeIVSHMEM_VMO(index) { 237 this.defaultVal.splice(index, 1); 238 }, 239 addIVSHMEM_VMO(index) { 240 if (!_.isArray(this.defaultVal)) { 241 this.defaultVal = [] 242 } 243 this.defaultVal.splice(index + 1, 0, { 244 "NAME": "", 245 "PROVIDED_BY": "Hypervisor", 246 "IVSHMEM_SIZE": "2", 247 "IVSHMEM_VMS": { 248 "IVSHMEM_VM": [ 249 { 250 "VM_NAME": "", 251 "VBDF": "" 252 }, 253 { 254 "VM_NAME": "", 255 "VBDF": "" 256 } 257 ] 258 } 259 }) 260 } 261 } 262}; 263</script> 264 265<!--suppress CssUnusedSymbol --> 266<style scoped> 267label:before { 268 content: '*'; 269 color: red; 270 margin-right: 3px; 271} 272 273.form-control { 274 line-height: 2; 275} 276 277.IVSH_REGIONS { 278 display: flex; 279 flex-direction: column; 280 width: 100%; 281 gap: 2rem; 282} 283 284.IVSH_REGION { 285 display: flex; 286 align-items: start; 287 gap: 1rem; 288 width: 100%; 289} 290 291.IVSH_REGION_CONTENT { 292 border: 1px solid gray; 293 border-radius: 5px; 294 padding: 25px; 295 width: 100%; 296} 297 298.ToolSet { 299 display: flex; 300 justify-content: space-around; 301 gap: 0.5rem; 302 max-width: 5rem; 303 width: 100%; 304} 305 306.ToolSet div { 307 cursor: pointer; 308 border: 1px solid gray; 309 border-radius: 3px; 310 background: #f9f9f9; 311 padding: 5px 5px 3px; 312} 313</style> 314