mirror of https://github.com/apache/cloudstack.git
rebase
This commit is contained in:
parent
5893ba5a8c
commit
8b0cd2ca54
|
|
@ -996,6 +996,7 @@ public class ApiConstants {
|
|||
public static final String VPC_OFF_NAME = "vpcofferingname";
|
||||
public static final String VPC_OFFERING_CONSERVE_MODE = "vpcofferingconservemode";
|
||||
public static final String NETWORK = "network";
|
||||
public static final String VPC_ACCESS = "vpcaccess";
|
||||
public static final String VPC_ID = "vpcid";
|
||||
public static final String VPC_NAME = "vpcname";
|
||||
public static final String VPC_GATEWAY_ID = "vpcgatewayid";
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ public class ListNetworksCmd extends BaseListRetrieveOnlyResourceCountCmd implem
|
|||
private void updateNetworkResponse(List<NetworkResponse> response) {
|
||||
for (NetworkResponse networkResponse : response) {
|
||||
ResourceIcon resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Network, networkResponse.getId());
|
||||
if (resourceIcon == null && networkResponse.getVpcId() != null) {
|
||||
if (resourceIcon == null && networkResponse.getVpcId() != null && networkResponse.getVpcAccess()) {
|
||||
resourceIcon = resourceIconManager.getByResourceTypeAndUuid(ResourceTag.ResourceObjectType.Vpc, networkResponse.getVpcId());
|
||||
}
|
||||
if (resourceIcon == null) {
|
||||
|
|
|
|||
|
|
@ -143,6 +143,10 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co
|
|||
@Param(description = "Purpose of the IP address. In Acton this value is not null for IPs with isSystem=true, and can have either StaticNat or LB value")
|
||||
private String purpose;
|
||||
|
||||
@SerializedName(ApiConstants.VPC_ACCESS)
|
||||
@Param(description = "Whether the calling account has access to this network's VPC", since = "4.20")
|
||||
private boolean vpcAccess;
|
||||
|
||||
@SerializedName(ApiConstants.VPC_ID)
|
||||
@Param(description = "VPC ID the IP belongs to")
|
||||
private String vpcId;
|
||||
|
|
@ -301,6 +305,10 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co
|
|||
this.purpose = purpose;
|
||||
}
|
||||
|
||||
public void setVpcAccess(boolean vpcAccess) {
|
||||
this.vpcAccess = vpcAccess;
|
||||
}
|
||||
|
||||
public void setVpcId(String vpcId) {
|
||||
this.vpcId = vpcId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,6 +203,10 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
|
|||
@Param(description = "True if Network supports specifying IP ranges, false otherwise")
|
||||
private Boolean specifyIpRanges;
|
||||
|
||||
@SerializedName(ApiConstants.VPC_ACCESS)
|
||||
@Param(description = "Whether the calling account has access to this network's VPC", since = "4.20")
|
||||
private boolean vpcAccess;
|
||||
|
||||
@SerializedName(ApiConstants.VPC_ID)
|
||||
@Param(description = "VPC the Network belongs to")
|
||||
private String vpcId;
|
||||
|
|
@ -523,6 +527,14 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
|
|||
this.specifyIpRanges = specifyIpRanges;
|
||||
}
|
||||
|
||||
public void setVpcAccess(boolean vpcAccess) {
|
||||
this.vpcAccess = vpcAccess;
|
||||
}
|
||||
|
||||
public boolean getVpcAccess() {
|
||||
return vpcAccess;
|
||||
}
|
||||
|
||||
public void setVpcId(String vpcId) {
|
||||
this.vpcId = vpcId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1167,7 +1167,7 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
|
|||
}
|
||||
|
||||
|
||||
setVpcIdInResponse(ipAddr.getVpcId(), ipResponse::setVpcId, ipResponse::setVpcName);
|
||||
setVpcIdInResponse(ipAddr.getVpcId(), ipResponse::setVpcId, ipResponse::setVpcName, ipResponse::setVpcAccess);
|
||||
|
||||
|
||||
// Network id the ip is associated with (if associated networkId is
|
||||
|
|
@ -1242,20 +1242,24 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
|
|||
return ipResponse;
|
||||
}
|
||||
|
||||
|
||||
private void setVpcIdInResponse(Long vpcId, Consumer<String> vpcUuidSetter, Consumer<String> vpcNameSetter) {
|
||||
if (vpcId != null) {
|
||||
Vpc vpc = ApiDBUtils.findVpcById(vpcId);
|
||||
if (vpc != null) {
|
||||
try {
|
||||
_accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, false, vpc);
|
||||
vpcUuidSetter.accept(vpc.getUuid());
|
||||
} catch (PermissionDeniedException e) {
|
||||
logger.debug("Not setting the vpcId to the response because the caller does not have access to the VPC");
|
||||
}
|
||||
vpcNameSetter.accept(vpc.getName());
|
||||
}
|
||||
private void setVpcIdInResponse(Long vpcId, Consumer<String> vpcUuidSetter, Consumer<String> vpcNameSetter, Consumer<Boolean> vpcAccessSetter) {
|
||||
if (vpcId == null) {
|
||||
return;
|
||||
}
|
||||
Vpc vpc = ApiDBUtils.findVpcById(vpcId);
|
||||
if (vpc == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
_accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, false, vpc);
|
||||
vpcAccessSetter.accept(true);
|
||||
} catch (PermissionDeniedException e) {
|
||||
vpcAccessSetter.accept(false);
|
||||
logger.debug("Setting [%s] as false because the caller does not have access to the VPC [%s].", ApiConstants.VPC_ACCESS, vpc);
|
||||
}
|
||||
vpcNameSetter.accept(vpc.getName());
|
||||
vpcUuidSetter.accept(vpc.getUuid());
|
||||
}
|
||||
|
||||
private void showVmInfoForSharedNetworks(boolean forVirtualNetworks, IpAddress ipAddr, IPAddressResponse ipResponse) {
|
||||
|
|
@ -2799,7 +2803,7 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
|
|||
|
||||
response.setSpecifyIpRanges(network.getSpecifyIpRanges());
|
||||
|
||||
setVpcIdInResponse(network.getVpcId(), response::setVpcId, response::setVpcName);
|
||||
setVpcIdInResponse(network.getVpcId(), response::setVpcId, response::setVpcName, response::setVpcAccess);
|
||||
|
||||
setResponseAssociatedNetworkInformation(response, network.getId());
|
||||
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ public class ApiResponseHelperTest {
|
|||
public void setResponseIpAddressTestIpv4() {
|
||||
NicSecondaryIp result = Mockito.mock(NicSecondaryIp.class);
|
||||
NicSecondaryIpResponse response = new NicSecondaryIpResponse();
|
||||
setResult(result, "ipv4", "ipv6");
|
||||
setResult(result, "ipv4", "");
|
||||
|
||||
ApiResponseHelper.setResponseIpAddress(result, response);
|
||||
|
||||
|
|
|
|||
|
|
@ -504,6 +504,127 @@
|
|||
<gold-outlined />
|
||||
<router-link :to="{ path: '/autoscalevmgroup/' + resource.autoscalevmgroupid }">{{ resource.autoscalevmgroupname || resource.autoscalevmgroupid }}</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.resourcetype && resource.resourceid && routeFromResourceType">
|
||||
<div class="resource-detail-item__label">{{ $t('label.resource') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<resource-label :resourceType="resource.resourcetype" :resourceId="resource.resourceid" :resourceName="resource.resourcename" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.virtualmachineid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.vmname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<desktop-outlined />
|
||||
<router-link :to="{ path: createPathBasedOnVmType(resource.vmtype, resource.virtualmachineid) }">{{ resource.vmname || resource.vm || resource.virtualmachinename || resource.virtualmachineid }} </router-link>
|
||||
<status class="status status--end" :text="resource.vmstate" v-if="resource.vmstate"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.volumeid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.volume') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<hdd-outlined />
|
||||
<router-link v-if="validLinks.volume" :to="{ path: '/volume/' + resource.volumeid }">{{ resource.volumename || resource.volume || resource.volumeid }} </router-link>
|
||||
<span v-else>{{ resource.volumename || resource.volume || resource.volumeid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.associatednetworkid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.associatednetwork') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<wifi-outlined />
|
||||
<router-link :to="{ path: '/guestnetwork/' + resource.associatednetworkid }">{{ resource.associatednetworkname || resource.associatednetwork || resource.associatednetworkid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.sourceipaddressnetworkid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.network') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<wifi-outlined />
|
||||
<router-link :to="{ path: '/guestnetwork/' + resource.sourceipaddressnetworkid }">{{ resource.sourceipaddressnetworkname || resource.sourceipaddressnetworkid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.guestnetworkid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.guestnetwork') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<gateway-outlined />
|
||||
<router-link :to="{ path: '/guestnetwork/' + resource.guestnetworkid }">{{ resource.guestnetworkname || resource.guestnetworkid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.publicip">
|
||||
<div class="resource-detail-item__label">{{ $t('label.public.ip') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<gateway-outlined />
|
||||
<router-link v-if="resource.publicipid" :to="{ path: '/publicip/' + resource.publicipid }">{{ resource.publicip }} </router-link>
|
||||
<copy-label v-if="resource.publicipid" :copyValue="resource.publicip" :showIcon=true />
|
||||
<copy-label v-else :label="resource.publicip" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.vpcid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.vpcname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<span v-if="images.vpc">
|
||||
<resource-icon :image="getImage(images.vpc)" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<deployment-unit-outlined v-else />
|
||||
<router-link v-if="resource.vpcaccess" :to="{ path: '/vpc/' + resource.vpcid }">{{ resource.vpcname || resource.vpcid }}</router-link>
|
||||
<span v-else>{{ resource.vpcname || resource.vpcid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resource-detail-item" v-if="resource.aclid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.aclid') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<span v-if="images.acl">
|
||||
<resource-icon :image="getImage(images.acl)" size="1x" style="margin-right: 5px"/>
|
||||
</span>
|
||||
<deployment-unit-outlined v-else />
|
||||
<router-link :to="{ path: '/acllist/' + resource.aclid }">{{ resource.aclname || resource.aclid }}</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="resource-detail-item" v-if="resource.affinitygroup && resource.affinitygroup.length > 0">
|
||||
<div class="resource-detail-item__label">{{ $t('label.affinitygroup') }}</div>
|
||||
<SwapOutlined />
|
||||
<span
|
||||
v-for="(group, index) in resource.affinitygroup"
|
||||
:key="group.id"
|
||||
>
|
||||
<router-link :to="{ path: '/affinitygroup/' + group.id }">{{ group.name }}</router-link>
|
||||
<span v-if="index + 1 < resource.affinitygroup.length">, </span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.templateid">
|
||||
<div class="resource-detail-item__label">{{ resource.templateformat === 'ISO'? $t('label.iso') : $t('label.templatename') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<resource-icon v-if="resource.icon" :image="getImage(resource.icon.base64image)" size="1x" style="margin-right: 5px"/>
|
||||
<SaveOutlined v-else />
|
||||
<router-link :to="{ path: (resource.templateformat === 'ISO' ? '/iso/' : '/template/') + resource.templateid }">{{ resource.templatedisplaytext || resource.templatename || resource.templateid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.isoid">
|
||||
<div class="resource-detail-item__label">{{ $t('label.isoname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<resource-icon v-if="resource.icon" :image="getImage(resource.icon.base64image)" size="1x" style="margin-right: 5px"/>
|
||||
<UsbOutlined v-else />
|
||||
<router-link :to="{ path: '/iso/' + resource.isoid }">{{ resource.isodisplaytext || resource.isoname || resource.isoid }} </router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.serviceofferingname && resource.serviceofferingid">
|
||||
<div class="resource-detail-item__label" v-if="$route.meta.name === 'router' || $route.meta.name === 'systemvm'">{{ $t('label.system.offering') }}</div>
|
||||
<div class="resource-detail-item__label" v-else >{{ $t('label.serviceofferingname') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<cloud-outlined />
|
||||
<router-link v-if="!isStatic && ($route.meta.name === 'router' || $route.meta.name === 'systemvm')" :to="{ path: '/systemoffering/' + resource.serviceofferingid}">{{ resource.serviceofferingname || resource.serviceofferingid }} </router-link>
|
||||
<router-link v-else-if="$router.resolve('/computeoffering/' + resource.serviceofferingid).matched[0].redirect !== '/exception/404'" :to="{ path: '/computeoffering/' + resource.serviceofferingid }">{{ resource.serviceofferingname || resource.serviceofferingid }} </router-link>
|
||||
<span v-else>{{ resource.serviceofferingname || resource.serviceofferingid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.rootdiskofferingid && resource.rootdiskofferingdisplaytext || resource.datadiskofferingid && resource.datadiskofferingdisplaytext">
|
||||
<div class="resource-detail-item__label">{{ $t('label.diskoffering') }}</div>
|
||||
<div class="resource-detail-item__details">
|
||||
<hdd-outlined />
|
||||
<div v-if="resource.rootdiskofferingid">
|
||||
<router-link v-if="!isStatic && $router.resolve('/diskoffering/' + resource.rootdiskofferingid).matched[0].redirect !== '/exception/404'" :to="{ path: '/diskoffering/' + resource.rootdiskofferingid }">{{ resource.rootdiskofferingdisplaytext }}</router-link>
|
||||
<span v-else>{{ resource.rootdiskofferingdisplaytext }}</span>
|
||||
</div>
|
||||
<div class="resource-detail-item" v-if="resource.keypairs && resource.keypairs.length > 0">
|
||||
<div class="resource-detail-item__label">{{ $t('label.keypairs') }}</div>
|
||||
|
|
|
|||
|
|
@ -582,7 +582,7 @@
|
|||
<router-link :to="{ path: '/guestnetwork/' + record.associatednetworkid }">{{ text }}</router-link>
|
||||
</template>
|
||||
<template v-if="column.key === 'vpcname'">
|
||||
<a v-if="record.vpcid">
|
||||
<a v-if="record.vpcid && record.vpcaccess">
|
||||
<router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text || record.vpcid }}</router-link>
|
||||
</a>
|
||||
<span v-else>{{ text }}</span>
|
||||
|
|
|
|||
|
|
@ -47,12 +47,12 @@
|
|||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option key="all" value="">
|
||||
{{ $t('label.view.all') }}
|
||||
</a-select-option>
|
||||
<a-select-option v-for="network in networksList" :key="network.id" :value="network.id" :label="network.name">
|
||||
<a-select-option v-for="network in networksList" :key="network.id" :value="network.id">
|
||||
{{ network.name }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
|
|
@ -65,57 +65,35 @@
|
|||
:rowKey="item => item.id"
|
||||
:rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
|
||||
:pagination="false" >
|
||||
<template #bodyCell="{ column, text, record }">
|
||||
<template v-if="column.key === 'ipaddress'">
|
||||
<router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/publicip/' + record.id }" >{{ text }} </router-link>
|
||||
<div v-else>{{ text }}</div>
|
||||
<template v-if="record.issourcenat === true">
|
||||
<a-tag>{{ $t('label.sourcenat') }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="record.isstaticnat === true">
|
||||
<a-tag>{{ $t('label.staticnat') }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="record.hasrules === false">
|
||||
<tooltip-button
|
||||
v-if="record.forvirtualnetwork === true"
|
||||
:tooltip="$t('label.action.set.as.source.nat.ip')"
|
||||
type="primary"
|
||||
:danger="false"
|
||||
icon="aim-outlined"
|
||||
:disabled="!('updateNetwork' in $store.getters.apis)"
|
||||
@onClick="showChangeSourceNat(record)"></tooltip-button>
|
||||
</template>
|
||||
<template v-else><!-- -if="record.hasrules === true" -->
|
||||
<Tooltip placement="topLeft" :title="$t('message.sourcenatip.change.inhibited')" >
|
||||
<a-tag>{{ $t('label.hasrules') }}</a-tag>
|
||||
</Tooltip>
|
||||
</template>
|
||||
</template>
|
||||
<template #ipaddress="{ text, record }">
|
||||
<router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/publicip/' + record.id }" >{{ text }} </router-link>
|
||||
<div v-else>{{ text }}</div>
|
||||
<a-tag v-if="record.issourcenat === true">source-nat</a-tag>
|
||||
</template>
|
||||
|
||||
<template v-if="column.key === 'state'">
|
||||
<status :text="record.state" displayText />
|
||||
</template>
|
||||
<template #state="{ record }">
|
||||
<status :text="record.state" displayText />
|
||||
</template>
|
||||
|
||||
<template v-if="column.key === 'virtualmachineid'">
|
||||
<desktop-outlined v-if="record.virtualmachineid" />
|
||||
<router-link :to="{ path: getVmRouteUsingType(record) + record.virtualmachineid }" > {{ record.virtualmachinename || record.virtualmachineid }} </router-link>
|
||||
</template>
|
||||
<template #virtualmachineid="{ record }">
|
||||
<desktop-outlined v-if="record.virtualmachineid" />
|
||||
<router-link :to="{ path: '/vm/' + record.virtualmachineid }" > {{ record.virtualmachinename || record.virtualmachineid }} </router-link>
|
||||
</template>
|
||||
|
||||
<template v-if="column.key === 'associatednetworkname'">
|
||||
<router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/guestnetwork/' + record.associatednetworkid }" > {{ record.associatednetworkname || record.associatednetworkid }} </router-link>
|
||||
<div v-else>{{ record.networkname }}</div>
|
||||
</template>
|
||||
<template #associatednetworkname="{ record }">
|
||||
<router-link v-if="record.forvirtualnetwork === true" :to="{ path: '/guestnetwork/' + record.associatednetworkid }" > {{ record.associatednetworkname || record.associatednetworkid }} </router-link>
|
||||
<div v-else>{{ record.networkname }}</div>
|
||||
</template>
|
||||
|
||||
<template v-if="column.key === 'actions'">
|
||||
<tooltip-button
|
||||
v-if="record.issourcenat !== true && record.forvirtualnetwork === true"
|
||||
:tooltip="$t('label.action.release.ip')"
|
||||
type="primary"
|
||||
:danger="true"
|
||||
icon="delete-outlined"
|
||||
:disabled="!('disassociateIpAddress' in $store.getters.apis)"
|
||||
@onClick="releaseIpAddress(record)" />
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<tooltip-button
|
||||
v-if="record.issourcenat !== true && record.forvirtualnetwork === true"
|
||||
:tooltip="$t('label.action.release.ip')"
|
||||
type="primary"
|
||||
:danger="true"
|
||||
icon="delete-outlined"
|
||||
:disabled="!('disassociateIpAddress' in $store.getters.apis)"
|
||||
@onClick="releaseIpAddress(record)" />
|
||||
</template>
|
||||
</a-table>
|
||||
<a-divider/>
|
||||
|
|
@ -148,17 +126,19 @@
|
|||
<a-alert :message="$t('message.action.acquire.ip')" type="warning" />
|
||||
<a-form layout="vertical" style="margin-top: 10px">
|
||||
<a-form-item :label="$t('label.ipaddress')">
|
||||
<infinite-scroll-select
|
||||
<a-select
|
||||
v-focus="true"
|
||||
style="width: 100%;"
|
||||
v-model:value="acquireIp"
|
||||
api="listPublicIpAddresses"
|
||||
:apiParams="listApiParamsForAssociate"
|
||||
resourceType="publicipaddress"
|
||||
optionValueKey="ipaddress"
|
||||
:optionLabelFn="ip => ip.ipaddress + ' (' + ip.state + ')'"
|
||||
defaultIcon="environment-outlined"
|
||||
:autoSelectFirstOption="true"
|
||||
@change-option-value="(ip) => acquireIp = ip" />
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}" >
|
||||
<a-select-option
|
||||
v-for="ip in listPublicIpAddress"
|
||||
:key="ip.ipaddress">{{ ip.ipaddress }} ({{ ip.state }})</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="onCloseModal">{{ $t('label.cancel') }}</a-button>
|
||||
|
|
@ -167,24 +147,6 @@
|
|||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
<a-modal
|
||||
v-if="changeSourceNat"
|
||||
:title="$t('message.sourcenatip.change.warning')"
|
||||
:visible="changeSourceNat"
|
||||
:closable="true"
|
||||
:footer="null"
|
||||
@cancel="cancelChangeSourceNat"
|
||||
centered
|
||||
:disabled="!('updateNetwork' in $store.getters.apis)"
|
||||
width="450px">
|
||||
<template>
|
||||
<a-alert :message="$t('message.sourcenatip.change.warning')" type="warning" />
|
||||
</template>
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="cancelChangeSourceNat">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button ref="submit" type="primary" @click="setSourceNatIp(record)">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-modal>
|
||||
<bulk-action-view
|
||||
v-if="showConfirmationAction || showGroupActionModal"
|
||||
:showConfirmationAction="showConfirmationAction"
|
||||
|
|
@ -202,22 +164,19 @@
|
|||
@close-modal="closeModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAPI, postAPI } from '@/api'
|
||||
import { api } from '@/api'
|
||||
import Status from '@/components/widgets/Status'
|
||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||
import BulkActionView from '@/components/view/BulkActionView'
|
||||
import eventBus from '@/config/eventBus'
|
||||
import InfiniteScrollSelect from '@/components/widgets/InfiniteScrollSelect'
|
||||
|
||||
export default {
|
||||
name: 'IpAddressesTab',
|
||||
components: {
|
||||
Status,
|
||||
TooltipButton,
|
||||
BulkActionView,
|
||||
InfiniteScrollSelect
|
||||
BulkActionView
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
|
|
@ -245,7 +204,7 @@ export default {
|
|||
showGroupActionModal: false,
|
||||
selectedItems: [],
|
||||
selectedColumns: [],
|
||||
filterColumns: ['Actions'],
|
||||
filterColumns: ['Action'],
|
||||
showConfirmationAction: false,
|
||||
message: {
|
||||
title: this.$t('label.action.bulk.release.public.ip.address'),
|
||||
|
|
@ -253,39 +212,37 @@ export default {
|
|||
},
|
||||
columns: [
|
||||
{
|
||||
key: 'ipaddress',
|
||||
title: this.$t('label.ipaddress'),
|
||||
dataIndex: 'ipaddress'
|
||||
dataIndex: 'ipaddress',
|
||||
slots: { customRender: 'ipaddress' }
|
||||
},
|
||||
{
|
||||
key: 'state',
|
||||
title: this.$t('label.state'),
|
||||
dataIndex: 'state'
|
||||
dataIndex: 'state',
|
||||
slots: { customRender: 'state' }
|
||||
},
|
||||
{
|
||||
key: 'virtualmachineid',
|
||||
title: this.$t('label.vm'),
|
||||
dataIndex: 'virtualmachineid'
|
||||
dataIndex: 'virtualmachineid',
|
||||
slots: { customRender: 'virtualmachineid' }
|
||||
},
|
||||
{
|
||||
key: 'associatednetworkname',
|
||||
title: this.$t('label.network'),
|
||||
dataIndex: 'associatednetworkname'
|
||||
dataIndex: 'associatednetworkname',
|
||||
slots: { customRender: 'associatednetworkname' }
|
||||
},
|
||||
{
|
||||
key: 'actions',
|
||||
title: ''
|
||||
title: '',
|
||||
slots: { customRender: 'action' }
|
||||
}
|
||||
],
|
||||
showAcquireIp: false,
|
||||
acquireLoading: false,
|
||||
acquireIp: null,
|
||||
changeSourceNat: false,
|
||||
zoneExtNetProvider: ''
|
||||
listPublicIpAddress: []
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
await this.fetchZones()
|
||||
created () {
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
|
|
@ -300,26 +257,6 @@ export default {
|
|||
}
|
||||
},
|
||||
inject: ['parentFetchData'],
|
||||
computed: {
|
||||
listApiParams () {
|
||||
const params = {
|
||||
zoneid: this.resource.zoneid,
|
||||
domainid: this.resource.domainid,
|
||||
account: this.resource.account,
|
||||
forvirtualnetwork: true,
|
||||
allocatedonly: false
|
||||
}
|
||||
if (['nsx', 'netris'].includes(this.zoneExtNetProvider?.toLowerCase())) {
|
||||
params.forprovider = true
|
||||
}
|
||||
return params
|
||||
},
|
||||
listApiParamsForAssociate () {
|
||||
const params = this.listApiParams
|
||||
params.state = 'Free,Reserved'
|
||||
return params
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
const params = {
|
||||
|
|
@ -341,30 +278,24 @@ export default {
|
|||
} else {
|
||||
params.associatednetworkid = this.resource.id
|
||||
}
|
||||
if (['nsx', 'netris'].includes(this.zoneExtNetProvider?.toLowerCase())) {
|
||||
params.forprovider = true
|
||||
}
|
||||
this.fetchLoading = true
|
||||
getAPI('listPublicIpAddresses', params).then(json => {
|
||||
api('listPublicIpAddresses', params).then(json => {
|
||||
this.totalIps = json.listpublicipaddressesresponse.count || 0
|
||||
this.ips = json.listpublicipaddressesresponse.publicipaddress || []
|
||||
}).finally(() => {
|
||||
this.fetchLoading = false
|
||||
})
|
||||
},
|
||||
fetchZones () {
|
||||
fetchListPublicIpAddress () {
|
||||
return new Promise((resolve, reject) => {
|
||||
getAPI('listZones', {
|
||||
id: this.resource.zoneid
|
||||
}).then(json => {
|
||||
this.zoneExtNetProvider = json?.listzonesresponse?.zone?.[0]?.provider || null
|
||||
resolve(this.zoneExtNetProvider)
|
||||
}).catch(reject)
|
||||
})
|
||||
},
|
||||
fetchListPublicIpAddress (state) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getAPI('listPublicIpAddresses', this.listApiParams).then(json => {
|
||||
const params = {
|
||||
zoneid: this.resource.zoneid,
|
||||
domainid: this.resource.domainid,
|
||||
account: this.resource.account,
|
||||
forvirtualnetwork: true,
|
||||
allocatedonly: false
|
||||
}
|
||||
api('listPublicIpAddresses', params).then(json => {
|
||||
const listPublicIps = json.listpublicipaddressesresponse.publicipaddress || []
|
||||
resolve(listPublicIps)
|
||||
}).catch(reject)
|
||||
|
|
@ -381,50 +312,6 @@ export default {
|
|||
return selection.indexOf(item.id) !== -1
|
||||
}))
|
||||
},
|
||||
setSourceNatIp (ipaddress) {
|
||||
if (this.settingsourcenat) return
|
||||
if (this.$route.path.startsWith('/vpc')) {
|
||||
this.updateVpc(ipaddress)
|
||||
} else {
|
||||
this.updateNetwork(ipaddress)
|
||||
}
|
||||
},
|
||||
updateNetwork (ipaddress) {
|
||||
const params = {}
|
||||
params.sourcenatipaddress = this.sourceNatIp.ipaddress
|
||||
params.id = this.resource.id
|
||||
this.settingsourcenat = true
|
||||
postAPI('updateNetwork', params).then(response => {
|
||||
this.fetchData()
|
||||
}).catch(error => {
|
||||
this.$notification.error({
|
||||
message: `${this.$t('label.error')} ${error.response.status}`,
|
||||
description: error.response.data.updatenetworkresponse.errortext || error.response.data.errorresponse.errortext,
|
||||
duration: 0
|
||||
})
|
||||
}).finally(() => {
|
||||
this.settingsourcenat = false
|
||||
this.cancelChangeSourceNat()
|
||||
})
|
||||
},
|
||||
updateVpc (ipaddress) {
|
||||
const params = {}
|
||||
params.sourcenatipaddress = this.sourceNatIp.ipaddress
|
||||
params.id = this.resource.id
|
||||
this.settingsourcenat = true
|
||||
postAPI('updateVPC', params).then(response => {
|
||||
this.fetchData()
|
||||
}).catch(error => {
|
||||
this.$notification.error({
|
||||
message: `${this.$t('label.error')} ${error.response.status}`,
|
||||
description: error.response.data.updatevpcresponse.errortext || error.response.data.errorresponse.errortext,
|
||||
duration: 0
|
||||
})
|
||||
}).finally(() => {
|
||||
this.settingsourcenat = false
|
||||
this.cancelChangeSourceNat()
|
||||
})
|
||||
},
|
||||
resetSelection () {
|
||||
this.setSelection([])
|
||||
},
|
||||
|
|
@ -462,7 +349,7 @@ export default {
|
|||
params.ipaddress = this.acquireIp
|
||||
this.acquireLoading = true
|
||||
|
||||
postAPI('associateIpAddress', params).then(response => {
|
||||
api('associateIpAddress', params).then(response => {
|
||||
this.$pollJob({
|
||||
jobId: response.associateipaddressresponse.jobid,
|
||||
successMessage: `${this.$t('message.success.acquire.ip')} ${this.$t('label.for')} ${this.resource.name}`,
|
||||
|
|
@ -479,8 +366,8 @@ export default {
|
|||
this.onCloseModal()
|
||||
}).catch(error => {
|
||||
this.$notification.error({
|
||||
message: this.$t('message.request.failed'),
|
||||
description: (error.response && error.response.headers && error.response.headers['x-description']) || error.message,
|
||||
message: `${this.$t('label.error')} ${error.response.status}`,
|
||||
description: error.response.data.associateipaddressresponse.errortext || error.response.data.errorresponse.errortext,
|
||||
duration: 0
|
||||
})
|
||||
}).finally(() => {
|
||||
|
|
@ -498,9 +385,9 @@ export default {
|
|||
releaseIpAddresses (e) {
|
||||
this.showConfirmationAction = false
|
||||
this.selectedColumns.splice(0, 0, {
|
||||
key: 'status',
|
||||
dataIndex: 'status',
|
||||
title: this.$t('label.operation.status'),
|
||||
slots: { customRender: 'status' },
|
||||
filters: [
|
||||
{ text: 'In Progress', value: 'InProgress' },
|
||||
{ text: 'Success', value: 'success' },
|
||||
|
|
@ -516,7 +403,7 @@ export default {
|
|||
},
|
||||
releaseIpAddress (ip) {
|
||||
this.fetchLoading = true
|
||||
postAPI('disassociateIpAddress', {
|
||||
api('disassociateIpAddress', {
|
||||
id: ip.id
|
||||
}).then(response => {
|
||||
const jobId = response.disassociateipaddressresponse.jobid
|
||||
|
|
@ -552,29 +439,38 @@ export default {
|
|||
})
|
||||
})
|
||||
},
|
||||
getVmRouteUsingType (record) {
|
||||
switch (record.virtualmachinetype) {
|
||||
case 'DomainRouter' : return '/router/'
|
||||
case 'ConsoleProxy' :
|
||||
case 'SecondaryStorageVm': return '/systemvm/'
|
||||
default: return '/vm/'
|
||||
}
|
||||
},
|
||||
async onShowAcquireIp () {
|
||||
this.showAcquireIp = true
|
||||
this.acquireLoading = true
|
||||
this.listPublicIpAddress = []
|
||||
|
||||
try {
|
||||
const listPublicIpAddress = await this.fetchListPublicIpAddress()
|
||||
listPublicIpAddress.forEach(item => {
|
||||
if (item.state === 'Free' || item.state === 'Reserved') {
|
||||
this.listPublicIpAddress.push({
|
||||
ipaddress: item.ipaddress,
|
||||
state: item.state
|
||||
})
|
||||
}
|
||||
})
|
||||
this.listPublicIpAddress.sort(function (a, b) {
|
||||
if (a.ipaddress < b.ipaddress) { return -1 }
|
||||
if (a.ipaddress > b.ipaddress) { return 1 }
|
||||
return 0
|
||||
})
|
||||
this.acquireIp = this.listPublicIpAddress && this.listPublicIpAddress.length > 0 ? this.listPublicIpAddress[0].ipaddress : null
|
||||
this.acquireLoading = false
|
||||
} catch (e) {
|
||||
this.acquireLoading = false
|
||||
this.$notifyError(e)
|
||||
}
|
||||
},
|
||||
onCloseModal () {
|
||||
this.showAcquireIp = false
|
||||
},
|
||||
closeModal () {
|
||||
this.showConfirmationAction = false
|
||||
},
|
||||
showChangeSourceNat (ipaddress) {
|
||||
this.changeSourceNat = true
|
||||
this.sourceNatIp = ipaddress
|
||||
},
|
||||
cancelChangeSourceNat () {
|
||||
this.changeSourceNat = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,9 @@
|
|||
:footer="null"
|
||||
@cancel="showCreateNetworkModal = false">
|
||||
<a-spin :spinning="modalLoading" v-ctrl-enter="handleAddNetworkSubmit">
|
||||
<div v-if="!isNormalUserOrProject()">
|
||||
<ownership-selection @fetch-owner="fetchOwnerOptions"/>
|
||||
</div>
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:ref="formRef"
|
||||
|
|
@ -370,11 +373,13 @@ import { mixinForm } from '@/utils/mixin'
|
|||
import Status from '@/components/widgets/Status'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
import { getNetmaskFromCidr } from '@/utils/network'
|
||||
import OwnershipSelection from '@/views/compute/wizard/OwnershipSelection.vue'
|
||||
|
||||
export default {
|
||||
name: 'VpcTiersTab',
|
||||
mixins: [mixinForm],
|
||||
components: {
|
||||
OwnershipSelection,
|
||||
Status,
|
||||
TooltipLabel
|
||||
},
|
||||
|
|
@ -506,6 +511,9 @@ export default {
|
|||
isObjectEmpty (obj) {
|
||||
return !(obj !== null && obj !== undefined && Object.keys(obj).length > 0 && obj.constructor === Object)
|
||||
},
|
||||
isNormalUserOrProject () {
|
||||
return ['User'].includes(this.$store.getters.userInfo.roletype) || this.$store.getters.project?.id
|
||||
},
|
||||
initForm () {
|
||||
this.formRef = ref()
|
||||
this.form = reactive({})
|
||||
|
|
@ -536,6 +544,23 @@ export default {
|
|||
}
|
||||
this.publicLBNetworkExists()
|
||||
},
|
||||
fetchOwnerOptions (OwnerOptions) {
|
||||
this.owner = {}
|
||||
if (OwnerOptions.selectedAccountType === this.$t('label.account')) {
|
||||
if (!OwnerOptions.selectedAccount) {
|
||||
this.owner = undefined
|
||||
return
|
||||
}
|
||||
this.owner.account = OwnerOptions.selectedAccount
|
||||
this.owner.domainid = OwnerOptions.selectedDomain
|
||||
} else if (OwnerOptions.selectedAccountType === this.$t('label.project')) {
|
||||
if (!OwnerOptions.selectedProject) {
|
||||
this.owner = undefined
|
||||
return
|
||||
}
|
||||
this.owner.projectid = OwnerOptions.selectedProject
|
||||
}
|
||||
},
|
||||
fetchMtuForZone () {
|
||||
getAPI('listZones', {
|
||||
id: this.resource.zoneid
|
||||
|
|
@ -748,8 +773,9 @@ export default {
|
|||
this.showCreateNetworkModal = false
|
||||
var params = {
|
||||
vpcid: this.resource.id,
|
||||
domainid: this.resource.domainid,
|
||||
account: this.resource.account,
|
||||
domainid: this.owner?.domainid ? this.owner.domainid : this.resource.domainid,
|
||||
account: this.owner?.projectid ? null : (this.owner?.account ? this.owner.account : this.resource.account),
|
||||
projectid: this.owner?.projectid ? this.owner.projectid : null,
|
||||
networkOfferingId: values.networkOffering,
|
||||
name: values.name,
|
||||
displayText: values.name,
|
||||
|
|
|
|||
Loading…
Reference in New Issue