mirror of https://github.com/apache/cloudstack.git
New feature: VNF templates and appliances integration (#8022)
This commit is contained in:
parent
a06f8a8763
commit
bd52fa8a12
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.network;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
public class VNF {
|
||||||
|
|
||||||
|
public enum AccessMethod {
|
||||||
|
SSH_WITH_PASSWORD("ssh-password"),
|
||||||
|
SSH_WITH_KEY("ssh-key"),
|
||||||
|
HTTP("http"),
|
||||||
|
HTTPS("https"),
|
||||||
|
CONSOLE("console");
|
||||||
|
|
||||||
|
String _method;
|
||||||
|
|
||||||
|
AccessMethod(String method) {
|
||||||
|
_method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return _method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AccessMethod fromValue(String method) {
|
||||||
|
if (StringUtils.isBlank(method)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
for (AccessMethod accessMethod : AccessMethod.values()) {
|
||||||
|
if (accessMethod.toString().equalsIgnoreCase(method)) {
|
||||||
|
return accessMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AccessDetail {
|
||||||
|
ACCESS_METHODS,
|
||||||
|
USERNAME,
|
||||||
|
PASSWORD,
|
||||||
|
SSH_USER,
|
||||||
|
SSH_PASSWORD,
|
||||||
|
SSH_PORT,
|
||||||
|
WEB_USER,
|
||||||
|
WEB_PASSWORD,
|
||||||
|
HTTP_PATH,
|
||||||
|
HTTP_PORT,
|
||||||
|
HTTPS_PATH,
|
||||||
|
HTTPS_PORT
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum VnfDetail {
|
||||||
|
ICON,
|
||||||
|
VERSION,
|
||||||
|
VENDOR,
|
||||||
|
MAINTAINER
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class VnfNic {
|
||||||
|
long deviceId;
|
||||||
|
String name;
|
||||||
|
boolean required;
|
||||||
|
boolean management;
|
||||||
|
String description;
|
||||||
|
|
||||||
|
public VnfNic(long deviceId, String nicName, boolean required, boolean management, String nicDescription) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.name = nicName;
|
||||||
|
this.required = required;
|
||||||
|
this.management = management;
|
||||||
|
this.description = nicDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequired() {
|
||||||
|
return required;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isManagement() {
|
||||||
|
return management;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
|
||||||
public enum ResourceObjectType {
|
public enum ResourceObjectType {
|
||||||
UserVm(true, true, true),
|
UserVm(true, true, true),
|
||||||
Template(true, true, true),
|
Template(true, true, true),
|
||||||
|
VnfTemplate(true, true, true),
|
||||||
ISO(true, false, true),
|
ISO(true, false, true),
|
||||||
Volume(true, true),
|
Volume(true, true),
|
||||||
Snapshot(true, false),
|
Snapshot(true, false),
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ public class Storage {
|
||||||
BUILTIN, /* buildin template */
|
BUILTIN, /* buildin template */
|
||||||
PERHOST, /* every host has this template, don't need to install it in secondary storage */
|
PERHOST, /* every host has this template, don't need to install it in secondary storage */
|
||||||
USER, /* User supplied template/iso */
|
USER, /* User supplied template/iso */
|
||||||
|
VNF, /* VNFs (virtual network functions) template */
|
||||||
DATADISK, /* Template corresponding to a datadisk(non root disk) present in an OVA */
|
DATADISK, /* Template corresponding to a datadisk(non root disk) present in an OVA */
|
||||||
ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */
|
ISODISK /* Template corresponding to a iso (non root disk) present in an OVA */
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -436,6 +436,7 @@ public class ApiConstants {
|
||||||
public static final String TEMPLATE_ID = "templateid";
|
public static final String TEMPLATE_ID = "templateid";
|
||||||
public static final String TEMPLATE_IDS = "templateids";
|
public static final String TEMPLATE_IDS = "templateids";
|
||||||
public static final String TEMPLATE_NAME = "templatename";
|
public static final String TEMPLATE_NAME = "templatename";
|
||||||
|
public static final String TEMPLATE_TYPE = "templatetype";
|
||||||
public static final String TIMEOUT = "timeout";
|
public static final String TIMEOUT = "timeout";
|
||||||
public static final String TIMEZONE = "timezone";
|
public static final String TIMEZONE = "timezone";
|
||||||
public static final String TIMEZONEOFFSET = "timezoneoffset";
|
public static final String TIMEZONEOFFSET = "timezoneoffset";
|
||||||
|
|
@ -1013,7 +1014,6 @@ public class ApiConstants {
|
||||||
public static final String DEPLOY_AS_IS = "deployasis";
|
public static final String DEPLOY_AS_IS = "deployasis";
|
||||||
public static final String DEPLOY_AS_IS_DETAILS = "deployasisdetails";
|
public static final String DEPLOY_AS_IS_DETAILS = "deployasisdetails";
|
||||||
public static final String CROSS_ZONES = "crossZones";
|
public static final String CROSS_ZONES = "crossZones";
|
||||||
public static final String TEMPLATETYPE = "templatetype";
|
|
||||||
public static final String SOURCETEMPLATEID = "sourcetemplateid";
|
public static final String SOURCETEMPLATEID = "sourcetemplateid";
|
||||||
public static final String DYNAMIC_SCALING_ENABLED = "dynamicscalingenabled";
|
public static final String DYNAMIC_SCALING_ENABLED = "dynamicscalingenabled";
|
||||||
public static final String IOTHREADS_ENABLED = "iothreadsenabled";
|
public static final String IOTHREADS_ENABLED = "iothreadsenabled";
|
||||||
|
|
@ -1047,6 +1047,15 @@ public class ApiConstants {
|
||||||
public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid";
|
public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid";
|
||||||
public static final String HAS_RULES = "hasrules";
|
public static final String HAS_RULES = "hasrules";
|
||||||
|
|
||||||
|
public static final String MANAGEMENT = "management";
|
||||||
|
public static final String IS_VNF = "isvnf";
|
||||||
|
public static final String VNF_NICS = "vnfnics";
|
||||||
|
public static final String VNF_DETAILS = "vnfdetails";
|
||||||
|
public static final String CLEAN_UP_VNF_DETAILS = "cleanupvnfdetails";
|
||||||
|
public static final String CLEAN_UP_VNF_NICS = "cleanupvnfnics";
|
||||||
|
public static final String VNF_CONFIGURE_MANAGEMENT = "vnfconfiguremanagement";
|
||||||
|
public static final String VNF_CIDR_LIST = "vnfcidrlist";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
* This enum specifies IO Drivers, each option controls specific policies on I/O.
|
||||||
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
|
* Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0).
|
||||||
|
|
@ -1092,7 +1101,7 @@ public class ApiConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum VMDetails {
|
public enum VMDetails {
|
||||||
all, group, nics, stats, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp;
|
all, group, nics, stats, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp, vnfnics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DomainDetails {
|
public enum DomainDetails {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
|
||||||
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
|
import org.apache.cloudstack.network.lb.InternalLoadBalancerVMService;
|
||||||
import org.apache.cloudstack.query.QueryService;
|
import org.apache.cloudstack.query.QueryService;
|
||||||
import org.apache.cloudstack.storage.ImageStoreService;
|
import org.apache.cloudstack.storage.ImageStoreService;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateManager;
|
||||||
import org.apache.cloudstack.usage.UsageService;
|
import org.apache.cloudstack.usage.UsageService;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
@ -213,6 +214,8 @@ public abstract class BaseCmd {
|
||||||
public ResourceIconManager resourceIconManager;
|
public ResourceIconManager resourceIconManager;
|
||||||
@Inject
|
@Inject
|
||||||
public Ipv6Service ipv6Service;
|
public Ipv6Service ipv6Service;
|
||||||
|
@Inject
|
||||||
|
public VnfTemplateManager vnfTemplateManager;
|
||||||
|
|
||||||
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
|
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
|
||||||
ResourceAllocationException, NetworkRuleConflictException;
|
ResourceAllocationException, NetworkRuleConflictException;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.admin.template;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.ListVnfTemplatesCmd;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
|
||||||
|
@APICommand(name = "listVnfTemplates", description = "List all public, private, and privileged VNF templates.",
|
||||||
|
responseObject = TemplateResponse.class, entityType = {VirtualMachineTemplate.class}, responseView = ResponseView.Full,
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||||
|
since = "4.19.0")
|
||||||
|
public class ListVnfTemplatesCmdByAdmin extends ListVnfTemplatesCmd implements AdminCmd {
|
||||||
|
}
|
||||||
|
|
@ -18,9 +18,11 @@ package org.apache.cloudstack.api.command.admin.template;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
|
||||||
@APICommand(name = "registerTemplate", description = "Registers an existing template into the CloudStack cloud.", responseObject = TemplateResponse.class, responseView = ResponseView.Full,
|
@APICommand(name = "registerTemplate", description = "Registers an existing template into the CloudStack cloud.", responseObject = TemplateResponse.class, responseView = ResponseView.Full,
|
||||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||||
public class RegisterTemplateCmdByAdmin extends RegisterTemplateCmd {}
|
public class RegisterTemplateCmdByAdmin extends RegisterTemplateCmd implements AdminCmd {
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.admin.template;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
|
||||||
|
@APICommand(name = "registerVnfTemplate",
|
||||||
|
description = "Registers an existing VNF template into the CloudStack cloud. ",
|
||||||
|
responseObject = TemplateResponse.class, responseView = ResponseView.Full,
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||||
|
since = "4.19.0")
|
||||||
|
public class RegisterVnfTemplateCmdByAdmin extends RegisterVnfTemplateCmd implements AdminCmd {
|
||||||
|
}
|
||||||
|
|
@ -24,4 +24,5 @@ import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
|
||||||
@APICommand(name = "updateTemplate", description = "Updates attributes of a template.", responseObject = TemplateResponse.class, responseView = ResponseView.Full,
|
@APICommand(name = "updateTemplate", description = "Updates attributes of a template.", responseObject = TemplateResponse.class, responseView = ResponseView.Full,
|
||||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||||
public class UpdateTemplateCmdByAdmin extends UpdateTemplateCmd implements AdminCmd {}
|
public class UpdateTemplateCmdByAdmin extends UpdateTemplateCmd implements AdminCmd {
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.admin.template;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
|
||||||
|
@APICommand(name = "updateVnfTemplate",
|
||||||
|
description = "Updates a template to VNF template or attributes of a VNF template.",
|
||||||
|
responseObject = TemplateResponse.class, responseView = ResponseView.Full,
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||||
|
since = "4.19.0")
|
||||||
|
public class UpdateVnfTemplateCmdByAdmin extends UpdateVnfTemplateCmd implements AdminCmd {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.admin.vm;
|
||||||
|
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject;
|
||||||
|
import org.apache.cloudstack.api.command.admin.AdminCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
||||||
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
|
||||||
|
@APICommand(name = "deployVnfAppliance",
|
||||||
|
description = "Creates and automatically starts a VNF appliance based on a service offering, disk offering, and template.",
|
||||||
|
responseObject = UserVmResponse.class,
|
||||||
|
responseView = ResponseObject.ResponseView.Full,
|
||||||
|
entityType = {VirtualMachine.class},
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true,
|
||||||
|
since = "4.19.0")
|
||||||
|
public class DeployVnfApplianceCmdByAdmin extends DeployVnfApplianceCmd implements AdminCmd {
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.user.template;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||||
|
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
|
||||||
|
@APICommand(name = "deleteVnfTemplate",
|
||||||
|
responseObject = SuccessResponse.class,
|
||||||
|
description = "Deletes a VNF template from the system. All virtual machines using the deleted template will not be affected.",
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||||
|
since = "4.19.0")
|
||||||
|
public class DeleteVnfTemplateCmd extends DeleteTemplateCmd {
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getEntityOwnerId() {
|
||||||
|
VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, getId());
|
||||||
|
if (template != null) {
|
||||||
|
return template.getAccountId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Account.ACCOUNT_ID_SYSTEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -96,6 +96,15 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
||||||
description = "comma separated list of template details requested, value can be a list of [ all, min]")
|
description = "comma separated list of template details requested, value can be a list of [ all, min]")
|
||||||
private List<String> viewDetails;
|
private List<String> viewDetails;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.TEMPLATE_TYPE, type = CommandType.STRING,
|
||||||
|
description = "the type of the template", since = "4.19.0")
|
||||||
|
private String templateType;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_VNF, type = CommandType.BOOLEAN,
|
||||||
|
description = "flag to list VNF templates or not; true if need to list VNF templates, false otherwise.",
|
||||||
|
since = "4.19.0")
|
||||||
|
private Boolean isVnf;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
@ -151,6 +160,10 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
||||||
return parentTemplateId;
|
return parentTemplateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTemplateType() {
|
||||||
|
return templateType;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean listInReadyState() {
|
public boolean listInReadyState() {
|
||||||
|
|
||||||
Account account = CallContext.current().getCallingAccount();
|
Account account = CallContext.current().getCallingAccount();
|
||||||
|
|
@ -175,6 +188,10 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
||||||
return showIcon != null ? showIcon : false;
|
return showIcon != null ? showIcon : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getVnf() {
|
||||||
|
return isVnf;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCommandName() {
|
public String getCommandName() {
|
||||||
return s_name;
|
return s_name;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.user.template;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
|
||||||
|
@APICommand(name = "listVnfTemplates", description = "List all public, private, and privileged VNF templates.",
|
||||||
|
responseObject = TemplateResponse.class, entityType = {VirtualMachineTemplate.class}, responseView = ResponseView.Restricted,
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||||
|
since = "4.19.0")
|
||||||
|
public class ListVnfTemplatesCmd extends ListTemplatesCmd implements UserCmd {
|
||||||
|
}
|
||||||
|
|
@ -143,6 +143,7 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
||||||
description = "true if template contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory")
|
description = "true if template contains XS/VMWare tools inorder to support dynamic scaling of VM cpu/memory")
|
||||||
protected Boolean isDynamicallyScalable;
|
protected Boolean isDynamicallyScalable;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
@Parameter(name = ApiConstants.ROUTING, type = CommandType.BOOLEAN, description = "true if the template type is routing i.e., if template is used to deploy router")
|
@Parameter(name = ApiConstants.ROUTING, type = CommandType.BOOLEAN, description = "true if the template type is routing i.e., if template is used to deploy router")
|
||||||
protected Boolean isRoutingType;
|
protected Boolean isRoutingType;
|
||||||
|
|
||||||
|
|
@ -168,6 +169,11 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
||||||
description = "(VMware only) true if VM deployments should preserve all the configurations defined for this template", since = "4.15.1")
|
description = "(VMware only) true if VM deployments should preserve all the configurations defined for this template", since = "4.15.1")
|
||||||
protected Boolean deployAsIs;
|
protected Boolean deployAsIs;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.TEMPLATE_TYPE, type = CommandType.STRING,
|
||||||
|
description = "the type of the template. Valid options are: USER/VNF (for all users) and SYSTEM/ROUTING/BUILTIN (for admins only).",
|
||||||
|
since = "4.19.0")
|
||||||
|
private String templateType;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
@ -285,6 +291,10 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
||||||
Boolean.TRUE.equals(deployAsIs);
|
Boolean.TRUE.equals(deployAsIs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTemplateType() {
|
||||||
|
return templateType;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
@ -315,7 +325,7 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
||||||
|
|
||||||
VirtualMachineTemplate template = _templateService.registerTemplate(this);
|
VirtualMachineTemplate template = _templateService.registerTemplate(this);
|
||||||
if (template != null) {
|
if (template != null) {
|
||||||
ListResponse<TemplateResponse> response = new ListResponse<TemplateResponse>();
|
ListResponse<TemplateResponse> response = new ListResponse<>();
|
||||||
List<TemplateResponse> templateResponses = _responseGenerator.createTemplateResponses(getResponseView(),
|
List<TemplateResponse> templateResponses = _responseGenerator.createTemplateResponses(getResponseView(),
|
||||||
template, getZoneIds(), false);
|
template, getZoneIds(), false);
|
||||||
response.setResponses(templateResponses);
|
response.setResponses(templateResponses);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.user.template;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.cloud.network.VNF;
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateUtils;
|
||||||
|
|
||||||
|
@APICommand(name = "registerVnfTemplate",
|
||||||
|
description = "Registers an existing VNF template into the CloudStack cloud. ",
|
||||||
|
responseObject = TemplateResponse.class, responseView = ResponseView.Restricted,
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||||
|
since = "4.19.0")
|
||||||
|
public class RegisterVnfTemplateCmd extends RegisterTemplateCmd implements UserCmd {
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VNF_NICS,
|
||||||
|
type = CommandType.MAP,
|
||||||
|
description = "VNF nics in key/value pairs using format vnfnics[i].keyname=keyvalue. "
|
||||||
|
+ " Example: vnfnics[0].deviceid=0&&vnfnics[0].name=FirstNIC&&vnfnics[0].required=true"
|
||||||
|
+ "&&vnfnics[1].deviceid=1&&vnfnics[1].name=SecondNIC")
|
||||||
|
protected Map vnfNics;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VNF_DETAILS,
|
||||||
|
type = CommandType.MAP,
|
||||||
|
description = "VNF details in key/value pairs using format vnfdetails[i].keyname=keyvalue. "
|
||||||
|
+ "Example: vnfdetails[0].vendor=xxx&&vnfdetails[0].version=2.0")
|
||||||
|
protected Map vnfDetails;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public List<VNF.VnfNic> getVnfNics() {
|
||||||
|
return VnfTemplateUtils.getVnfNicsList(this.vnfNics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getVnfDetails() {
|
||||||
|
return convertDetailsToMap(vnfDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////// API Implementation///////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void validateParameters() {
|
||||||
|
super.validateParameters();
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateApiCommandParams(this, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,10 +16,11 @@
|
||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.command.user.template;
|
package org.apache.cloudstack.api.command.user.template;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.APICommand;
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.api.ApiErrorCode;
|
import org.apache.cloudstack.api.ApiErrorCode;
|
||||||
import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd;
|
import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd;
|
||||||
import org.apache.cloudstack.api.Parameter;
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
|
@ -41,7 +42,8 @@ public class UpdateTemplateCmd extends BaseUpdateTemplateOrIsoCmd implements Use
|
||||||
//////////////// API parameters /////////////////////
|
//////////////// API parameters /////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Parameter(name = "templatetype", type = CommandType.STRING, description = "the type of the template")
|
@Parameter(name = ApiConstants.TEMPLATE_TYPE, type = CommandType.STRING,
|
||||||
|
description = "the type of the template. Valid options are: USER/VNF (for all users) and SYSTEM/ROUTING/BUILTIN (for admins only).")
|
||||||
private String templateType;
|
private String templateType;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.user.template;
|
||||||
|
|
||||||
|
import com.cloud.network.VNF;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject.ResponseView;
|
||||||
|
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||||
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@APICommand(name = "updateVnfTemplate", description = "Updates a template to VNF template or attributes of a VNF template.",
|
||||||
|
responseObject = TemplateResponse.class, responseView = ResponseView.Restricted,
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||||
|
since = "4.19.0")
|
||||||
|
public class UpdateVnfTemplateCmd extends UpdateTemplateCmd implements UserCmd {
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
//////////////// API parameters /////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VNF_NICS,
|
||||||
|
type = CommandType.MAP,
|
||||||
|
description = "VNF nics in key/value pairs using format vnfnics[i].keyname=keyvalue. "
|
||||||
|
+ " Example: vnfnics[0].deviceid=0&&vnfnics[0].name=FirstNIC&&vnfnics[0].required=true"
|
||||||
|
+ "&&vnfnics[1].deviceid=1&&vnfnics[1].name=SecondNIC")
|
||||||
|
protected Map vnfNics;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VNF_DETAILS,
|
||||||
|
type = CommandType.MAP,
|
||||||
|
description = "VNF details in key/value pairs using format vnfdetails[i].keyname=keyvalue. "
|
||||||
|
+ "Example: vnfdetails[0].vendor=xxx&&vnfdetails[0].version=2.0")
|
||||||
|
protected Map vnfDetails;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CLEAN_UP_VNF_DETAILS,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
description = "optional boolean field, which indicates if VNF details will be cleaned up or not")
|
||||||
|
private Boolean cleanupVnfDetails = null;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CLEAN_UP_VNF_NICS,
|
||||||
|
type = CommandType.BOOLEAN,
|
||||||
|
description = "optional boolean field, which indicates if VNF nics will be cleaned up or not")
|
||||||
|
private Boolean cleanupVnfNics = null;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
/////////////////// Accessors ///////////////////////
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
public List<VNF.VnfNic> getVnfNics() {
|
||||||
|
return VnfTemplateUtils.getVnfNicsList(this.vnfNics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getVnfDetails() {
|
||||||
|
return convertDetailsToMap(vnfDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCleanupVnfDetails(){
|
||||||
|
return cleanupVnfDetails == null ? false : cleanupVnfDetails.booleanValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCleanupVnfNics(){
|
||||||
|
return cleanupVnfNics == null ? false : cleanupVnfNics.booleanValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.command.user.vm;
|
||||||
|
|
||||||
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
|
import com.cloud.utils.net.NetUtils;
|
||||||
|
import com.cloud.vm.VirtualMachine;
|
||||||
|
import org.apache.cloudstack.acl.RoleType;
|
||||||
|
import org.apache.cloudstack.api.APICommand;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.Parameter;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject;
|
||||||
|
import org.apache.cloudstack.api.command.user.UserCmd;
|
||||||
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateUtils;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@APICommand(name = "deployVnfAppliance",
|
||||||
|
description = "Creates and automatically starts a VNF appliance based on a service offering, disk offering, and template.",
|
||||||
|
responseObject = UserVmResponse.class,
|
||||||
|
responseView = ResponseObject.ResponseView.Restricted,
|
||||||
|
entityType = {VirtualMachine.class},
|
||||||
|
requestHasSensitiveInfo = false, responseHasSensitiveInfo = true,
|
||||||
|
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||||
|
since = "4.19.0")
|
||||||
|
public class DeployVnfApplianceCmd extends DeployVMCmd implements UserCmd {
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VNF_CONFIGURE_MANAGEMENT, type = CommandType.BOOLEAN, required = false,
|
||||||
|
description = "True by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. False otherwise. " +
|
||||||
|
"Network rules are configured if management network is an isolated network or shared network with security groups.")
|
||||||
|
private Boolean vnfConfigureManagement;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.VNF_CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING,
|
||||||
|
description = "the CIDR list to forward traffic from to the VNF management interface. Multiple entries must be separated by a single comma character (,). The default value is 0.0.0.0/0.")
|
||||||
|
private List<String> vnfCidrlist;
|
||||||
|
|
||||||
|
public Boolean getVnfConfigureManagement() {
|
||||||
|
return vnfConfigureManagement != null && vnfConfigureManagement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getVnfCidrlist() {
|
||||||
|
if (CollectionUtils.isNotEmpty(vnfCidrlist)) {
|
||||||
|
return vnfCidrlist;
|
||||||
|
} else {
|
||||||
|
List<String> defaultCidrList = new ArrayList<String>();
|
||||||
|
defaultCidrList.add(NetUtils.ALL_IP4_CIDRS);
|
||||||
|
return defaultCidrList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create() throws ResourceAllocationException {
|
||||||
|
VnfTemplateUtils.validateVnfCidrList(this.getVnfCidrlist());
|
||||||
|
|
||||||
|
super.create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -189,6 +189,10 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements
|
||||||
return zoneId;
|
return zoneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IS_VNF, type = CommandType.BOOLEAN,
|
||||||
|
description = "flag to list vms created from VNF templates (as known as VNF appliances) or not; true if need to list VNF appliances, false otherwise.",
|
||||||
|
since = "4.19.0")
|
||||||
|
private Boolean isVnf;
|
||||||
|
|
||||||
public Long getNetworkId() {
|
public Long getNetworkId() {
|
||||||
return networkId;
|
return networkId;
|
||||||
|
|
@ -266,6 +270,10 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements
|
||||||
return accumulate;
|
return accumulate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Boolean getVnf() {
|
||||||
|
return isVnf;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ public class ChildTemplateResponse extends BaseResponse {
|
||||||
@Param(description = "the size of the template")
|
@Param(description = "the size of the template")
|
||||||
private Integer size;
|
private Integer size;
|
||||||
|
|
||||||
@SerializedName("templatetype")
|
@SerializedName(ApiConstants.TEMPLATE_TYPE)
|
||||||
@Param(description = "the type of the template")
|
@Param(description = "the type of the template")
|
||||||
private String templateType;
|
private String templateType;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,14 @@ public class NicResponse extends BaseResponse {
|
||||||
@Param(description = "MTU configured on the NIC", since="4.18.0")
|
@Param(description = "MTU configured on the NIC", since="4.18.0")
|
||||||
private Integer mtu;
|
private Integer mtu;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.PUBLIC_IP_ID)
|
||||||
|
@Param(description = "public IP address id associated with this nic via Static nat rule")
|
||||||
|
private String publicIpId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.PUBLIC_IP)
|
||||||
|
@Param(description = "public IP address associated with this nic via Static nat rule")
|
||||||
|
private String publicIp;
|
||||||
|
|
||||||
public void setVmId(String vmId) {
|
public void setVmId(String vmId) {
|
||||||
this.vmId = vmId;
|
this.vmId = vmId;
|
||||||
}
|
}
|
||||||
|
|
@ -400,4 +408,12 @@ public class NicResponse extends BaseResponse {
|
||||||
public String getVpcId() {
|
public String getVpcId() {
|
||||||
return vpcId;
|
return vpcId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPublicIpId(String publicIpId) {
|
||||||
|
this.publicIpId = publicIpId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPublicIp(String publicIp) {
|
||||||
|
this.publicIp = publicIp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
||||||
@Param(description = "the physical size of the template")
|
@Param(description = "the physical size of the template")
|
||||||
private Long physicalSize;
|
private Long physicalSize;
|
||||||
|
|
||||||
@SerializedName(ApiConstants.TEMPLATETYPE)
|
@SerializedName(ApiConstants.TEMPLATE_TYPE)
|
||||||
@Param(description = "the type of the template")
|
@Param(description = "the type of the template")
|
||||||
private String templateType;
|
private String templateType;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,12 @@
|
||||||
// under the License.
|
// under the License.
|
||||||
package org.apache.cloudstack.api.response;
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
@ -130,6 +133,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
||||||
@Param(description = "the name of the template for the virtual machine")
|
@Param(description = "the name of the template for the virtual machine")
|
||||||
private String templateName;
|
private String templateName;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.TEMPLATE_TYPE)
|
||||||
|
@Param(description = "the type of the template for the virtual machine", since = "4.19.0")
|
||||||
|
private String templateType;
|
||||||
|
|
||||||
@SerializedName("templatedisplaytext")
|
@SerializedName("templatedisplaytext")
|
||||||
@Param(description = " an alternate display text of the template for the virtual machine")
|
@Param(description = " an alternate display text of the template for the virtual machine")
|
||||||
private String templateDisplayText;
|
private String templateDisplayText;
|
||||||
|
|
@ -360,6 +367,14 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
||||||
@SerializedName(ApiConstants.USER_DATA_DETAILS) @Param(description="list of variables and values for the variables declared in userdata", since = "4.18.0")
|
@SerializedName(ApiConstants.USER_DATA_DETAILS) @Param(description="list of variables and values for the variables declared in userdata", since = "4.18.0")
|
||||||
private String userDataDetails;
|
private String userDataDetails;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VNF_NICS)
|
||||||
|
@Param(description = "NICs of the VNF appliance", since = "4.19.0")
|
||||||
|
private List<VnfNicResponse> vnfNics;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VNF_DETAILS)
|
||||||
|
@Param(description = "VNF details", since = "4.19.0")
|
||||||
|
private Map<String, String> vnfDetails;
|
||||||
|
|
||||||
public UserVmResponse() {
|
public UserVmResponse() {
|
||||||
securityGroupList = new LinkedHashSet<>();
|
securityGroupList = new LinkedHashSet<>();
|
||||||
nics = new TreeSet<>(Comparator.comparingInt(x -> Integer.parseInt(x.getDeviceId())));
|
nics = new TreeSet<>(Comparator.comparingInt(x -> Integer.parseInt(x.getDeviceId())));
|
||||||
|
|
@ -1045,4 +1060,49 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
||||||
this.userDataDetails = userDataDetails;
|
this.userDataDetails = userDataDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getBytesReceived() {
|
||||||
|
return bytesReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBytesSent() {
|
||||||
|
return bytesSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemplateType() {
|
||||||
|
return templateType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTemplateType(String templateType) {
|
||||||
|
this.templateType = templateType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VnfNicResponse> getVnfNics() {
|
||||||
|
return vnfNics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVnfNics(List<VnfNicResponse> vnfNics) {
|
||||||
|
this.vnfNics = vnfNics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getVnfDetails() {
|
||||||
|
return vnfDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVnfDetails(Map<String, String> vnfDetails) {
|
||||||
|
this.vnfDetails = vnfDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addVnfNic(VnfNicResponse vnfNic) {
|
||||||
|
if (this.vnfNics == null) {
|
||||||
|
this.vnfNics = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.vnfNics.add(vnfNic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addVnfDetail(String key, String value) {
|
||||||
|
if (this.vnfDetails == null) {
|
||||||
|
this.vnfDetails = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
this.vnfDetails.put(key,value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import com.cloud.serializer.Param;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class VnfNicResponse {
|
||||||
|
@SerializedName(ApiConstants.DEVICE_ID)
|
||||||
|
@Param(description = "Device id of the NIC")
|
||||||
|
private long deviceId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.NAME)
|
||||||
|
@Param(description = "Name of the NIC")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.REQUIRED)
|
||||||
|
@Param(description = "True if the NIC is required. False if optional")
|
||||||
|
private Boolean required;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.MANAGEMENT)
|
||||||
|
@Param(description = "True if the NIC is a management interface. False otherwise")
|
||||||
|
private Boolean management;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.DESCRIPTION)
|
||||||
|
@Param(description = "Description of the NIC")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.NETWORK_ID)
|
||||||
|
@Param(description = "Network id of the NIC")
|
||||||
|
private String networkId;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.NETWORK_NAME)
|
||||||
|
@Param(description = "Network name of the NIC")
|
||||||
|
private String networkName;
|
||||||
|
|
||||||
|
public void setDeviceId(long deviceId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequired(Boolean required) {
|
||||||
|
this.required = required;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setManagement(Boolean management) {
|
||||||
|
this.management = management;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetworkId(String networkId) {
|
||||||
|
this.networkId = networkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNetworkName(String networkName) {
|
||||||
|
this.networkName = networkName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VnfNicResponse() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VnfNicResponse(long deviceId, String name, Boolean required, Boolean management, String description) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.name = name;
|
||||||
|
this.required = required;
|
||||||
|
this.management = management;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isRequired() {
|
||||||
|
return required;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean isManagement() {
|
||||||
|
return management;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNetworkId() {
|
||||||
|
return networkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNetworkName() {
|
||||||
|
return networkName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import com.cloud.serializer.Param;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class VnfTemplateResponse extends TemplateResponse {
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VNF_NICS)
|
||||||
|
@Param(description = "NICs of the VNF template")
|
||||||
|
private List<VnfNicResponse> vnfNics;
|
||||||
|
|
||||||
|
@SerializedName(ApiConstants.VNF_DETAILS)
|
||||||
|
@Param(description = "VNF details")
|
||||||
|
private Map<String, String> vnfDetails;
|
||||||
|
|
||||||
|
public void addVnfNic(VnfNicResponse vnfNic) {
|
||||||
|
if (this.vnfNics == null) {
|
||||||
|
this.vnfNics = new ArrayList<>();
|
||||||
|
}
|
||||||
|
this.vnfNics.add(vnfNic);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addVnfDetail(String key, String value) {
|
||||||
|
if (this.vnfDetails == null) {
|
||||||
|
this.vnfDetails = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
this.vnfDetails.put(key,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<VnfNicResponse> getVnfNics() {
|
||||||
|
return vnfNics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getVnfDetails() {
|
||||||
|
return vnfDetails;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.storage.template;
|
||||||
|
|
||||||
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||||
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.network.security.SecurityGroup;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.uservm.UserVm;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface VnfTemplateManager {
|
||||||
|
|
||||||
|
ConfigKey<Boolean> VnfTemplateAndApplianceEnabled = new ConfigKey<Boolean>("Advanced", Boolean.class,
|
||||||
|
"vnf.template.appliance.enabled",
|
||||||
|
"true",
|
||||||
|
"Indicates whether the creation of VNF templates and VNF appliances is enabled or not.",
|
||||||
|
false);
|
||||||
|
|
||||||
|
void persistVnfTemplate(long templateId, RegisterVnfTemplateCmd cmd);
|
||||||
|
|
||||||
|
void updateVnfTemplate(long templateId, UpdateVnfTemplateCmd cmd);
|
||||||
|
|
||||||
|
void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds);
|
||||||
|
|
||||||
|
SecurityGroup createSecurityGroupForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner, DeployVnfApplianceCmd cmd);
|
||||||
|
|
||||||
|
void createIsolatedNetworkRulesForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner,
|
||||||
|
UserVm vm, DeployVnfApplianceCmd cmd)
|
||||||
|
throws InsufficientAddressCapacityException, ResourceAllocationException, ResourceUnavailableException;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,152 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.storage.template;
|
||||||
|
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.network.VNF;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.utils.net.NetUtils;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.DeleteVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.apache.commons.lang3.EnumUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class VnfTemplateUtils {
|
||||||
|
private VnfTemplateUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<VNF.VnfNic> getVnfNicsList(Map vnfNics) {
|
||||||
|
List<VNF.VnfNic> nicsList = new ArrayList<>();
|
||||||
|
if (MapUtils.isNotEmpty(vnfNics)) {
|
||||||
|
Collection nicsCollection = vnfNics.values();
|
||||||
|
Iterator iter = nicsCollection.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
HashMap<String, String> nicDetails = (HashMap<String, String>)iter.next();
|
||||||
|
String deviceIdString = nicDetails.get("deviceid");
|
||||||
|
String name = nicDetails.get("name");
|
||||||
|
String requiredString = nicDetails.get("required");
|
||||||
|
String managementString = nicDetails.get("management");
|
||||||
|
String description = nicDetails.get("description");
|
||||||
|
Integer deviceId = null;
|
||||||
|
if (StringUtils.isAnyBlank(name, deviceIdString)) {
|
||||||
|
throw new InvalidParameterValueException("VNF nic name and deviceid cannot be null");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
deviceId = Integer.parseInt(deviceIdString);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidParameterValueException("Unable to parse VNF nic deviceId to Integer: " + deviceId);
|
||||||
|
}
|
||||||
|
boolean required = StringUtils.isBlank(requiredString) || Boolean.parseBoolean(requiredString);
|
||||||
|
boolean management = StringUtils.isBlank(managementString) || Boolean.parseBoolean(managementString);
|
||||||
|
nicsList.add(new VNF.VnfNic(deviceId, name, required, management, description));
|
||||||
|
}
|
||||||
|
Collections.sort(nicsList, Comparator.comparing(VNF.VnfNic::getDeviceId));
|
||||||
|
}
|
||||||
|
return nicsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateApiCommandParams(Map<String, String> vnfDetails, List<VNF.VnfNic> vnfNics, String templateType) {
|
||||||
|
if (templateType != null && !Storage.TemplateType.VNF.name().equals(templateType)) {
|
||||||
|
throw new InvalidParameterValueException("The template type must be VNF for VNF templates.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vnfDetails != null) {
|
||||||
|
for (String vnfDetail : vnfDetails.keySet()) {
|
||||||
|
if (!EnumUtils.isValidEnumIgnoreCase(VNF.VnfDetail.class, vnfDetail) &&
|
||||||
|
!EnumUtils.isValidEnumIgnoreCase(VNF.AccessDetail.class, vnfDetail)) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Invalid VNF detail found: %s. Valid values are %s and %s", vnfDetail,
|
||||||
|
Arrays.stream(VNF.AccessDetail.values()).map(method -> method.toString()).collect(Collectors.joining(", ")),
|
||||||
|
Arrays.stream(VNF.VnfDetail.values()).map(method -> method.toString()).collect(Collectors.joining(", "))));
|
||||||
|
}
|
||||||
|
if (vnfDetails.get(vnfDetail) == null) {
|
||||||
|
throw new InvalidParameterValueException("Empty value found for VNF detail: " + vnfDetail);
|
||||||
|
}
|
||||||
|
if (VNF.AccessDetail.ACCESS_METHODS.name().equalsIgnoreCase(vnfDetail)) {
|
||||||
|
String[] accessMethods = vnfDetails.get(vnfDetail).split(",");
|
||||||
|
for (String accessMethod : accessMethods) {
|
||||||
|
if (VNF.AccessMethod.fromValue(accessMethod.trim()) == null) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Invalid VNF access method found: %s. Valid values are %s", accessMethod,
|
||||||
|
Arrays.stream(VNF.AccessMethod.values()).map(method -> method.toString()).sorted().collect(Collectors.joining(", "))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateVnfNics(vnfNics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateVnfNics(List<VNF.VnfNic> nicsList) {
|
||||||
|
long deviceId = 0L;
|
||||||
|
boolean required = true;
|
||||||
|
for (VNF.VnfNic nic : nicsList) {
|
||||||
|
if (nic.getDeviceId() != deviceId) {
|
||||||
|
throw new InvalidParameterValueException(String.format("deviceid must be consecutive and start from 0. Nic deviceid should be %s but actual is %s.", deviceId, nic.getDeviceId()));
|
||||||
|
}
|
||||||
|
if (!required && nic.isRequired()) {
|
||||||
|
throw new InvalidParameterValueException(String.format("required cannot be true if a preceding nic is optional. Nic with deviceid %s should be required but actual is optional.", deviceId));
|
||||||
|
}
|
||||||
|
deviceId ++;
|
||||||
|
required = nic.isRequired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateApiCommandParams(BaseCmd cmd, VirtualMachineTemplate template) {
|
||||||
|
if (cmd instanceof RegisterVnfTemplateCmd) {
|
||||||
|
RegisterVnfTemplateCmd registerCmd = (RegisterVnfTemplateCmd) cmd;
|
||||||
|
validateApiCommandParams(registerCmd.getVnfDetails(), registerCmd.getVnfNics(), registerCmd.getTemplateType());
|
||||||
|
} else if (cmd instanceof UpdateVnfTemplateCmd) {
|
||||||
|
UpdateVnfTemplateCmd updateCmd = (UpdateVnfTemplateCmd) cmd;
|
||||||
|
if (!Storage.TemplateType.VNF.equals(template.getTemplateType())) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Cannot update as template %s is not a VNF template. The template type is %s.", updateCmd.getId(), template.getTemplateType()));
|
||||||
|
}
|
||||||
|
validateApiCommandParams(updateCmd.getVnfDetails(), updateCmd.getVnfNics(), updateCmd.getTemplateType());
|
||||||
|
} else if (cmd instanceof DeleteVnfTemplateCmd) {
|
||||||
|
if (!Storage.TemplateType.VNF.equals(template.getTemplateType())) {
|
||||||
|
DeleteVnfTemplateCmd deleteCmd = (DeleteVnfTemplateCmd) cmd;
|
||||||
|
throw new InvalidParameterValueException(String.format("Cannot delete as Template %s is not a VNF template. The template type is %s.", deleteCmd.getId(), template.getTemplateType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void validateVnfCidrList(List<String> cidrList) {
|
||||||
|
if (CollectionUtils.isEmpty(cidrList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String cidr : cidrList) {
|
||||||
|
if (!NetUtils.isValidIp4Cidr(cidr)) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Invalid cidr for VNF appliance: %s", cidr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.network;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class VNFTest {
|
||||||
|
|
||||||
|
static long deviceId = 0L;
|
||||||
|
static String deviceName = "eth0";
|
||||||
|
static boolean required = true;
|
||||||
|
static boolean management = false;
|
||||||
|
static String description = "description of vnf nic";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAccessMethods() {
|
||||||
|
Assert.assertEquals(VNF.AccessMethod.CONSOLE, VNF.AccessMethod.fromValue("console"));
|
||||||
|
Assert.assertEquals(VNF.AccessMethod.HTTP, VNF.AccessMethod.fromValue("http"));
|
||||||
|
Assert.assertEquals(VNF.AccessMethod.HTTPS, VNF.AccessMethod.fromValue("https"));
|
||||||
|
Assert.assertEquals(VNF.AccessMethod.SSH_WITH_KEY, VNF.AccessMethod.fromValue("ssh-key"));
|
||||||
|
Assert.assertEquals(VNF.AccessMethod.SSH_WITH_PASSWORD, VNF.AccessMethod.fromValue("ssh-password"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVnfNic() {
|
||||||
|
VNF.VnfNic vnfNic = new VNF.VnfNic(deviceId, deviceName, required, management, description);
|
||||||
|
|
||||||
|
Assert.assertEquals(deviceId, vnfNic.getDeviceId());
|
||||||
|
Assert.assertEquals(deviceName, vnfNic.getName());
|
||||||
|
Assert.assertEquals(required, vnfNic.isRequired());
|
||||||
|
Assert.assertEquals(management, vnfNic.isManagement());
|
||||||
|
Assert.assertEquals(description, vnfNic.getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public final class VnfNicResponseTest {
|
||||||
|
|
||||||
|
static long deviceId = 0L;
|
||||||
|
static String deviceName = "eth0";
|
||||||
|
static boolean required = true;
|
||||||
|
static boolean management = false;
|
||||||
|
static String description = "description of vnf nic";
|
||||||
|
|
||||||
|
static String networkUuid = "networkuuid";
|
||||||
|
static String networkName = "networkname";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewVnfNicResponse() {
|
||||||
|
final VnfNicResponse response = new VnfNicResponse(deviceId, deviceName, required, management, description);
|
||||||
|
Assert.assertEquals(deviceId, response.getDeviceId());
|
||||||
|
Assert.assertEquals(deviceName, response.getName());
|
||||||
|
Assert.assertEquals(required, response.isRequired());
|
||||||
|
Assert.assertEquals(management, response.isManagement());
|
||||||
|
Assert.assertEquals(description, response.getDescription());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetVnfNicResponse() {
|
||||||
|
final VnfNicResponse response = new VnfNicResponse();
|
||||||
|
response.setNetworkId(networkUuid);
|
||||||
|
response.setNetworkName(networkName);
|
||||||
|
Assert.assertEquals(networkUuid, response.getNetworkId());
|
||||||
|
Assert.assertEquals(networkName, response.getNetworkName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.api.response;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public final class VnfTemplateResponseTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddVnfNicToResponse() {
|
||||||
|
final VnfTemplateResponse response = new VnfTemplateResponse();
|
||||||
|
|
||||||
|
response.addVnfNic(new VnfNicResponse());
|
||||||
|
response.addVnfNic(new VnfNicResponse());
|
||||||
|
|
||||||
|
Assert.assertEquals(2, response.getVnfNics().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddVnfDetailToResponse() {
|
||||||
|
final VnfTemplateResponse response = new VnfTemplateResponse();
|
||||||
|
|
||||||
|
response.addVnfDetail("key1", "value1");
|
||||||
|
response.addVnfDetail("key2", "value2");
|
||||||
|
response.addVnfDetail("key3", "value3");
|
||||||
|
|
||||||
|
Assert.assertEquals(3, response.getVnfDetails().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,261 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.storage.template;
|
||||||
|
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.network.VNF.VnfNic;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class VnfTemplateUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetVnfNicsListAllGood() {
|
||||||
|
final Map<String, Object> vnfNics = new HashMap<>();
|
||||||
|
vnfNics.put("0", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "1"),
|
||||||
|
Map.entry("name", "eth1"),
|
||||||
|
Map.entry("required", "true"),
|
||||||
|
Map.entry("description", "The second NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
vnfNics.put("1", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "2"),
|
||||||
|
Map.entry("name", "eth2"),
|
||||||
|
Map.entry("required", "false"),
|
||||||
|
Map.entry("description", "The third NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
vnfNics.put("2", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "0"),
|
||||||
|
Map.entry("name", "eth0"),
|
||||||
|
Map.entry("description", "The first NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
|
||||||
|
Map<String, Object> vnfNicsMock = Mockito.mock(Map.class);
|
||||||
|
Mockito.when(vnfNicsMock.values()).thenReturn(vnfNics.values());
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = VnfTemplateUtils.getVnfNicsList(vnfNicsMock);
|
||||||
|
Mockito.verify(vnfNicsMock).values();
|
||||||
|
|
||||||
|
Assert.assertEquals(3, nicsList.size());
|
||||||
|
Assert.assertEquals(0, nicsList.get(0).getDeviceId());
|
||||||
|
Assert.assertEquals("eth0", nicsList.get(0).getName());
|
||||||
|
Assert.assertTrue(nicsList.get(0).isRequired());
|
||||||
|
Assert.assertEquals(1, nicsList.get(1).getDeviceId());
|
||||||
|
Assert.assertEquals("eth1", nicsList.get(1).getName());
|
||||||
|
Assert.assertTrue(nicsList.get(1).isRequired());
|
||||||
|
Assert.assertEquals(2, nicsList.get(2).getDeviceId());
|
||||||
|
Assert.assertEquals("eth2", nicsList.get(2).getName());
|
||||||
|
Assert.assertFalse(nicsList.get(2).isRequired());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testGetVnfNicsListWithEmptyName() {
|
||||||
|
final Map<String, Object> vnfNics = new HashMap<>();
|
||||||
|
vnfNics.put("0", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "1"),
|
||||||
|
Map.entry("required", "true"),
|
||||||
|
Map.entry("description", "The second NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
|
||||||
|
Map<String, Object> vnfNicsMock = Mockito.mock(Map.class);
|
||||||
|
Mockito.when(vnfNicsMock.values()).thenReturn(vnfNics.values());
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = VnfTemplateUtils.getVnfNicsList(vnfNicsMock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testGetVnfNicsListWithEmptyDeviceId() {
|
||||||
|
final Map<String, Object> vnfNics = new HashMap<>();
|
||||||
|
vnfNics.put("0", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("name", "eth1"),
|
||||||
|
Map.entry("required", "true"),
|
||||||
|
Map.entry("description", "The second NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
|
||||||
|
Map<String, Object> vnfNicsMock = Mockito.mock(Map.class);
|
||||||
|
Mockito.when(vnfNicsMock.values()).thenReturn(vnfNics.values());
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = VnfTemplateUtils.getVnfNicsList(vnfNicsMock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testGetVnfNicsListWithInvalidDeviceId() {
|
||||||
|
final Map<String, Object> vnfNics = new HashMap<>();
|
||||||
|
vnfNics.put("0", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "invalid"),
|
||||||
|
Map.entry("name", "eth1"),
|
||||||
|
Map.entry("required", "true"),
|
||||||
|
Map.entry("description", "The second NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
|
||||||
|
Map<String, Object> vnfNicsMock = Mockito.mock(Map.class);
|
||||||
|
Mockito.when(vnfNicsMock.values()).thenReturn(vnfNics.values());
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = VnfTemplateUtils.getVnfNicsList(vnfNicsMock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateVnfNicsAllGood() {
|
||||||
|
VnfNic nic1 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic1.getDeviceId()).thenReturn(0L);
|
||||||
|
Mockito.when(nic1.isRequired()).thenReturn(true);
|
||||||
|
|
||||||
|
VnfNic nic2 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic2.getDeviceId()).thenReturn(1L);
|
||||||
|
Mockito.when(nic2.isRequired()).thenReturn(true);
|
||||||
|
|
||||||
|
VnfNic nic3 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic3.getDeviceId()).thenReturn(2L);
|
||||||
|
Mockito.when(nic3.isRequired()).thenReturn(false);
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = Arrays.asList(nic1, nic2, nic3);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateVnfNics(nicsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateVnfNicsStartWithNonzero() {
|
||||||
|
VnfNic nic1 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic1.getDeviceId()).thenReturn(1L);
|
||||||
|
|
||||||
|
VnfNic nic2 = Mockito.mock(VnfNic.class);
|
||||||
|
|
||||||
|
VnfNic nic3 = Mockito.mock(VnfNic.class);
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = Arrays.asList(nic1, nic2, nic3);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateVnfNics(nicsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateVnfNicsWithNonConstantDeviceIds() {
|
||||||
|
VnfNic nic1 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic1.getDeviceId()).thenReturn(0L);
|
||||||
|
Mockito.when(nic1.isRequired()).thenReturn(true);
|
||||||
|
|
||||||
|
VnfNic nic2 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic2.getDeviceId()).thenReturn(2L);
|
||||||
|
|
||||||
|
VnfNic nic3 = Mockito.mock(VnfNic.class);
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = Arrays.asList(nic1, nic2, nic3);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateVnfNics(nicsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateVnfNicsWithInvalidRequired() {
|
||||||
|
VnfNic nic1 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic1.getDeviceId()).thenReturn(0L);
|
||||||
|
Mockito.when(nic1.isRequired()).thenReturn(true);
|
||||||
|
|
||||||
|
VnfNic nic2 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic2.getDeviceId()).thenReturn(1L);
|
||||||
|
Mockito.when(nic2.isRequired()).thenReturn(false);
|
||||||
|
|
||||||
|
VnfNic nic3 = Mockito.mock(VnfNic.class);
|
||||||
|
Mockito.when(nic3.getDeviceId()).thenReturn(2L);
|
||||||
|
Mockito.when(nic3.isRequired()).thenReturn(true);
|
||||||
|
|
||||||
|
List<VnfNic> nicsList = Arrays.asList(nic1, nic2, nic3);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateVnfNics(nicsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateApiCommandParamsAllGood() {
|
||||||
|
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||||
|
RegisterVnfTemplateCmd cmd = Mockito.mock(RegisterVnfTemplateCmd.class);
|
||||||
|
Map<String, String> vnfDetails = Mockito.spy(new HashMap<>());
|
||||||
|
vnfDetails.put("username", "admin");
|
||||||
|
vnfDetails.put("password", "password");
|
||||||
|
vnfDetails.put("version", "4.19.0");
|
||||||
|
vnfDetails.put("vendor", "cloudstack");
|
||||||
|
Mockito.when(cmd.getVnfDetails()).thenReturn(vnfDetails);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateApiCommandParams(cmd, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateApiCommandParamsInvalidAccessMethods() {
|
||||||
|
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||||
|
Mockito.when(template.getTemplateType()).thenReturn(Storage.TemplateType.VNF);
|
||||||
|
UpdateVnfTemplateCmd cmd = Mockito.mock(UpdateVnfTemplateCmd.class);
|
||||||
|
Map<String, String> vnfDetails = Mockito.spy(new HashMap<>());
|
||||||
|
vnfDetails.put("access_methods", "invalid");
|
||||||
|
Mockito.when(cmd.getVnfDetails()).thenReturn(vnfDetails);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateApiCommandParams(cmd, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateApiCommandParamsInvalidAccessDetails() {
|
||||||
|
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||||
|
Mockito.when(template.getTemplateType()).thenReturn(Storage.TemplateType.VNF);
|
||||||
|
UpdateVnfTemplateCmd cmd = Mockito.mock(UpdateVnfTemplateCmd.class);
|
||||||
|
Map<String, String> vnfDetails = Mockito.spy(new HashMap<>());
|
||||||
|
vnfDetails.put("invalid", "value");
|
||||||
|
Mockito.when(cmd.getVnfDetails()).thenReturn(vnfDetails);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateApiCommandParams(cmd, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateApiCommandParamsInvalidTemplateType() {
|
||||||
|
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||||
|
Mockito.when(template.getTemplateType()).thenReturn(Storage.TemplateType.USER);
|
||||||
|
UpdateVnfTemplateCmd cmd = Mockito.mock(UpdateVnfTemplateCmd.class);
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateApiCommandParams(cmd, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateVnfCidrList() {
|
||||||
|
List<String> cidrList = new ArrayList<>();
|
||||||
|
cidrList.add("10.10.10.0/24");
|
||||||
|
VnfTemplateUtils.validateVnfCidrList(cidrList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateVnfCidrListWithEmptyList() {
|
||||||
|
List<String> cidrList = new ArrayList<>();
|
||||||
|
VnfTemplateUtils.validateVnfCidrList(cidrList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateVnfCidrListwithInvalidList() {
|
||||||
|
List<String> cidrList = new ArrayList<>();
|
||||||
|
cidrList.add("10.10.10.0/24");
|
||||||
|
cidrList.add("10.10.10.0/33");
|
||||||
|
VnfTemplateUtils.validateVnfCidrList(cidrList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ package com.cloud.template;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
|
||||||
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
|
||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
|
@ -29,6 +30,7 @@ import com.cloud.deploy.DeployDestination;
|
||||||
import com.cloud.exception.ResourceAllocationException;
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
import com.cloud.exception.StorageUnavailableException;
|
import com.cloud.exception.StorageUnavailableException;
|
||||||
import com.cloud.storage.DataStoreRole;
|
import com.cloud.storage.DataStoreRole;
|
||||||
|
import com.cloud.storage.Storage.TemplateType;
|
||||||
import com.cloud.storage.StoragePool;
|
import com.cloud.storage.StoragePool;
|
||||||
import com.cloud.storage.VMTemplateStoragePoolVO;
|
import com.cloud.storage.VMTemplateStoragePoolVO;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
|
|
@ -133,5 +135,7 @@ public interface TemplateManager {
|
||||||
public static final String MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT = "Message.RegisterPublicTemplate.Event";
|
public static final String MESSAGE_REGISTER_PUBLIC_TEMPLATE_EVENT = "Message.RegisterPublicTemplate.Event";
|
||||||
public static final String MESSAGE_RESET_TEMPLATE_PERMISSION_EVENT = "Message.ResetTemplatePermission.Event";
|
public static final String MESSAGE_RESET_TEMPLATE_PERMISSION_EVENT = "Message.ResetTemplatePermission.Event";
|
||||||
|
|
||||||
|
TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean isCrossZones);
|
||||||
|
|
||||||
List<DatadiskTO> getTemplateDisksOnImageStore(Long templateId, DataStoreRole role, String configurationId);
|
List<DatadiskTO> getTemplateDisksOnImageStore(Long templateId, DataStoreRole role, String configurationId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Lob;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.ResourceDetail;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "vnf_template_details")
|
||||||
|
public class VnfTemplateDetailVO implements ResourceDetail {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "id")
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column(name = "template_id")
|
||||||
|
private long resourceId;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Lob
|
||||||
|
@Column(name = "value", length = 65535)
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
@Column(name = "display")
|
||||||
|
private boolean display = true;
|
||||||
|
|
||||||
|
public VnfTemplateDetailVO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VnfTemplateDetailVO(long templateId, String name, String value, boolean display) {
|
||||||
|
this.resourceId = templateId;
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
this.display = display;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getResourceId() {
|
||||||
|
return resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDisplay() {
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceId(long resourceId) {
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.InternalIdentity;
|
||||||
|
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "vnf_template_nics")
|
||||||
|
public class VnfTemplateNicVO implements InternalIdentity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "id")
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Column(name = "template_id")
|
||||||
|
private long templateId;
|
||||||
|
|
||||||
|
@Column(name = "device_id")
|
||||||
|
private long deviceId;
|
||||||
|
|
||||||
|
@Column(name = "device_name")
|
||||||
|
private String deviceName;
|
||||||
|
|
||||||
|
@Column(name = "required")
|
||||||
|
private boolean required = true;
|
||||||
|
|
||||||
|
@Column(name = "management")
|
||||||
|
private boolean management = true;
|
||||||
|
|
||||||
|
@Column(name = "description")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public VnfTemplateNicVO() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VnfTemplateNicVO(long templateId, long deviceId, String deviceName, boolean required, boolean management, String description) {
|
||||||
|
this.templateId = templateId;
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.deviceName = deviceName;
|
||||||
|
this.required = required;
|
||||||
|
this.management = management;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Template %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "templateId", "deviceId", "required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTemplateId() {
|
||||||
|
return templateId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDeviceId() {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceName() {
|
||||||
|
return deviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRequired() {
|
||||||
|
return required;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isManagement() {
|
||||||
|
return management;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDao;
|
||||||
|
|
||||||
|
public interface VnfTemplateDetailsDao extends GenericDao<VnfTemplateDetailVO, Long>, ResourceDetailsDao<VnfTemplateDetailVO> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.resourcedetail.ResourceDetailsDaoBase;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class VnfTemplateDetailsDaoImpl extends ResourceDetailsDaoBase<VnfTemplateDetailVO> implements VnfTemplateDetailsDao {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addDetail(long resourceId, String key, String value, boolean display) {
|
||||||
|
super.addDetail(new VnfTemplateDetailVO(resourceId, key, value, display));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.utils.db.GenericDao;
|
||||||
|
|
||||||
|
public interface VnfTemplateNicDao extends GenericDao<VnfTemplateNicVO, Long> {
|
||||||
|
|
||||||
|
List<VnfTemplateNicVO> listByTemplateId(long templateId);
|
||||||
|
|
||||||
|
void deleteByTemplateId(long templateId);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.utils.db.GenericDaoBase;
|
||||||
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
|
|
||||||
|
public class VnfTemplateNicDaoImpl extends GenericDaoBase<VnfTemplateNicVO, Long> implements VnfTemplateNicDao {
|
||||||
|
|
||||||
|
protected SearchBuilder<VnfTemplateNicVO> TemplateSearch;
|
||||||
|
|
||||||
|
public VnfTemplateNicDaoImpl() {
|
||||||
|
TemplateSearch = createSearchBuilder();
|
||||||
|
TemplateSearch.and("templateId", TemplateSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
|
||||||
|
TemplateSearch.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<VnfTemplateNicVO> listByTemplateId(long templateId) {
|
||||||
|
SearchCriteria<VnfTemplateNicVO> sc = TemplateSearch.create();
|
||||||
|
sc.setParameters("templateId", templateId);
|
||||||
|
return listBy(sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteByTemplateId(long templateId) {
|
||||||
|
SearchCriteria<VnfTemplateNicVO> sc = TemplateSearch.create();
|
||||||
|
sc.setParameters("templateId", templateId);
|
||||||
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
txn.start();
|
||||||
|
remove(sc);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -333,6 +333,8 @@ public class NicVO implements Nic {
|
||||||
.append("-")
|
.append("-")
|
||||||
.append(instanceId)
|
.append(instanceId)
|
||||||
.append("-")
|
.append("-")
|
||||||
|
.append(deviceId)
|
||||||
|
.append("-")
|
||||||
.append(reservationId)
|
.append(reservationId)
|
||||||
.append("-")
|
.append("-")
|
||||||
.append(iPv4Address)
|
.append(iPv4Address)
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,8 @@
|
||||||
<bean id="PassphraseDaoImpl" class="org.apache.cloudstack.secret.dao.PassphraseDaoImpl" />
|
<bean id="PassphraseDaoImpl" class="org.apache.cloudstack.secret.dao.PassphraseDaoImpl" />
|
||||||
<bean id="VMScheduleDaoImpl" class="org.apache.cloudstack.vm.schedule.dao.VMScheduleDaoImpl" />
|
<bean id="VMScheduleDaoImpl" class="org.apache.cloudstack.vm.schedule.dao.VMScheduleDaoImpl" />
|
||||||
<bean id="VMScheduledJobDaoImpl" class="org.apache.cloudstack.vm.schedule.dao.VMScheduledJobDaoImpl" />
|
<bean id="VMScheduledJobDaoImpl" class="org.apache.cloudstack.vm.schedule.dao.VMScheduledJobDaoImpl" />
|
||||||
|
<bean id="vnfTemplateDetailsDaoImpl" class="com.cloud.storage.dao.VnfTemplateDetailsDaoImpl" />
|
||||||
|
<bean id="vnfTemplateNicDaoImpl" class="com.cloud.storage.dao.VnfTemplateNicDaoImpl" />
|
||||||
<bean id="ClusterDrsPlanDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanDaoImpl" />
|
<bean id="ClusterDrsPlanDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanDaoImpl" />
|
||||||
<bean id="ClusterDrsPlanDetailsDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanMigrationDaoImpl" />
|
<bean id="ClusterDrsPlanDetailsDaoImpl" class="org.apache.cloudstack.cluster.dao.ClusterDrsPlanMigrationDaoImpl" />
|
||||||
</beans>
|
</beans>
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,230 @@ ALTER TABLE `cloud`.`kubernetes_cluster` MODIFY COLUMN `kubernetes_version_id` b
|
||||||
-- Set removed state for all removed accounts
|
-- Set removed state for all removed accounts
|
||||||
UPDATE `cloud`.`account` SET state='removed' WHERE `removed` IS NOT NULL;
|
UPDATE `cloud`.`account` SET state='removed' WHERE `removed` IS NOT NULL;
|
||||||
|
|
||||||
|
|
||||||
|
-- New tables for VNF
|
||||||
|
CREATE TABLE IF NOT EXISTS `cloud`.`vnf_template_nics` (
|
||||||
|
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`template_id` bigint unsigned NOT NULL COMMENT 'id of the VNF template',
|
||||||
|
`device_id` bigint unsigned NOT NULL COMMENT 'Device id of the NIC when plugged into the VNF appliances',
|
||||||
|
`device_name` varchar(1024) NOT NULL COMMENT 'Name of the NIC',
|
||||||
|
`required` tinyint NOT NULL DEFAULT '1' COMMENT 'True if the NIC is required. False if optional',
|
||||||
|
`management` tinyint NOT NULL DEFAULT '1' COMMENT 'True if the NIC is a management interface',
|
||||||
|
`description` varchar(1024) COMMENT 'Description of the NIC',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_template_id_device_id` (`template_id`, `device_id`),
|
||||||
|
KEY `fk_vnf_template_nics__template_id` (`template_id`),
|
||||||
|
CONSTRAINT `fk_vnf_template_nics__template_id` FOREIGN KEY (`template_id`) REFERENCES `vm_template` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `cloud`.`vnf_template_details` (
|
||||||
|
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||||
|
`template_id` bigint unsigned NOT NULL COMMENT 'id of the VNF template',
|
||||||
|
`name` varchar(255) NOT NULL,
|
||||||
|
`value` varchar(1024) NOT NULL,
|
||||||
|
`display` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'True if the detail can be displayed to the end user',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `fk_vnf_template_details__template_id` (`template_id`),
|
||||||
|
CONSTRAINT `fk_vnf_template_details__template_id` FOREIGN KEY (`template_id`) REFERENCES `vm_template` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
DROP VIEW IF EXISTS `cloud`.`user_vm_view`;
|
||||||
|
CREATE
|
||||||
|
VIEW `user_vm_view` AS
|
||||||
|
SELECT
|
||||||
|
`vm_instance`.`id` AS `id`,
|
||||||
|
`vm_instance`.`name` AS `name`,
|
||||||
|
`user_vm`.`display_name` AS `display_name`,
|
||||||
|
`user_vm`.`user_data` AS `user_data`,
|
||||||
|
`account`.`id` AS `account_id`,
|
||||||
|
`account`.`uuid` AS `account_uuid`,
|
||||||
|
`account`.`account_name` AS `account_name`,
|
||||||
|
`account`.`type` AS `account_type`,
|
||||||
|
`domain`.`id` AS `domain_id`,
|
||||||
|
`domain`.`uuid` AS `domain_uuid`,
|
||||||
|
`domain`.`name` AS `domain_name`,
|
||||||
|
`domain`.`path` AS `domain_path`,
|
||||||
|
`projects`.`id` AS `project_id`,
|
||||||
|
`projects`.`uuid` AS `project_uuid`,
|
||||||
|
`projects`.`name` AS `project_name`,
|
||||||
|
`instance_group`.`id` AS `instance_group_id`,
|
||||||
|
`instance_group`.`uuid` AS `instance_group_uuid`,
|
||||||
|
`instance_group`.`name` AS `instance_group_name`,
|
||||||
|
`vm_instance`.`uuid` AS `uuid`,
|
||||||
|
`vm_instance`.`user_id` AS `user_id`,
|
||||||
|
`vm_instance`.`last_host_id` AS `last_host_id`,
|
||||||
|
`vm_instance`.`vm_type` AS `type`,
|
||||||
|
`vm_instance`.`limit_cpu_use` AS `limit_cpu_use`,
|
||||||
|
`vm_instance`.`created` AS `created`,
|
||||||
|
`vm_instance`.`state` AS `state`,
|
||||||
|
`vm_instance`.`update_time` AS `update_time`,
|
||||||
|
`vm_instance`.`removed` AS `removed`,
|
||||||
|
`vm_instance`.`ha_enabled` AS `ha_enabled`,
|
||||||
|
`vm_instance`.`hypervisor_type` AS `hypervisor_type`,
|
||||||
|
`vm_instance`.`instance_name` AS `instance_name`,
|
||||||
|
`vm_instance`.`guest_os_id` AS `guest_os_id`,
|
||||||
|
`vm_instance`.`display_vm` AS `display_vm`,
|
||||||
|
`guest_os`.`uuid` AS `guest_os_uuid`,
|
||||||
|
`vm_instance`.`pod_id` AS `pod_id`,
|
||||||
|
`host_pod_ref`.`uuid` AS `pod_uuid`,
|
||||||
|
`vm_instance`.`private_ip_address` AS `private_ip_address`,
|
||||||
|
`vm_instance`.`private_mac_address` AS `private_mac_address`,
|
||||||
|
`vm_instance`.`vm_type` AS `vm_type`,
|
||||||
|
`data_center`.`id` AS `data_center_id`,
|
||||||
|
`data_center`.`uuid` AS `data_center_uuid`,
|
||||||
|
`data_center`.`name` AS `data_center_name`,
|
||||||
|
`data_center`.`is_security_group_enabled` AS `security_group_enabled`,
|
||||||
|
`data_center`.`networktype` AS `data_center_network_type`,
|
||||||
|
`host`.`id` AS `host_id`,
|
||||||
|
`host`.`uuid` AS `host_uuid`,
|
||||||
|
`host`.`name` AS `host_name`,
|
||||||
|
`host`.`cluster_id` AS `cluster_id`,
|
||||||
|
`host`.`status` AS `host_status`,
|
||||||
|
`host`.`resource_state` AS `host_resource_state`,
|
||||||
|
`vm_template`.`id` AS `template_id`,
|
||||||
|
`vm_template`.`uuid` AS `template_uuid`,
|
||||||
|
`vm_template`.`name` AS `template_name`,
|
||||||
|
`vm_template`.`type` AS `template_type`,
|
||||||
|
`vm_template`.`display_text` AS `template_display_text`,
|
||||||
|
`vm_template`.`enable_password` AS `password_enabled`,
|
||||||
|
`iso`.`id` AS `iso_id`,
|
||||||
|
`iso`.`uuid` AS `iso_uuid`,
|
||||||
|
`iso`.`name` AS `iso_name`,
|
||||||
|
`iso`.`display_text` AS `iso_display_text`,
|
||||||
|
`service_offering`.`id` AS `service_offering_id`,
|
||||||
|
`service_offering`.`uuid` AS `service_offering_uuid`,
|
||||||
|
`disk_offering`.`uuid` AS `disk_offering_uuid`,
|
||||||
|
`disk_offering`.`id` AS `disk_offering_id`,
|
||||||
|
(CASE
|
||||||
|
WHEN ISNULL(`service_offering`.`cpu`) THEN `custom_cpu`.`value`
|
||||||
|
ELSE `service_offering`.`cpu`
|
||||||
|
END) AS `cpu`,
|
||||||
|
(CASE
|
||||||
|
WHEN ISNULL(`service_offering`.`speed`) THEN `custom_speed`.`value`
|
||||||
|
ELSE `service_offering`.`speed`
|
||||||
|
END) AS `speed`,
|
||||||
|
(CASE
|
||||||
|
WHEN ISNULL(`service_offering`.`ram_size`) THEN `custom_ram_size`.`value`
|
||||||
|
ELSE `service_offering`.`ram_size`
|
||||||
|
END) AS `ram_size`,
|
||||||
|
`backup_offering`.`uuid` AS `backup_offering_uuid`,
|
||||||
|
`backup_offering`.`id` AS `backup_offering_id`,
|
||||||
|
`service_offering`.`name` AS `service_offering_name`,
|
||||||
|
`disk_offering`.`name` AS `disk_offering_name`,
|
||||||
|
`backup_offering`.`name` AS `backup_offering_name`,
|
||||||
|
`storage_pool`.`id` AS `pool_id`,
|
||||||
|
`storage_pool`.`uuid` AS `pool_uuid`,
|
||||||
|
`storage_pool`.`pool_type` AS `pool_type`,
|
||||||
|
`volumes`.`id` AS `volume_id`,
|
||||||
|
`volumes`.`uuid` AS `volume_uuid`,
|
||||||
|
`volumes`.`device_id` AS `volume_device_id`,
|
||||||
|
`volumes`.`volume_type` AS `volume_type`,
|
||||||
|
`security_group`.`id` AS `security_group_id`,
|
||||||
|
`security_group`.`uuid` AS `security_group_uuid`,
|
||||||
|
`security_group`.`name` AS `security_group_name`,
|
||||||
|
`security_group`.`description` AS `security_group_description`,
|
||||||
|
`nics`.`id` AS `nic_id`,
|
||||||
|
`nics`.`uuid` AS `nic_uuid`,
|
||||||
|
`nics`.`device_id` AS `nic_device_id`,
|
||||||
|
`nics`.`network_id` AS `network_id`,
|
||||||
|
`nics`.`ip4_address` AS `ip_address`,
|
||||||
|
`nics`.`ip6_address` AS `ip6_address`,
|
||||||
|
`nics`.`ip6_gateway` AS `ip6_gateway`,
|
||||||
|
`nics`.`ip6_cidr` AS `ip6_cidr`,
|
||||||
|
`nics`.`default_nic` AS `is_default_nic`,
|
||||||
|
`nics`.`gateway` AS `gateway`,
|
||||||
|
`nics`.`netmask` AS `netmask`,
|
||||||
|
`nics`.`mac_address` AS `mac_address`,
|
||||||
|
`nics`.`broadcast_uri` AS `broadcast_uri`,
|
||||||
|
`nics`.`isolation_uri` AS `isolation_uri`,
|
||||||
|
`vpc`.`id` AS `vpc_id`,
|
||||||
|
`vpc`.`uuid` AS `vpc_uuid`,
|
||||||
|
`networks`.`uuid` AS `network_uuid`,
|
||||||
|
`networks`.`name` AS `network_name`,
|
||||||
|
`networks`.`traffic_type` AS `traffic_type`,
|
||||||
|
`networks`.`guest_type` AS `guest_type`,
|
||||||
|
`user_ip_address`.`id` AS `public_ip_id`,
|
||||||
|
`user_ip_address`.`uuid` AS `public_ip_uuid`,
|
||||||
|
`user_ip_address`.`public_ip_address` AS `public_ip_address`,
|
||||||
|
`ssh_details`.`value` AS `keypair_names`,
|
||||||
|
`resource_tags`.`id` AS `tag_id`,
|
||||||
|
`resource_tags`.`uuid` AS `tag_uuid`,
|
||||||
|
`resource_tags`.`key` AS `tag_key`,
|
||||||
|
`resource_tags`.`value` AS `tag_value`,
|
||||||
|
`resource_tags`.`domain_id` AS `tag_domain_id`,
|
||||||
|
`domain`.`uuid` AS `tag_domain_uuid`,
|
||||||
|
`domain`.`name` AS `tag_domain_name`,
|
||||||
|
`resource_tags`.`account_id` AS `tag_account_id`,
|
||||||
|
`account`.`account_name` AS `tag_account_name`,
|
||||||
|
`resource_tags`.`resource_id` AS `tag_resource_id`,
|
||||||
|
`resource_tags`.`resource_uuid` AS `tag_resource_uuid`,
|
||||||
|
`resource_tags`.`resource_type` AS `tag_resource_type`,
|
||||||
|
`resource_tags`.`customer` AS `tag_customer`,
|
||||||
|
`async_job`.`id` AS `job_id`,
|
||||||
|
`async_job`.`uuid` AS `job_uuid`,
|
||||||
|
`async_job`.`job_status` AS `job_status`,
|
||||||
|
`async_job`.`account_id` AS `job_account_id`,
|
||||||
|
`affinity_group`.`id` AS `affinity_group_id`,
|
||||||
|
`affinity_group`.`uuid` AS `affinity_group_uuid`,
|
||||||
|
`affinity_group`.`name` AS `affinity_group_name`,
|
||||||
|
`affinity_group`.`description` AS `affinity_group_description`,
|
||||||
|
`autoscale_vmgroups`.`id` AS `autoscale_vmgroup_id`,
|
||||||
|
`autoscale_vmgroups`.`uuid` AS `autoscale_vmgroup_uuid`,
|
||||||
|
`autoscale_vmgroups`.`name` AS `autoscale_vmgroup_name`,
|
||||||
|
`vm_instance`.`dynamically_scalable` AS `dynamically_scalable`,
|
||||||
|
`user_data`.`id` AS `user_data_id`,
|
||||||
|
`user_data`.`uuid` AS `user_data_uuid`,
|
||||||
|
`user_data`.`name` AS `user_data_name`,
|
||||||
|
`user_vm`.`user_data_details` AS `user_data_details`,
|
||||||
|
`vm_template`.`user_data_link_policy` AS `user_data_policy`
|
||||||
|
FROM
|
||||||
|
(((((((((((((((((((((((((((((((((((`user_vm`
|
||||||
|
JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`)
|
||||||
|
AND ISNULL(`vm_instance`.`removed`))))
|
||||||
|
JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`)))
|
||||||
|
JOIN `domain` ON ((`vm_instance`.`domain_id` = `domain`.`id`)))
|
||||||
|
LEFT JOIN `guest_os` ON ((`vm_instance`.`guest_os_id` = `guest_os`.`id`)))
|
||||||
|
LEFT JOIN `host_pod_ref` ON ((`vm_instance`.`pod_id` = `host_pod_ref`.`id`)))
|
||||||
|
LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`)))
|
||||||
|
LEFT JOIN `instance_group_vm_map` ON ((`vm_instance`.`id` = `instance_group_vm_map`.`instance_id`)))
|
||||||
|
LEFT JOIN `instance_group` ON ((`instance_group_vm_map`.`group_id` = `instance_group`.`id`)))
|
||||||
|
LEFT JOIN `data_center` ON ((`vm_instance`.`data_center_id` = `data_center`.`id`)))
|
||||||
|
LEFT JOIN `host` ON ((`vm_instance`.`host_id` = `host`.`id`)))
|
||||||
|
LEFT JOIN `vm_template` ON ((`vm_instance`.`vm_template_id` = `vm_template`.`id`)))
|
||||||
|
LEFT JOIN `vm_template` `iso` ON ((`iso`.`id` = `user_vm`.`iso_id`)))
|
||||||
|
LEFT JOIN `volumes` ON ((`vm_instance`.`id` = `volumes`.`instance_id`)))
|
||||||
|
LEFT JOIN `service_offering` ON ((`vm_instance`.`service_offering_id` = `service_offering`.`id`)))
|
||||||
|
LEFT JOIN `disk_offering` `svc_disk_offering` ON ((`volumes`.`disk_offering_id` = `svc_disk_offering`.`id`)))
|
||||||
|
LEFT JOIN `disk_offering` ON ((`volumes`.`disk_offering_id` = `disk_offering`.`id`)))
|
||||||
|
LEFT JOIN `backup_offering` ON ((`vm_instance`.`backup_offering_id` = `backup_offering`.`id`)))
|
||||||
|
LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`)))
|
||||||
|
LEFT JOIN `security_group_vm_map` ON ((`vm_instance`.`id` = `security_group_vm_map`.`instance_id`)))
|
||||||
|
LEFT JOIN `security_group` ON ((`security_group_vm_map`.`security_group_id` = `security_group`.`id`)))
|
||||||
|
LEFT JOIN `user_data` ON ((`user_data`.`id` = `user_vm`.`user_data_id`)))
|
||||||
|
LEFT JOIN `nics` ON (((`vm_instance`.`id` = `nics`.`instance_id`)
|
||||||
|
AND ISNULL(`nics`.`removed`))))
|
||||||
|
LEFT JOIN `networks` ON ((`nics`.`network_id` = `networks`.`id`)))
|
||||||
|
LEFT JOIN `vpc` ON (((`networks`.`vpc_id` = `vpc`.`id`)
|
||||||
|
AND ISNULL(`vpc`.`removed`))))
|
||||||
|
LEFT JOIN `user_ip_address` ON ((`user_ip_address`.`vm_id` = `vm_instance`.`id`)))
|
||||||
|
LEFT JOIN `user_vm_details` `ssh_details` ON (((`ssh_details`.`vm_id` = `vm_instance`.`id`)
|
||||||
|
AND (`ssh_details`.`name` = 'SSH.KeyPairNames'))))
|
||||||
|
LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`)
|
||||||
|
AND (`resource_tags`.`resource_type` = 'UserVm'))))
|
||||||
|
LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`)
|
||||||
|
AND (`async_job`.`instance_type` = 'VirtualMachine')
|
||||||
|
AND (`async_job`.`job_status` = 0))))
|
||||||
|
LEFT JOIN `affinity_group_vm_map` ON ((`vm_instance`.`id` = `affinity_group_vm_map`.`instance_id`)))
|
||||||
|
LEFT JOIN `affinity_group` ON ((`affinity_group_vm_map`.`affinity_group_id` = `affinity_group`.`id`)))
|
||||||
|
LEFT JOIN `autoscale_vmgroup_vm_map` ON ((`autoscale_vmgroup_vm_map`.`instance_id` = `vm_instance`.`id`)))
|
||||||
|
LEFT JOIN `autoscale_vmgroups` ON ((`autoscale_vmgroup_vm_map`.`vmgroup_id` = `autoscale_vmgroups`.`id`)))
|
||||||
|
LEFT JOIN `user_vm_details` `custom_cpu` ON (((`custom_cpu`.`vm_id` = `vm_instance`.`id`)
|
||||||
|
AND (`custom_cpu`.`name` = 'CpuNumber'))))
|
||||||
|
LEFT JOIN `user_vm_details` `custom_speed` ON (((`custom_speed`.`vm_id` = `vm_instance`.`id`)
|
||||||
|
AND (`custom_speed`.`name` = 'CpuSpeed'))))
|
||||||
|
LEFT JOIN `user_vm_details` `custom_ram_size` ON (((`custom_ram_size`.`vm_id` = `vm_instance`.`id`)
|
||||||
|
AND (`custom_ram_size`.`name` = 'memory'))));
|
||||||
|
|
||||||
-- Add tables for Cluster DRS
|
-- Add tables for Cluster DRS
|
||||||
DROP TABLE IF EXISTS `cloud`.`cluster_drs_plan`;
|
DROP TABLE IF EXISTS `cloud`.`cluster_drs_plan`;
|
||||||
CREATE TABLE `cloud`.`cluster_drs_plan` (
|
CREATE TABLE `cloud`.`cluster_drs_plan` (
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class VnfTemplateDetailVOTest {
|
||||||
|
|
||||||
|
static long templateId = 100L;
|
||||||
|
static String name = "key1";
|
||||||
|
static String value = "value1";
|
||||||
|
static boolean display = true;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVnfTemplateNicVOProperties() {
|
||||||
|
VnfTemplateDetailVO detailVO = new VnfTemplateDetailVO(templateId, name, value, display);
|
||||||
|
|
||||||
|
Assert.assertEquals(templateId, detailVO.getResourceId());
|
||||||
|
Assert.assertEquals(name, detailVO.getName());
|
||||||
|
Assert.assertEquals(value, detailVO.getValue());
|
||||||
|
Assert.assertEquals(display, detailVO.isDisplay());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class VnfTemplateNicVOTest {
|
||||||
|
|
||||||
|
static long templateId = 100L;
|
||||||
|
static long deviceId = 0L;
|
||||||
|
static String deviceName = "eth0";
|
||||||
|
static boolean required = true;
|
||||||
|
static boolean management = false;
|
||||||
|
static String description = "description of vnf nic";
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVnfTemplateNicVOProperties() {
|
||||||
|
VnfTemplateNicVO nicVO = new VnfTemplateNicVO(templateId, deviceId, deviceName, required, management, description);
|
||||||
|
|
||||||
|
Assert.assertEquals(templateId, nicVO.getTemplateId());
|
||||||
|
Assert.assertEquals(deviceId, nicVO.getDeviceId());
|
||||||
|
Assert.assertEquals(deviceName, nicVO.getDeviceName());
|
||||||
|
Assert.assertEquals(required, nicVO.isRequired());
|
||||||
|
Assert.assertEquals(management, nicVO.isManagement());
|
||||||
|
Assert.assertEquals(description, nicVO.getDescription());
|
||||||
|
|
||||||
|
String expected = String.format("Template {\"deviceId\":%d,\"id\":0,\"required\":%s,\"templateId\":%d}", deviceId, required, templateId);
|
||||||
|
Assert.assertEquals(expected, nicVO.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package com.cloud.storage.dao;
|
||||||
|
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class VnfTemplateNicDaoImplTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
SearchBuilder<VnfTemplateNicVO> searchBuilderVnfTemplateNicVOMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
SearchCriteria<VnfTemplateNicVO> searchCriteriaVnfTemplateNicVOMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
List<VnfTemplateNicVO> listVnfTemplateNicVOMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TransactionLegacy transactionMock;
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
VnfTemplateNicDaoImpl vnfTemplateNicDaoImplSpy;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
vnfTemplateNicDaoImplSpy.TemplateSearch = searchBuilderVnfTemplateNicVOMock;
|
||||||
|
Mockito.doReturn(searchCriteriaVnfTemplateNicVOMock).when(searchBuilderVnfTemplateNicVOMock).create();
|
||||||
|
Mockito.doNothing().when(searchCriteriaVnfTemplateNicVOMock).setParameters(Mockito.anyString(), Mockito.any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListByTemplateId() {
|
||||||
|
Mockito.doReturn(listVnfTemplateNicVOMock).when(vnfTemplateNicDaoImplSpy).listBy(Mockito.any(SearchCriteria.class));
|
||||||
|
long templateId = 100L;
|
||||||
|
|
||||||
|
List<VnfTemplateNicVO> result = vnfTemplateNicDaoImplSpy.listByTemplateId(templateId);
|
||||||
|
|
||||||
|
Assert.assertEquals(listVnfTemplateNicVOMock, result);
|
||||||
|
Mockito.verify(searchCriteriaVnfTemplateNicVOMock).setParameters("templateId", templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteByTemplateId() {
|
||||||
|
Mockito.doReturn(0).when(vnfTemplateNicDaoImplSpy).remove(searchCriteriaVnfTemplateNicVOMock);
|
||||||
|
long templateId = 100L;
|
||||||
|
|
||||||
|
try (MockedStatic<TransactionLegacy> ignore = Mockito.mockStatic(TransactionLegacy.class)) {
|
||||||
|
Mockito.when(TransactionLegacy.currentTxn()).thenReturn(transactionMock);
|
||||||
|
Mockito.doNothing().when(transactionMock).start();
|
||||||
|
Mockito.doReturn(true).when(transactionMock).commit();
|
||||||
|
|
||||||
|
vnfTemplateNicDaoImplSpy.deleteByTemplateId(templateId);
|
||||||
|
|
||||||
|
Mockito.verify(transactionMock, Mockito.times(1)).start();
|
||||||
|
Mockito.verify(vnfTemplateNicDaoImplSpy, Mockito.times(1)).remove(searchCriteriaVnfTemplateNicVOMock);
|
||||||
|
Mockito.verify(transactionMock, Mockito.times(1)).commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1533,6 +1533,10 @@ public class ApiDBUtils {
|
||||||
return s_ipAddressDao.findByAssociatedVmId(vmId);
|
return s_ipAddressDao.findByAssociatedVmId(vmId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IpAddress findIpByAssociatedVmIdAndNetworkId(long vmId, long networkId) {
|
||||||
|
return s_ipAddressDao.findByVmIdAndNetworkId(networkId, vmId);
|
||||||
|
}
|
||||||
|
|
||||||
public static String getHaTag() {
|
public static String getHaTag() {
|
||||||
return s_haMgr.getHaTag();
|
return s_haMgr.getHaTag();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ import org.apache.cloudstack.api.command.user.snapshot.CopySnapshotCmd;
|
||||||
import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
|
import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
|
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.ListVnfTemplatesCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
|
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd;
|
import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd;
|
||||||
|
|
@ -222,6 +223,7 @@ import com.cloud.ha.HighAvailabilityManager;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.network.RouterHealthCheckResult;
|
import com.cloud.network.RouterHealthCheckResult;
|
||||||
|
import com.cloud.network.VNF;
|
||||||
import com.cloud.network.VpcVirtualNetworkApplianceService;
|
import com.cloud.network.VpcVirtualNetworkApplianceService;
|
||||||
import com.cloud.network.dao.RouterHealthCheckResultDao;
|
import com.cloud.network.dao.RouterHealthCheckResultDao;
|
||||||
import com.cloud.network.dao.RouterHealthCheckResultVO;
|
import com.cloud.network.dao.RouterHealthCheckResultVO;
|
||||||
|
|
@ -1315,6 +1317,15 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
userVmSearchBuilder.join("autoScaleVmGroup", autoScaleMapSearch, autoScaleMapSearch.entity().getInstanceId(), userVmSearchBuilder.entity().getId(), JoinBuilder.JoinType.INNER);
|
userVmSearchBuilder.join("autoScaleVmGroup", autoScaleMapSearch, autoScaleMapSearch.entity().getInstanceId(), userVmSearchBuilder.entity().getId(), JoinBuilder.JoinType.INNER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Boolean isVnf = cmd.getVnf();
|
||||||
|
if (isVnf != null) {
|
||||||
|
SearchBuilder<VMTemplateVO> templateSearch = _templateDao.createSearchBuilder();
|
||||||
|
templateSearch.and("templateTypeEQ", templateSearch.entity().getTemplateType(), Op.EQ);
|
||||||
|
templateSearch.and("templateTypeNEQ", templateSearch.entity().getTemplateType(), Op.NEQ);
|
||||||
|
|
||||||
|
userVmSearchBuilder.join("vmTemplate", templateSearch, templateSearch.entity().getId(), userVmSearchBuilder.entity().getTemplateId(), JoinBuilder.JoinType.INNER);
|
||||||
|
}
|
||||||
|
|
||||||
SearchCriteria<UserVmVO> userVmSearchCriteria = userVmSearchBuilder.create();
|
SearchCriteria<UserVmVO> userVmSearchCriteria = userVmSearchBuilder.create();
|
||||||
accountMgr.buildACLSearchCriteria(userVmSearchCriteria, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
accountMgr.buildACLSearchCriteria(userVmSearchCriteria, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||||
|
|
||||||
|
|
@ -1423,6 +1434,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
userVmSearchCriteria.setJoinParameters("autoScaleVmGroup", "autoScaleVmGroupId", autoScaleVmGroupId);
|
userVmSearchCriteria.setJoinParameters("autoScaleVmGroup", "autoScaleVmGroupId", autoScaleVmGroupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isVnf != null) {
|
||||||
|
if (isVnf) {
|
||||||
|
userVmSearchCriteria.setJoinParameters("vmTemplate", "templateTypeEQ", TemplateType.VNF);
|
||||||
|
} else {
|
||||||
|
userVmSearchCriteria.setJoinParameters("vmTemplate", "templateTypeNEQ", TemplateType.VNF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isRootAdmin) {
|
if (isRootAdmin) {
|
||||||
if (podId != null) {
|
if (podId != null) {
|
||||||
userVmSearchCriteria.setParameters("podId", podId);
|
userVmSearchCriteria.setParameters("podId", podId);
|
||||||
|
|
@ -3791,13 +3810,24 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
boolean showDomr = ((templateFilter != TemplateFilter.selfexecutable) && (templateFilter != TemplateFilter.featured));
|
boolean showDomr = ((templateFilter != TemplateFilter.selfexecutable) && (templateFilter != TemplateFilter.featured));
|
||||||
HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor());
|
HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor());
|
||||||
|
|
||||||
|
String templateType = cmd.getTemplateType();
|
||||||
|
if (cmd instanceof ListVnfTemplatesCmd) {
|
||||||
|
if (templateType == null) {
|
||||||
|
templateType = TemplateType.VNF.name();
|
||||||
|
} else if (!TemplateType.VNF.name().equals(templateType)) {
|
||||||
|
throw new InvalidParameterValueException("Template type must be VNF when list VNF templates");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Boolean isVnf = cmd.getVnf();
|
||||||
|
|
||||||
return searchForTemplatesInternal(id, cmd.getTemplateName(), cmd.getKeyword(), templateFilter, false, null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType,
|
return searchForTemplatesInternal(id, cmd.getTemplateName(), cmd.getKeyword(), templateFilter, false, null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), hypervisorType,
|
||||||
showDomr, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl, cmd.getIds(), parentTemplateId, cmd.getShowUnique());
|
showDomr, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedTmpl, cmd.getIds(), parentTemplateId, cmd.getShowUnique(), templateType, isVnf);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<List<TemplateJoinVO>, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword, TemplateFilter templateFilter, boolean isIso, Boolean bootable, Long pageSize,
|
private Pair<List<TemplateJoinVO>, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword, TemplateFilter templateFilter, boolean isIso, Boolean bootable, Long pageSize,
|
||||||
Long startIndex, Long zoneId, HypervisorType hyperType, boolean showDomr, boolean onlyReady, List<Account> permittedAccounts, Account caller,
|
Long startIndex, Long zoneId, HypervisorType hyperType, boolean showDomr, boolean onlyReady, List<Account> permittedAccounts, Account caller,
|
||||||
ListProjectResourcesCriteria listProjectResourcesCriteria, Map<String, String> tags, boolean showRemovedTmpl, List<Long> ids, Long parentTemplateId, Boolean showUnique) {
|
ListProjectResourcesCriteria listProjectResourcesCriteria, Map<String, String> tags, boolean showRemovedTmpl, List<Long> ids, Long parentTemplateId, Boolean showUnique, String templateType,
|
||||||
|
Boolean isVnf) {
|
||||||
|
|
||||||
// check if zone is configured, if not, just return empty list
|
// check if zone is configured, if not, just return empty list
|
||||||
List<HypervisorType> hypers = null;
|
List<HypervisorType> hypers = null;
|
||||||
|
|
@ -3964,7 +3994,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
applyPublicTemplateSharingRestrictions(sc, caller);
|
applyPublicTemplateSharingRestrictions(sc, caller);
|
||||||
|
|
||||||
return templateChecks(isIso, hypers, tags, name, keyword, hyperType, onlyReady, bootable, zoneId, showDomr, caller,
|
return templateChecks(isIso, hypers, tags, name, keyword, hyperType, onlyReady, bootable, zoneId, showDomr, caller,
|
||||||
showRemovedTmpl, parentTemplateId, showUnique, searchFilter, sc);
|
showRemovedTmpl, parentTemplateId, showUnique, templateType, isVnf, searchFilter, sc);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4019,7 +4049,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
|
|
||||||
private Pair<List<TemplateJoinVO>, Integer> templateChecks(boolean isIso, List<HypervisorType> hypers, Map<String, String> tags, String name, String keyword,
|
private Pair<List<TemplateJoinVO>, Integer> templateChecks(boolean isIso, List<HypervisorType> hypers, Map<String, String> tags, String name, String keyword,
|
||||||
HypervisorType hyperType, boolean onlyReady, Boolean bootable, Long zoneId, boolean showDomr, Account caller,
|
HypervisorType hyperType, boolean onlyReady, Boolean bootable, Long zoneId, boolean showDomr, Account caller,
|
||||||
boolean showRemovedTmpl, Long parentTemplateId, Boolean showUnique,
|
boolean showRemovedTmpl, Long parentTemplateId, Boolean showUnique, String templateType, Boolean isVnf,
|
||||||
Filter searchFilter, SearchCriteria<TemplateJoinVO> sc) {
|
Filter searchFilter, SearchCriteria<TemplateJoinVO> sc) {
|
||||||
if (!isIso) {
|
if (!isIso) {
|
||||||
// add hypervisor criteria for template case
|
// add hypervisor criteria for template case
|
||||||
|
|
@ -4101,6 +4131,18 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
sc.addAnd("parentTemplateId", SearchCriteria.Op.EQ, parentTemplateId);
|
sc.addAnd("parentTemplateId", SearchCriteria.Op.EQ, parentTemplateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (templateType != null) {
|
||||||
|
sc.addAnd("templateType", SearchCriteria.Op.EQ, templateType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVnf != null) {
|
||||||
|
if (isVnf) {
|
||||||
|
sc.addAnd("templateType", SearchCriteria.Op.EQ, TemplateType.VNF);
|
||||||
|
} else {
|
||||||
|
sc.addAnd("templateType", SearchCriteria.Op.NEQ, TemplateType.VNF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// don't return removed template, this should not be needed since we
|
// don't return removed template, this should not be needed since we
|
||||||
// changed annotation for removed field in TemplateJoinVO.
|
// changed annotation for removed field in TemplateJoinVO.
|
||||||
// sc.addAnd("removed", SearchCriteria.Op.NULL);
|
// sc.addAnd("removed", SearchCriteria.Op.NULL);
|
||||||
|
|
@ -4192,7 +4234,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor());
|
HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor());
|
||||||
|
|
||||||
return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(), cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(),
|
return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(), cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(),
|
||||||
hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, null, null, cmd.getShowUnique());
|
hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, null, null, cmd.getShowUnique(), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -4212,6 +4254,9 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
}
|
}
|
||||||
fillVMOrTemplateDetailOptions(options, hypervisorType);
|
fillVMOrTemplateDetailOptions(options, hypervisorType);
|
||||||
break;
|
break;
|
||||||
|
case VnfTemplate:
|
||||||
|
fillVnfTemplateDetailOptions(options);
|
||||||
|
return new DetailOptionsResponse(options);
|
||||||
default:
|
default:
|
||||||
throw new CloudRuntimeException("Resource type not supported.");
|
throw new CloudRuntimeException("Resource type not supported.");
|
||||||
}
|
}
|
||||||
|
|
@ -4235,6 +4280,19 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
||||||
return responses;
|
return responses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillVnfTemplateDetailOptions(final Map<String, List<String>> options) {
|
||||||
|
for (VNF.AccessDetail detail : VNF.AccessDetail.values()) {
|
||||||
|
if (VNF.AccessDetail.ACCESS_METHODS.equals(detail)) {
|
||||||
|
options.put(detail.name().toLowerCase(), Arrays.stream(VNF.AccessMethod.values()).map(method -> method.toString()).sorted().collect(Collectors.toList()));
|
||||||
|
} else {
|
||||||
|
options.put(detail.name().toLowerCase(), Collections.emptyList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (VNF.VnfDetail detail : VNF.VnfDetail.values()) {
|
||||||
|
options.put(detail.name().toLowerCase(), Collections.emptyList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void fillVMOrTemplateDetailOptions(final Map<String, List<String>> options, final HypervisorType hypervisorType) {
|
private void fillVMOrTemplateDetailOptions(final Map<String, List<String>> options, final HypervisorType hypervisorType) {
|
||||||
if (options == null) {
|
if (options == null) {
|
||||||
throw new CloudRuntimeException("Invalid/null detail-options response object passed");
|
throw new CloudRuntimeException("Invalid/null detail-options response object passed");
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package com.cloud.api.query.dao;
|
package com.cloud.api.query.dao;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
@ -29,10 +30,16 @@ import javax.inject.Inject;
|
||||||
import com.cloud.deployasis.DeployAsIsConstants;
|
import com.cloud.deployasis.DeployAsIsConstants;
|
||||||
import com.cloud.deployasis.TemplateDeployAsIsDetailVO;
|
import com.cloud.deployasis.TemplateDeployAsIsDetailVO;
|
||||||
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
|
import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao;
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||||
import com.cloud.user.dao.UserDataDao;
|
import com.cloud.user.dao.UserDataDao;
|
||||||
import org.apache.cloudstack.annotation.AnnotationService;
|
import org.apache.cloudstack.annotation.AnnotationService;
|
||||||
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.response.VnfNicResponse;
|
||||||
|
import org.apache.cloudstack.api.response.VnfTemplateResponse;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
|
||||||
import org.apache.cloudstack.utils.security.DigestHelper;
|
import org.apache.cloudstack.utils.security.DigestHelper;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
@ -93,6 +100,10 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||||
private AnnotationDao annotationDao;
|
private AnnotationDao annotationDao;
|
||||||
@Inject
|
@Inject
|
||||||
private UserDataDao userDataDao;
|
private UserDataDao userDataDao;
|
||||||
|
@Inject
|
||||||
|
VnfTemplateDetailsDao vnfTemplateDetailsDao;
|
||||||
|
@Inject
|
||||||
|
VnfTemplateNicDao vnfTemplateNicDao;
|
||||||
|
|
||||||
private final SearchBuilder<TemplateJoinVO> tmpltIdPairSearch;
|
private final SearchBuilder<TemplateJoinVO> tmpltIdPairSearch;
|
||||||
|
|
||||||
|
|
@ -190,7 +201,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateResponse templateResponse = new TemplateResponse();
|
TemplateResponse templateResponse = initTemplateResponse(template);
|
||||||
templateResponse.setDownloadProgress(downloadProgressDetails);
|
templateResponse.setDownloadProgress(downloadProgressDetails);
|
||||||
templateResponse.setId(template.getUuid());
|
templateResponse.setId(template.getUuid());
|
||||||
templateResponse.setName(template.getName());
|
templateResponse.setName(template.getName());
|
||||||
|
|
@ -305,10 +316,29 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||||
templateResponse.setUserDataParams(template.getUserDataParams());
|
templateResponse.setUserDataParams(template.getUserDataParams());
|
||||||
templateResponse.setUserDataPolicy(template.getUserDataPolicy());
|
templateResponse.setUserDataPolicy(template.getUserDataPolicy());
|
||||||
}
|
}
|
||||||
|
|
||||||
templateResponse.setObjectName("template");
|
templateResponse.setObjectName("template");
|
||||||
return templateResponse;
|
return templateResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TemplateResponse initTemplateResponse(TemplateJoinVO template) {
|
||||||
|
TemplateResponse templateResponse = new TemplateResponse();
|
||||||
|
if (Storage.TemplateType.VNF.equals(template.getTemplateType())) {
|
||||||
|
VnfTemplateResponse vnfTemplateResponse = new VnfTemplateResponse();
|
||||||
|
List<VnfTemplateNicVO> nics = vnfTemplateNicDao.listByTemplateId(template.getId());
|
||||||
|
for (VnfTemplateNicVO nic : nics) {
|
||||||
|
vnfTemplateResponse.addVnfNic(new VnfNicResponse(nic.getDeviceId(), nic.getDeviceName(), nic.isRequired(), nic.isManagement(), nic.getDescription()));
|
||||||
|
}
|
||||||
|
List<VnfTemplateDetailVO> details = vnfTemplateDetailsDao.listDetails(template.getId());
|
||||||
|
Collections.sort(details, (v1, v2) -> v1.getName().compareToIgnoreCase(v2.getName()));
|
||||||
|
for (VnfTemplateDetailVO detail : details) {
|
||||||
|
vnfTemplateResponse.addVnfDetail(detail.getName(), detail.getValue());
|
||||||
|
}
|
||||||
|
templateResponse = vnfTemplateResponse;
|
||||||
|
}
|
||||||
|
return templateResponse;
|
||||||
|
}
|
||||||
|
|
||||||
private void setDeployAsIsDetails(TemplateJoinVO template, TemplateResponse templateResponse) {
|
private void setDeployAsIsDetails(TemplateJoinVO template, TemplateResponse templateResponse) {
|
||||||
if (template.isDeployAsIs()) {
|
if (template.isDeployAsIs()) {
|
||||||
List<TemplateDeployAsIsDetailVO> deployAsIsDetails = templateDeployAsIsDetailsDao.listDetails(template.getId());
|
List<TemplateDeployAsIsDetailVO> deployAsIsDetails = templateDeployAsIsDetailsDao.listDetails(template.getId());
|
||||||
|
|
@ -326,7 +356,7 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
||||||
// compared to listTemplates and listIsos.
|
// compared to listTemplates and listIsos.
|
||||||
@Override
|
@Override
|
||||||
public TemplateResponse newUpdateResponse(TemplateJoinVO result) {
|
public TemplateResponse newUpdateResponse(TemplateJoinVO result) {
|
||||||
TemplateResponse response = new TemplateResponse();
|
TemplateResponse response = initTemplateResponse(result);
|
||||||
response.setId(result.getUuid());
|
response.setId(result.getUuid());
|
||||||
response.setName(result.getName());
|
response.setName(result.getName());
|
||||||
response.setDisplayText(result.getDisplayText());
|
response.setDisplayText(result.getDisplayText());
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package com.cloud.api.query.dao;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -39,6 +40,7 @@ import org.apache.cloudstack.api.response.NicResponse;
|
||||||
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
|
import org.apache.cloudstack.api.response.NicSecondaryIpResponse;
|
||||||
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
import org.apache.cloudstack.api.response.SecurityGroupResponse;
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
|
import org.apache.cloudstack.api.response.VnfNicResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.query.QueryService;
|
import org.apache.cloudstack.query.QueryService;
|
||||||
|
|
@ -51,11 +53,17 @@ import com.cloud.api.ApiResponseHelper;
|
||||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||||
import com.cloud.gpu.GPU;
|
import com.cloud.gpu.GPU;
|
||||||
import com.cloud.host.ControlState;
|
import com.cloud.host.ControlState;
|
||||||
|
import com.cloud.network.IpAddress;
|
||||||
import com.cloud.network.vpc.VpcVO;
|
import com.cloud.network.vpc.VpcVO;
|
||||||
import com.cloud.network.vpc.dao.VpcDao;
|
import com.cloud.network.vpc.dao.VpcDao;
|
||||||
import com.cloud.service.ServiceOfferingDetailsVO;
|
import com.cloud.service.ServiceOfferingDetailsVO;
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
import com.cloud.storage.GuestOS;
|
import com.cloud.storage.GuestOS;
|
||||||
|
import com.cloud.storage.Storage.TemplateType;
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.user.User;
|
import com.cloud.user.User;
|
||||||
|
|
@ -95,6 +103,10 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
||||||
private VpcDao vpcDao;
|
private VpcDao vpcDao;
|
||||||
@Inject
|
@Inject
|
||||||
UserStatisticsDao userStatsDao;
|
UserStatisticsDao userStatsDao;
|
||||||
|
@Inject
|
||||||
|
VnfTemplateDetailsDao vnfTemplateDetailsDao;
|
||||||
|
@Inject
|
||||||
|
VnfTemplateNicDao vnfTemplateNicDao;
|
||||||
|
|
||||||
private final SearchBuilder<UserVmJoinVO> VmDetailSearch;
|
private final SearchBuilder<UserVmJoinVO> VmDetailSearch;
|
||||||
private final SearchBuilder<UserVmJoinVO> activeVmByIsoSearch;
|
private final SearchBuilder<UserVmJoinVO> activeVmByIsoSearch;
|
||||||
|
|
@ -183,6 +195,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
||||||
userVmResponse.setTemplateName(userVm.getTemplateName());
|
userVmResponse.setTemplateName(userVm.getTemplateName());
|
||||||
userVmResponse.setTemplateDisplayText(userVm.getTemplateDisplayText());
|
userVmResponse.setTemplateDisplayText(userVm.getTemplateDisplayText());
|
||||||
userVmResponse.setPasswordEnabled(userVm.isPasswordEnabled());
|
userVmResponse.setPasswordEnabled(userVm.isPasswordEnabled());
|
||||||
|
userVmResponse.setTemplateType(userVm.getTemplateType().toString());
|
||||||
}
|
}
|
||||||
if (details.contains(VMDetails.all) || details.contains(VMDetails.iso)) {
|
if (details.contains(VMDetails.all) || details.contains(VMDetails.iso)) {
|
||||||
userVmResponse.setIsoId(userVm.getIsoUuid());
|
userVmResponse.setIsoId(userVm.getIsoUuid());
|
||||||
|
|
@ -320,6 +333,12 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
||||||
}
|
}
|
||||||
nicResponse.setSecondaryIps(ipList);
|
nicResponse.setSecondaryIps(ipList);
|
||||||
}
|
}
|
||||||
|
IpAddress publicIp = ApiDBUtils.findIpByAssociatedVmIdAndNetworkId(userVm.getId(), userVm.getNetworkId());
|
||||||
|
if (publicIp != null) {
|
||||||
|
nicResponse.setPublicIpId(publicIp.getUuid());
|
||||||
|
nicResponse.setPublicIp(publicIp.getAddress().toString());
|
||||||
|
}
|
||||||
|
|
||||||
nicResponse.setObjectName("nic");
|
nicResponse.setObjectName("nic");
|
||||||
|
|
||||||
List<NicExtraDhcpOptionResponse> nicExtraDhcpOptionResponses = _nicExtraDhcpOptionDao.listByNicId(nic_id).stream()
|
List<NicExtraDhcpOptionResponse> nicExtraDhcpOptionResponses = _nicExtraDhcpOptionDao.listByNicId(nic_id).stream()
|
||||||
|
|
@ -419,9 +438,25 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
||||||
|
|
||||||
addVmRxTxDataToResponse(userVm, userVmResponse);
|
addVmRxTxDataToResponse(userVm, userVmResponse);
|
||||||
|
|
||||||
|
if (TemplateType.VNF.equals(userVm.getTemplateType()) && (details.contains(VMDetails.all) || details.contains(VMDetails.vnfnics))) {
|
||||||
|
addVnfInfoToserVmResponse(userVm, userVmResponse);
|
||||||
|
}
|
||||||
|
|
||||||
return userVmResponse;
|
return userVmResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addVnfInfoToserVmResponse(UserVmJoinVO userVm, UserVmResponse userVmResponse) {
|
||||||
|
List<VnfTemplateNicVO> vnfNics = vnfTemplateNicDao.listByTemplateId(userVm.getTemplateId());
|
||||||
|
for (VnfTemplateNicVO nic : vnfNics) {
|
||||||
|
userVmResponse.addVnfNic(new VnfNicResponse(nic.getDeviceId(), nic.getDeviceName(), nic.isRequired(), nic.isManagement(), nic.getDescription()));
|
||||||
|
}
|
||||||
|
List<VnfTemplateDetailVO> vnfDetails = vnfTemplateDetailsDao.listDetails(userVm.getTemplateId());
|
||||||
|
Collections.sort(vnfDetails, (v1, v2) -> v1.getName().compareToIgnoreCase(v2.getName()));
|
||||||
|
for (VnfTemplateDetailVO detail : vnfDetails) {
|
||||||
|
userVmResponse.addVnfDetail(detail.getName(), detail.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addVmRxTxDataToResponse(UserVmJoinVO userVm, UserVmResponse userVmResponse) {
|
private void addVmRxTxDataToResponse(UserVmJoinVO userVm, UserVmResponse userVmResponse) {
|
||||||
Long bytesReceived = 0L;
|
Long bytesReceived = 0L;
|
||||||
Long bytesSent = 0L;
|
Long bytesSent = 0L;
|
||||||
|
|
@ -519,6 +554,11 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
||||||
}
|
}
|
||||||
nicResponse.setSecondaryIps(ipList);
|
nicResponse.setSecondaryIps(ipList);
|
||||||
}
|
}
|
||||||
|
IpAddress publicIp = ApiDBUtils.findIpByAssociatedVmIdAndNetworkId(uvo.getId(), uvo.getNetworkId());
|
||||||
|
if (publicIp != null) {
|
||||||
|
nicResponse.setPublicIpId(publicIp.getUuid());
|
||||||
|
nicResponse.setPublicIp(publicIp.getAddress().toString());
|
||||||
|
}
|
||||||
|
|
||||||
/* 18: extra dhcp options */
|
/* 18: extra dhcp options */
|
||||||
nicResponse.setObjectName("nic");
|
nicResponse.setObjectName("nic");
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
import com.cloud.network.Network.GuestType;
|
import com.cloud.network.Network.GuestType;
|
||||||
import com.cloud.network.Networks.TrafficType;
|
import com.cloud.network.Networks.TrafficType;
|
||||||
import com.cloud.resource.ResourceState;
|
import com.cloud.resource.ResourceState;
|
||||||
|
import com.cloud.storage.Storage.TemplateType;
|
||||||
import com.cloud.storage.Storage.StoragePoolType;
|
import com.cloud.storage.Storage.StoragePoolType;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
|
|
@ -191,6 +192,9 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
||||||
@Column(name = "template_name")
|
@Column(name = "template_name")
|
||||||
private String templateName;
|
private String templateName;
|
||||||
|
|
||||||
|
@Column(name = "template_type")
|
||||||
|
private TemplateType templateType;
|
||||||
|
|
||||||
@Column(name = "template_display_text", length = 4096)
|
@Column(name = "template_display_text", length = 4096)
|
||||||
private String templateDisplayText;
|
private String templateDisplayText;
|
||||||
|
|
||||||
|
|
@ -632,6 +636,10 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
||||||
return templateName;
|
return templateName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TemplateType getTemplateType() {
|
||||||
|
return templateType;
|
||||||
|
}
|
||||||
|
|
||||||
public String getTemplateDisplayText() {
|
public String getTemplateDisplayText() {
|
||||||
return templateDisplayText;
|
return templateDisplayText;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,8 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
||||||
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
|
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
|
||||||
_accountMgr.checkAccess(caller, null, true, owner);
|
_accountMgr.checkAccess(caller, null, true, owner);
|
||||||
|
|
||||||
boolean isRouting = (cmd.isRoutingType() == null) ? false : cmd.isRoutingType();
|
TemplateType templateType = templateMgr.validateTemplateType(cmd, _accountMgr.isAdmin(caller.getAccountId()),
|
||||||
|
CollectionUtils.isEmpty(cmd.getZoneIds()));
|
||||||
|
|
||||||
List<Long> zoneId = cmd.getZoneIds();
|
List<Long> zoneId = cmd.getZoneIds();
|
||||||
// ignore passed zoneId if we are using region wide image store
|
// ignore passed zoneId if we are using region wide image store
|
||||||
|
|
@ -305,7 +306,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
||||||
}
|
}
|
||||||
return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(),
|
return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(),
|
||||||
cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), zoneId, hypervisorType, cmd.getChecksum(), true,
|
cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), zoneId, hypervisorType, cmd.getChecksum(), true,
|
||||||
cmd.getTemplateTag(), owner, details, cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), isRouting ? TemplateType.ROUTING : TemplateType.USER,
|
cmd.getTemplateTag(), owner, details, cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), templateType,
|
||||||
cmd.isDirectDownload(), cmd.isDeployAsIs());
|
cmd.isDirectDownload(), cmd.isDeployAsIs());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.BaseCmd;
|
||||||
import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd;
|
import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd;
|
||||||
import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd;
|
import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd;
|
||||||
import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd;
|
import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd;
|
||||||
|
|
@ -53,8 +54,10 @@ import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd;
|
import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd;
|
import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
||||||
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
|
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
|
@ -96,6 +99,8 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
|
import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateManager;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateUtils;
|
||||||
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
import org.apache.cloudstack.storage.to.TemplateObjectTO;
|
||||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
@ -303,6 +308,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected SnapshotHelper snapshotHelper;
|
protected SnapshotHelper snapshotHelper;
|
||||||
|
@Inject
|
||||||
|
VnfTemplateManager vnfTemplateManager;
|
||||||
|
|
||||||
private TemplateAdapter getAdapter(HypervisorType type) {
|
private TemplateAdapter getAdapter(HypervisorType type) {
|
||||||
TemplateAdapter adapter = null;
|
TemplateAdapter adapter = null;
|
||||||
|
|
@ -360,6 +367,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||||
|
|
||||||
if (template != null) {
|
if (template != null) {
|
||||||
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
|
CallContext.current().putContextParameter(VirtualMachineTemplate.class, template.getUuid());
|
||||||
|
if (cmd instanceof RegisterVnfTemplateCmd) {
|
||||||
|
vnfTemplateManager.persistVnfTemplate(template.getId(), (RegisterVnfTemplateCmd) cmd);
|
||||||
|
}
|
||||||
return template;
|
return template;
|
||||||
} else {
|
} else {
|
||||||
throw new CloudRuntimeException("Failed to create a template");
|
throw new CloudRuntimeException("Failed to create a template");
|
||||||
|
|
@ -1329,6 +1339,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||||
throw new InvalidParameterValueException("Please specify a valid template.");
|
throw new InvalidParameterValueException("Please specify a valid template.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VnfTemplateUtils.validateApiCommandParams(cmd, template);
|
||||||
|
|
||||||
TemplateAdapter adapter = getAdapter(template.getHypervisorType());
|
TemplateAdapter adapter = getAdapter(template.getHypervisorType());
|
||||||
TemplateProfile profile = adapter.prepareDelete(cmd);
|
TemplateProfile profile = adapter.prepareDelete(cmd);
|
||||||
return adapter.delete(profile);
|
return adapter.delete(profile);
|
||||||
|
|
@ -2113,22 +2125,11 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||||
// update template type
|
// update template type
|
||||||
TemplateType templateType = null;
|
TemplateType templateType = null;
|
||||||
if (cmd instanceof UpdateTemplateCmd) {
|
if (cmd instanceof UpdateTemplateCmd) {
|
||||||
String newType = ((UpdateTemplateCmd)cmd).getTemplateType();
|
boolean isAdmin = _accountMgr.isAdmin(account.getId());
|
||||||
if (newType != null) {
|
templateType = validateTemplateType(cmd, isAdmin, template.isCrossZones());
|
||||||
if (!_accountService.isRootAdmin(account.getId())) {
|
if (cmd instanceof UpdateVnfTemplateCmd) {
|
||||||
throw new PermissionDeniedException("Parameter templatetype can only be specified by a Root Admin, permission denied");
|
VnfTemplateUtils.validateApiCommandParams(cmd, template);
|
||||||
}
|
vnfTemplateManager.updateVnfTemplate(template.getId(), (UpdateVnfTemplateCmd) cmd);
|
||||||
try {
|
|
||||||
templateType = TemplateType.valueOf(newType.toUpperCase());
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
throw new InvalidParameterValueException("Please specify a valid templatetype: ROUTING / SYSTEM / USER / BUILTIN / PERHOST");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (templateType != null && cmd.isRoutingType() != null && (TemplateType.ROUTING.equals(templateType) != cmd.isRoutingType())) {
|
|
||||||
throw new InvalidParameterValueException("Please specify a valid templatetype (consistent with isrouting parameter).");
|
|
||||||
}
|
|
||||||
if (templateType != null && (templateType == TemplateType.SYSTEM || templateType == TemplateType.BUILTIN) && !template.isCrossZones()) {
|
|
||||||
throw new InvalidParameterValueException("System and Builtin templates must be cross zone");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2248,6 +2249,51 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||||
return _tmpltDao.findById(id);
|
return _tmpltDao.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean isCrossZones) {
|
||||||
|
if (!(cmd instanceof UpdateTemplateCmd) && !(cmd instanceof RegisterTemplateCmd)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TemplateType templateType = null;
|
||||||
|
String newType = null;
|
||||||
|
Boolean isRoutingType = null;
|
||||||
|
if (cmd instanceof UpdateTemplateCmd) {
|
||||||
|
newType = ((UpdateTemplateCmd)cmd).getTemplateType();
|
||||||
|
isRoutingType = ((UpdateTemplateCmd)cmd).isRoutingType();
|
||||||
|
} else if (cmd instanceof RegisterTemplateCmd) {
|
||||||
|
newType = ((RegisterTemplateCmd)cmd).getTemplateType();
|
||||||
|
isRoutingType = ((RegisterTemplateCmd)cmd).isRoutingType();
|
||||||
|
}
|
||||||
|
if (newType != null) {
|
||||||
|
try {
|
||||||
|
templateType = TemplateType.valueOf(newType.toUpperCase());
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Please specify a valid templatetype: %s",
|
||||||
|
org.apache.commons.lang3.StringUtils.join(",", TemplateType.values())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (templateType != null) {
|
||||||
|
if (isRoutingType != null && (TemplateType.ROUTING.equals(templateType) != isRoutingType)) {
|
||||||
|
throw new InvalidParameterValueException("Please specify a valid templatetype (consistent with isrouting parameter).");
|
||||||
|
} else if ((templateType == TemplateType.SYSTEM || templateType == TemplateType.BUILTIN) && !isCrossZones) {
|
||||||
|
throw new InvalidParameterValueException("System and Builtin templates must be cross zone.");
|
||||||
|
} else if ((cmd instanceof RegisterVnfTemplateCmd || cmd instanceof UpdateVnfTemplateCmd) && !TemplateType.VNF.equals(templateType)) {
|
||||||
|
throw new InvalidParameterValueException("The template type must be VNF for VNF templates, but the actual type is " + templateType);
|
||||||
|
}
|
||||||
|
} else if (cmd instanceof RegisterTemplateCmd) {
|
||||||
|
boolean isRouting = Boolean.TRUE.equals(isRoutingType);
|
||||||
|
templateType = (cmd instanceof RegisterVnfTemplateCmd) ? TemplateType.VNF : (isRouting ? TemplateType.ROUTING : TemplateType.USER);
|
||||||
|
}
|
||||||
|
if (templateType != null && !isAdmin && !Arrays.asList(TemplateType.USER, TemplateType.VNF).contains(templateType)) {
|
||||||
|
if (cmd instanceof RegisterTemplateCmd) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Users can not register template with template type %s.", templateType));
|
||||||
|
} else if (cmd instanceof UpdateTemplateCmd) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Users can not update template to template type %s.", templateType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return templateType;
|
||||||
|
}
|
||||||
|
|
||||||
void validateDetails(VMTemplateVO template, Map<String, String> details) {
|
void validateDetails(VMTemplateVO template, Map<String, String> details) {
|
||||||
if (MapUtils.isEmpty(details)) {
|
if (MapUtils.isEmpty(details)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -2270,7 +2316,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
||||||
String msg = String.format("Invalid %s: %s specified. Valid values are: %s",
|
String msg = String.format("Invalid %s: %s specified. Valid values are: %s",
|
||||||
ApiConstants.BOOT_MODE, bootMode, Arrays.toString(ApiConstants.BootMode.values()));
|
ApiConstants.BOOT_MODE, bootMode, Arrays.toString(ApiConstants.BootMode.values()));
|
||||||
s_logger.error(msg);
|
s_logger.error(msg);
|
||||||
throw new InvalidParameterValueException(msg); }
|
throw new InvalidParameterValueException(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void verifyTemplateId(Long id) {
|
void verifyTemplateId(Long id) {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,7 @@ import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin;
|
||||||
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
|
import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.RebootVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd;
|
||||||
|
|
@ -123,6 +124,7 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateManager;
|
||||||
import org.apache.cloudstack.userdata.UserDataManager;
|
import org.apache.cloudstack.userdata.UserDataManager;
|
||||||
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
import org.apache.cloudstack.utils.bytescale.ByteScaleUtils;
|
||||||
import org.apache.cloudstack.utils.security.ParserUtils;
|
import org.apache.cloudstack.utils.security.ParserUtils;
|
||||||
|
|
@ -620,6 +622,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||||
@Inject
|
@Inject
|
||||||
private UserDataManager userDataManager;
|
private UserDataManager userDataManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
VnfTemplateManager vnfTemplateManager;
|
||||||
|
|
||||||
private static final ConfigKey<Integer> VmIpFetchWaitInterval = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmip.retrieval.interval", "180",
|
private static final ConfigKey<Integer> VmIpFetchWaitInterval = new ConfigKey<Integer>("Advanced", Integer.class, "externaldhcp.vmip.retrieval.interval", "180",
|
||||||
"Wait Interval (in seconds) for shared network vm dhcp ip addr fetch for next iteration ", true);
|
"Wait Interval (in seconds) for shared network vm dhcp ip addr fetch for next iteration ", true);
|
||||||
|
|
||||||
|
|
@ -5901,6 +5906,11 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||||
if (template == null) {
|
if (template == null) {
|
||||||
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
throw new InvalidParameterValueException("Unable to use template " + templateId);
|
||||||
}
|
}
|
||||||
|
if (TemplateType.VNF.equals(template.getTemplateType())) {
|
||||||
|
vnfTemplateManager.validateVnfApplianceNics(template, cmd.getNetworkIds());
|
||||||
|
} else if (cmd instanceof DeployVnfApplianceCmd) {
|
||||||
|
throw new InvalidParameterValueException("Can't deploy VNF appliance from a non-VNF template");
|
||||||
|
}
|
||||||
|
|
||||||
ServiceOfferingJoinVO svcOffering = serviceOfferingJoinDao.findById(serviceOfferingId);
|
ServiceOfferingJoinVO svcOffering = serviceOfferingJoinDao.findById(serviceOfferingId);
|
||||||
|
|
||||||
|
|
@ -5982,14 +5992,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||||
if (networkIds != null) {
|
if (networkIds != null) {
|
||||||
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
|
throw new InvalidParameterValueException("Can't specify network Ids in Basic zone");
|
||||||
} else {
|
} else {
|
||||||
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd), owner, name, displayName, diskOfferingId,
|
vm = createBasicSecurityGroupVirtualMachine(zone, serviceOffering, template, getSecurityGroupIdList(cmd, zone, template, owner), owner, name, displayName, diskOfferingId,
|
||||||
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
|
size , group , cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm , keyboard , cmd.getAffinityGroupIdList(),
|
||||||
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
||||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId);
|
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (zone.isSecurityGroupEnabled()) {
|
if (zone.isSecurityGroupEnabled()) {
|
||||||
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd), owner, name,
|
vm = createAdvancedSecurityGroupVirtualMachine(zone, serviceOffering, template, networkIds, getSecurityGroupIdList(cmd, zone, template, owner), owner, name,
|
||||||
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
|
displayName, diskOfferingId, size, group, cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard,
|
||||||
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
cmd.getAffinityGroupIdList(), cmd.getDetails(), cmd.getCustomId(), cmd.getDhcpOptionsMap(),
|
||||||
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, null);
|
dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, overrideDiskOfferingId, null);
|
||||||
|
|
@ -6001,6 +6011,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||||
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, group,
|
vm = createAdvancedVirtualMachine(zone, serviceOffering, template, networkIds, owner, name, displayName, diskOfferingId, size, group,
|
||||||
cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
|
cmd.getHypervisor(), cmd.getHttpMethod(), userData, userDataId, userDataDetails, sshKeyPairNames, cmd.getIpToNetworkMap(), addrs, displayVm, keyboard, cmd.getAffinityGroupIdList(), cmd.getDetails(),
|
||||||
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
|
cmd.getCustomId(), cmd.getDhcpOptionsMap(), dataDiskTemplateToDiskOfferingMap, userVmOVFProperties, dynamicScalingEnabled, null, overrideDiskOfferingId);
|
||||||
|
if (cmd instanceof DeployVnfApplianceCmd) {
|
||||||
|
vnfTemplateManager.createIsolatedNetworkRulesForVnfAppliance(zone, template, owner, vm, (DeployVnfApplianceCmd) cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6267,6 +6280,20 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<Long> getSecurityGroupIdList(SecurityGroupAction cmd, DataCenter zone, VirtualMachineTemplate template, Account owner) {
|
||||||
|
List<Long> securityGroupIdList = getSecurityGroupIdList(cmd);
|
||||||
|
if (cmd instanceof DeployVnfApplianceCmd) {
|
||||||
|
SecurityGroup securityGroup = vnfTemplateManager.createSecurityGroupForVnfAppliance(zone, template, owner, (DeployVnfApplianceCmd) cmd);
|
||||||
|
if (securityGroup != null) {
|
||||||
|
if (securityGroupIdList == null) {
|
||||||
|
securityGroupIdList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
securityGroupIdList.add(securityGroup.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return securityGroupIdList;
|
||||||
|
}
|
||||||
|
|
||||||
// this is an opportunity to verify that parameters that came in via the Details Map are OK
|
// this is an opportunity to verify that parameters that came in via the Details Map are OK
|
||||||
// for example, minIops and maxIops should either both be specified or neither be specified and,
|
// for example, minIops and maxIops should either both be specified or neither be specified and,
|
||||||
// if specified, minIops should be <= maxIops
|
// if specified, minIops should be <= maxIops
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,372 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.storage.template;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.exception.NetworkRuleConflictException;
|
||||||
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.network.IpAddress;
|
||||||
|
import com.cloud.network.IpAddressManager;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.NetworkModel;
|
||||||
|
import com.cloud.network.NetworkService;
|
||||||
|
import com.cloud.network.VNF;
|
||||||
|
import com.cloud.network.dao.FirewallRulesDao;
|
||||||
|
import com.cloud.network.dao.NetworkDao;
|
||||||
|
import com.cloud.network.firewall.FirewallService;
|
||||||
|
import com.cloud.network.rules.FirewallRule;
|
||||||
|
import com.cloud.network.rules.FirewallRuleVO;
|
||||||
|
import com.cloud.network.rules.RulesService;
|
||||||
|
import com.cloud.network.security.SecurityGroup;
|
||||||
|
import com.cloud.network.security.SecurityGroupManager;
|
||||||
|
import com.cloud.network.security.SecurityGroupService;
|
||||||
|
import com.cloud.network.security.SecurityGroupVO;
|
||||||
|
import com.cloud.network.security.SecurityRule;
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.uservm.UserVm;
|
||||||
|
import com.cloud.utils.NumbersUtil;
|
||||||
|
import com.cloud.utils.component.ManagerBase;
|
||||||
|
import com.cloud.utils.component.PluggableService;
|
||||||
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
|
||||||
|
import com.cloud.utils.db.TransactionStatus;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import com.cloud.utils.net.NetUtils;
|
||||||
|
import com.cloud.vm.NicVO;
|
||||||
|
import com.cloud.vm.dao.NicDao;
|
||||||
|
import org.apache.cloudstack.api.command.admin.template.ListVnfTemplatesCmdByAdmin;
|
||||||
|
import org.apache.cloudstack.api.command.admin.template.RegisterVnfTemplateCmdByAdmin;
|
||||||
|
import org.apache.cloudstack.api.command.admin.template.UpdateVnfTemplateCmdByAdmin;
|
||||||
|
import org.apache.cloudstack.api.command.admin.vm.DeployVnfApplianceCmdByAdmin;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.DeleteVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.ListVnfTemplatesCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
||||||
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.collections.MapUtils;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
public class VnfTemplateManagerImpl extends ManagerBase implements VnfTemplateManager, PluggableService, Configurable {
|
||||||
|
|
||||||
|
static final Logger LOGGER = Logger.getLogger(VnfTemplateManagerImpl.class);
|
||||||
|
|
||||||
|
public static final String VNF_SECURITY_GROUP_NAME = "VNF_SecurityGroup_";
|
||||||
|
public static final String ACCESS_METHOD_SEPARATOR = ",";
|
||||||
|
public static final Integer ACCESS_DEFAULT_SSH_PORT = 22;
|
||||||
|
public static final Integer ACCESS_DEFAULT_HTTP_PORT = 80;
|
||||||
|
public static final Integer ACCESS_DEFAULT_HTTPS_PORT = 443;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
VnfTemplateDetailsDao vnfTemplateDetailsDao;
|
||||||
|
@Inject
|
||||||
|
VnfTemplateNicDao vnfTemplateNicDao;
|
||||||
|
@Inject
|
||||||
|
SecurityGroupManager securityGroupManager;
|
||||||
|
@Inject
|
||||||
|
SecurityGroupService securityGroupService;
|
||||||
|
@Inject
|
||||||
|
NetworkModel networkModel;
|
||||||
|
@Inject
|
||||||
|
IpAddressManager ipAddressManager;
|
||||||
|
@Inject
|
||||||
|
NicDao nicDao;
|
||||||
|
@Inject
|
||||||
|
NetworkDao networkDao;
|
||||||
|
@Inject
|
||||||
|
NetworkService networkService;
|
||||||
|
@Inject
|
||||||
|
RulesService rulesService;
|
||||||
|
@Inject
|
||||||
|
FirewallRulesDao firewallRulesDao;
|
||||||
|
@Inject
|
||||||
|
FirewallService firewallService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Class<?>> getCommands() {
|
||||||
|
final List<Class<?>> cmdList = new ArrayList<>();
|
||||||
|
if (!VnfTemplateAndApplianceEnabled.value()) {
|
||||||
|
return cmdList;
|
||||||
|
}
|
||||||
|
cmdList.add(RegisterVnfTemplateCmd.class);
|
||||||
|
cmdList.add(RegisterVnfTemplateCmdByAdmin.class);
|
||||||
|
cmdList.add(ListVnfTemplatesCmd.class);
|
||||||
|
cmdList.add(ListVnfTemplatesCmdByAdmin.class);
|
||||||
|
cmdList.add(UpdateVnfTemplateCmd.class);
|
||||||
|
cmdList.add(UpdateVnfTemplateCmdByAdmin.class);
|
||||||
|
cmdList.add(DeleteVnfTemplateCmd.class);
|
||||||
|
cmdList.add(DeployVnfApplianceCmd.class);
|
||||||
|
cmdList.add(DeployVnfApplianceCmdByAdmin.class);
|
||||||
|
return cmdList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void persistVnfTemplate(long templateId, RegisterVnfTemplateCmd cmd) {
|
||||||
|
persistVnfTemplateNics(templateId, cmd.getVnfNics());
|
||||||
|
persistVnfTemplateDetails(templateId, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistVnfTemplateNics(long templateId, List<VNF.VnfNic> nics) {
|
||||||
|
for (VNF.VnfNic nic : nics) {
|
||||||
|
VnfTemplateNicVO vnfTemplateNicVO = new VnfTemplateNicVO(templateId, nic.getDeviceId(), nic.getName(), nic.isRequired(), nic.isManagement(), nic.getDescription());
|
||||||
|
vnfTemplateNicDao.persist(vnfTemplateNicVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistVnfTemplateDetails(long templateId, RegisterVnfTemplateCmd cmd) {
|
||||||
|
persistVnfTemplateDetails(templateId, cmd.getVnfDetails());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistVnfTemplateDetails(long templateId, Map<String, String> vnfDetails) {
|
||||||
|
for (Map.Entry<String, String> entry: vnfDetails.entrySet()) {
|
||||||
|
String value = entry.getValue();
|
||||||
|
if (VNF.AccessDetail.ACCESS_METHODS.name().equalsIgnoreCase(entry.getKey())) {
|
||||||
|
value = Arrays.stream(value.split(ACCESS_METHOD_SEPARATOR)).sorted().collect(Collectors.joining(ACCESS_METHOD_SEPARATOR));
|
||||||
|
}
|
||||||
|
vnfTemplateDetailsDao.addDetail(templateId, entry.getKey().toLowerCase(), value, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateVnfTemplate(long templateId, UpdateVnfTemplateCmd cmd) {
|
||||||
|
updateVnfTemplateDetails(templateId, cmd);
|
||||||
|
updateVnfTemplateNics(templateId, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateVnfTemplateDetails(long templateId, UpdateVnfTemplateCmd cmd) {
|
||||||
|
boolean cleanupVnfDetails = cmd.isCleanupVnfDetails();
|
||||||
|
if (cleanupVnfDetails) {
|
||||||
|
vnfTemplateDetailsDao.removeDetails(templateId);
|
||||||
|
} else if (MapUtils.isNotEmpty(cmd.getVnfDetails())) {
|
||||||
|
vnfTemplateDetailsDao.removeDetails(templateId);
|
||||||
|
persistVnfTemplateDetails(templateId, cmd.getVnfDetails());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateVnfTemplateNics(long templateId, UpdateVnfTemplateCmd cmd) {
|
||||||
|
boolean cleanupVnfNics = cmd.isCleanupVnfNics();
|
||||||
|
if (cleanupVnfNics) {
|
||||||
|
vnfTemplateNicDao.deleteByTemplateId(templateId);
|
||||||
|
} else if (CollectionUtils.isNotEmpty(cmd.getVnfNics())) {
|
||||||
|
vnfTemplateNicDao.deleteByTemplateId(templateId);
|
||||||
|
persistVnfTemplateNics(templateId, cmd.getVnfNics());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConfigComponentName() {
|
||||||
|
return VnfTemplateManager.class.getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConfigKey<?>[] getConfigKeys() {
|
||||||
|
return new ConfigKey[] { VnfTemplateAndApplianceEnabled };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateVnfApplianceNics(VirtualMachineTemplate template, List<Long> networkIds) {
|
||||||
|
if (CollectionUtils.isEmpty(networkIds)) {
|
||||||
|
throw new InvalidParameterValueException("VNF nics list is empty");
|
||||||
|
}
|
||||||
|
List<VnfTemplateNicVO> vnfNics = vnfTemplateNicDao.listByTemplateId(template.getId());
|
||||||
|
for (VnfTemplateNicVO vnfNic : vnfNics) {
|
||||||
|
if (vnfNic.isRequired() && networkIds.size() <= vnfNic.getDeviceId()) {
|
||||||
|
throw new InvalidParameterValueException("VNF nic is required but not found: " + vnfNic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Set<Integer> getOpenPortsForVnfAppliance(VirtualMachineTemplate template) {
|
||||||
|
Set<Integer> ports = new HashSet<>();
|
||||||
|
VnfTemplateDetailVO accessMethodsDetail = vnfTemplateDetailsDao.findDetail(template.getId(), VNF.AccessDetail.ACCESS_METHODS.name().toLowerCase());
|
||||||
|
if (accessMethodsDetail == null || accessMethodsDetail.getValue() == null) {
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
String[] accessMethods = accessMethodsDetail.getValue().split(ACCESS_METHOD_SEPARATOR);
|
||||||
|
for (String accessMethod : accessMethods) {
|
||||||
|
if (VNF.AccessMethod.SSH_WITH_KEY.toString().equalsIgnoreCase(accessMethod)
|
||||||
|
|| VNF.AccessMethod.SSH_WITH_PASSWORD.toString().equalsIgnoreCase(accessMethod)) {
|
||||||
|
VnfTemplateDetailVO accessDetail = vnfTemplateDetailsDao.findDetail(template.getId(), VNF.AccessDetail.SSH_PORT.name().toLowerCase());
|
||||||
|
if (accessDetail == null) {
|
||||||
|
ports.add(ACCESS_DEFAULT_SSH_PORT);
|
||||||
|
} else {
|
||||||
|
ports.add(NumbersUtil.parseInt(accessDetail.getValue(), ACCESS_DEFAULT_SSH_PORT));
|
||||||
|
}
|
||||||
|
} else if (VNF.AccessMethod.HTTP.toString().equalsIgnoreCase(accessMethod)) {
|
||||||
|
VnfTemplateDetailVO accessDetail = vnfTemplateDetailsDao.findDetail(template.getId(), VNF.AccessDetail.HTTP_PORT.name().toLowerCase());
|
||||||
|
if (accessDetail == null) {
|
||||||
|
ports.add(ACCESS_DEFAULT_HTTP_PORT);
|
||||||
|
} else {
|
||||||
|
ports.add(NumbersUtil.parseInt(accessDetail.getValue(), ACCESS_DEFAULT_HTTP_PORT));
|
||||||
|
}
|
||||||
|
} else if (VNF.AccessMethod.HTTPS.toString().equalsIgnoreCase(accessMethod)) {
|
||||||
|
VnfTemplateDetailVO accessDetail = vnfTemplateDetailsDao.findDetail(template.getId(), VNF.AccessDetail.HTTPS_PORT.name().toLowerCase());
|
||||||
|
if (accessDetail == null) {
|
||||||
|
ports.add(ACCESS_DEFAULT_HTTPS_PORT);
|
||||||
|
} else {
|
||||||
|
ports.add(NumbersUtil.parseInt(accessDetail.getValue(), ACCESS_DEFAULT_HTTPS_PORT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ports;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<Long> getDeviceIdsOfVnfManagementNics(VirtualMachineTemplate template) {
|
||||||
|
Set<Long> deviceIds = new HashSet<>();
|
||||||
|
for (VnfTemplateNicVO nic : vnfTemplateNicDao.listByTemplateId(template.getId())) {
|
||||||
|
if (nic.isManagement()) {
|
||||||
|
deviceIds.add(nic.getDeviceId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return deviceIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<Network, String> getManagementNetworkAndIp(VirtualMachineTemplate template, UserVm vm) {
|
||||||
|
Map<Network, String> networkAndIpMap = new HashMap<>();
|
||||||
|
Set<Long> managementDeviceIds = getDeviceIdsOfVnfManagementNics(template);
|
||||||
|
for (NicVO nic : nicDao.listByVmId(vm.getId())) {
|
||||||
|
if (managementDeviceIds.contains((long) nic.getDeviceId()) && nic.getIPv4Address() != null) {
|
||||||
|
Network network = networkDao.findById(nic.getNetworkId());
|
||||||
|
if (network == null || !Network.GuestType.Isolated.equals(network.getGuestType())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!networkModel.areServicesSupportedInNetwork(network.getId(), Network.Service.StaticNat)) {
|
||||||
|
LOGGER.info(String.format("Network ID: %s does not support static nat, " +
|
||||||
|
"skipping this network configuration for VNF appliance", network.getUuid()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (network.getVpcId() != null) {
|
||||||
|
LOGGER.info(String.format("Network ID: %s is a VPC tier, " +
|
||||||
|
"skipping this network configuration for VNF appliance", network.getUuid()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!networkModel.areServicesSupportedInNetwork(network.getId(), Network.Service.Firewall)) {
|
||||||
|
LOGGER.info(String.format("Network ID: %s does not support firewall, " +
|
||||||
|
"skipping this network configuration for VNF appliance", network.getUuid()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
networkAndIpMap.put(network, nic.getIPv4Address());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return networkAndIpMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecurityGroup createSecurityGroupForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner,
|
||||||
|
DeployVnfApplianceCmd cmd) {
|
||||||
|
if (zone == null || !zone.isSecurityGroupEnabled()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!cmd.getVnfConfigureManagement()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LOGGER.debug("Creating security group and rules for VNF appliance");
|
||||||
|
Set<Integer> ports = getOpenPortsForVnfAppliance(template);
|
||||||
|
if (ports.size() == 0) {
|
||||||
|
LOGGER.debug("No need to create security group and rules for VNF appliance as there is no ports to be open");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String securityGroupName = VNF_SECURITY_GROUP_NAME.concat(Long.toHexString(System.currentTimeMillis()));
|
||||||
|
SecurityGroupVO securityGroupVO = securityGroupManager.createSecurityGroup(securityGroupName,
|
||||||
|
"Security group for VNF appliance", owner.getDomainId(), owner.getId(), owner.getAccountName());
|
||||||
|
if (securityGroupVO == null) {
|
||||||
|
throw new CloudRuntimeException(String.format("Failed to create security group: %s", securityGroupName));
|
||||||
|
}
|
||||||
|
List<String> cidrList = cmd.getVnfCidrlist();
|
||||||
|
for (Integer port : ports) {
|
||||||
|
securityGroupService.authorizeSecurityGroupRule(securityGroupVO.getId(), NetUtils.TCP_PROTO, port, port,
|
||||||
|
null, null, cidrList, null, SecurityRule.SecurityRuleType.IngressRule);
|
||||||
|
}
|
||||||
|
return securityGroupVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createIsolatedNetworkRulesForVnfAppliance(DataCenter zone, VirtualMachineTemplate template, Account owner,
|
||||||
|
UserVm vm, DeployVnfApplianceCmd cmd)
|
||||||
|
throws InsufficientAddressCapacityException, ResourceAllocationException, ResourceUnavailableException {
|
||||||
|
|
||||||
|
Map<Network, String> networkAndIpMap = getManagementNetworkAndIp(template, vm);
|
||||||
|
Set<Integer> ports = getOpenPortsForVnfAppliance(template);
|
||||||
|
for (Map.Entry<Network, String> entry : networkAndIpMap.entrySet()) {
|
||||||
|
Network network = entry.getKey();
|
||||||
|
LOGGER.debug("Creating network rules for VNF appliance on isolated network " + network.getUuid());
|
||||||
|
String ip = entry.getValue();
|
||||||
|
IpAddress publicIp = networkService.allocateIP(owner, zone.getId(), network.getId(), null, null);
|
||||||
|
if (publicIp == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
publicIp = ipAddressManager.associateIPToGuestNetwork(publicIp.getId(), network.getId(), false);
|
||||||
|
if (publicIp.isSourceNat()) {
|
||||||
|
// If isolated network is not implemented, the first acquired Public IP will be Source NAT IP
|
||||||
|
publicIp = networkService.allocateIP(owner, zone.getId(), network.getId(), null, null);
|
||||||
|
if (publicIp == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
publicIp = ipAddressManager.associateIPToGuestNetwork(publicIp.getId(), network.getId(), false);
|
||||||
|
}
|
||||||
|
final IpAddress publicIpFinal = publicIp;
|
||||||
|
final List<String> cidrList = cmd.getVnfCidrlist();
|
||||||
|
try {
|
||||||
|
boolean result = rulesService.enableStaticNat(publicIp.getId(), vm.getId(), network.getId(), ip);
|
||||||
|
if (!result) {
|
||||||
|
throw new CloudRuntimeException(String.format("Failed to create static nat for vm: %s", vm.getUuid()));
|
||||||
|
}
|
||||||
|
} catch (NetworkRuleConflictException e) {
|
||||||
|
throw new CloudRuntimeException(String.format("Failed to create static nat for vm %s due to %s", vm.getUuid(), e.getMessage()));
|
||||||
|
}
|
||||||
|
if (network.getVpcId() == null) {
|
||||||
|
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<>() {
|
||||||
|
@Override
|
||||||
|
public void doInTransactionWithoutResult(final TransactionStatus status) throws CloudRuntimeException {
|
||||||
|
for (Integer port : ports) {
|
||||||
|
FirewallRuleVO newFirewallRule = new FirewallRuleVO(null, publicIpFinal.getId(), port, port, NetUtils.TCP_PROTO,
|
||||||
|
network.getId(), owner.getAccountId(), owner.getDomainId(), FirewallRule.Purpose.Firewall,
|
||||||
|
cidrList, null, null, null, FirewallRule.TrafficType.Ingress);
|
||||||
|
newFirewallRule.setDisplay(true);
|
||||||
|
newFirewallRule.setState(FirewallRule.State.Add);
|
||||||
|
firewallRulesDao.persist(newFirewallRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
firewallService.applyIngressFwRules(publicIp.getId(), owner);
|
||||||
|
}
|
||||||
|
LOGGER.debug("Created network rules for VNF appliance on isolated network " + network.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -356,4 +356,5 @@
|
||||||
<property name="asyncJobDispatcher" ref="ApiAsyncJobDispatcher" />
|
<property name="asyncJobDispatcher" ref="ApiAsyncJobDispatcher" />
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
<bean id="vnfTemplateManager" class="org.apache.cloudstack.storage.template.VnfTemplateManagerImpl" />
|
||||||
</beans>
|
</beans>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ import com.cloud.event.dao.EventJoinDao;
|
||||||
import com.cloud.exception.InvalidParameterValueException;
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
import com.cloud.exception.PermissionDeniedException;
|
import com.cloud.exception.PermissionDeniedException;
|
||||||
import com.cloud.network.Network;
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.VNF;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
|
import com.cloud.server.ResourceTag;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.user.AccountVO;
|
import com.cloud.user.AccountVO;
|
||||||
|
|
@ -39,6 +41,8 @@ import com.cloud.vm.VirtualMachine;
|
||||||
import org.apache.cloudstack.acl.SecurityChecker;
|
import org.apache.cloudstack.acl.SecurityChecker;
|
||||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||||
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
|
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
|
||||||
|
import org.apache.cloudstack.api.response.DetailOptionsResponse;
|
||||||
import org.apache.cloudstack.api.response.EventResponse;
|
import org.apache.cloudstack.api.response.EventResponse;
|
||||||
import org.apache.cloudstack.api.response.ListResponse;
|
import org.apache.cloudstack.api.response.ListResponse;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
|
|
@ -54,10 +58,13 @@ import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
|
@ -197,6 +204,27 @@ public class QueryManagerImplTest {
|
||||||
queryManager.searchForEvents(cmd);
|
queryManager.searchForEvents(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listVnfDetailOptionsCmd() {
|
||||||
|
ListDetailOptionsCmd cmd = Mockito.mock(ListDetailOptionsCmd.class);
|
||||||
|
when(cmd.getResourceType()).thenReturn(ResourceTag.ResourceObjectType.VnfTemplate);
|
||||||
|
|
||||||
|
DetailOptionsResponse response = queryManager.listDetailOptions(cmd);
|
||||||
|
Map<String, List<String>> options = response.getDetails();
|
||||||
|
|
||||||
|
int expectedLength = VNF.AccessDetail.values().length + VNF.VnfDetail.values().length;
|
||||||
|
Assert.assertEquals(expectedLength, options.size());
|
||||||
|
Set<String> keys = options.keySet();
|
||||||
|
for (VNF.AccessDetail detail : VNF.AccessDetail.values()) {
|
||||||
|
Assert.assertTrue(keys.contains(detail.name().toLowerCase()));
|
||||||
|
}
|
||||||
|
for (VNF.VnfDetail detail : VNF.VnfDetail.values()) {
|
||||||
|
Assert.assertTrue(keys.contains(detail.name().toLowerCase()));
|
||||||
|
}
|
||||||
|
List<String> expectedAccessMethods = Arrays.stream(VNF.AccessMethod.values()).map(method -> method.toString()).sorted().collect(Collectors.toList());
|
||||||
|
Assert.assertEquals(expectedAccessMethods, options.get(VNF.AccessDetail.ACCESS_METHODS.name().toLowerCase()));
|
||||||
|
|
||||||
|
}
|
||||||
@Test
|
@Test
|
||||||
public void applyPublicTemplateRestrictionsTestDoesNotApplyRestrictionsWhenCallerIsRootAdmin() {
|
public void applyPublicTemplateRestrictionsTestDoesNotApplyRestrictionsWhenCallerIsRootAdmin() {
|
||||||
Mockito.when(accountMock.getType()).thenReturn(Account.Type.ADMIN);
|
Mockito.when(accountMock.getType()).thenReturn(Account.Type.ADMIN);
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,25 @@ package com.cloud.api.query.dao;
|
||||||
import com.cloud.api.query.vo.TemplateJoinVO;
|
import com.cloud.api.query.vo.TemplateJoinVO;
|
||||||
import com.cloud.hypervisor.Hypervisor;
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||||
import com.cloud.template.TemplateManager;
|
import com.cloud.template.TemplateManager;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||||
|
import org.apache.cloudstack.api.response.VnfTemplateResponse;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -39,6 +47,12 @@ public class TemplateJoinDaoImplTest extends GenericDaoBaseWithTagInformationBas
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private TemplateJoinDaoImpl _templateJoinDaoImpl;
|
private TemplateJoinDaoImpl _templateJoinDaoImpl;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private VnfTemplateNicDao vnfTemplateNicDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private VnfTemplateDetailsDao vnfTemplateDetailsDao;
|
||||||
|
|
||||||
private TemplateJoinVO template = new TemplateJoinVO();
|
private TemplateJoinVO template = new TemplateJoinVO();
|
||||||
private TemplateResponse templateResponse = new TemplateResponse();
|
private TemplateResponse templateResponse = new TemplateResponse();
|
||||||
|
|
||||||
|
|
@ -60,6 +74,8 @@ public class TemplateJoinDaoImplTest extends GenericDaoBaseWithTagInformationBas
|
||||||
private String domainName = "ROOT";
|
private String domainName = "ROOT";
|
||||||
private String detailName = "detail_name1";
|
private String detailName = "detail_name1";
|
||||||
private String detailValue = "detail_val";
|
private String detailValue = "detail_val";
|
||||||
|
private Storage.TemplateType templateType = Storage.TemplateType.VNF;
|
||||||
|
private Long templateId = 101L;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
@ -68,7 +84,7 @@ public class TemplateJoinDaoImplTest extends GenericDaoBaseWithTagInformationBas
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateTemplateTagInfo(){
|
public void testUpdateTemplateTagInfo() {
|
||||||
testUpdateTagInformation(_templateJoinDaoImpl, template, templateResponse);
|
testUpdateTagInformation(_templateJoinDaoImpl, template, templateResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,8 +105,8 @@ public class TemplateJoinDaoImplTest extends GenericDaoBaseWithTagInformationBas
|
||||||
Assert.assertEquals(accountName, ReflectionTestUtils.getField(response, "account"));
|
Assert.assertEquals(accountName, ReflectionTestUtils.getField(response, "account"));
|
||||||
Assert.assertEquals(domainUuid, ReflectionTestUtils.getField(response, "domainId"));
|
Assert.assertEquals(domainUuid, ReflectionTestUtils.getField(response, "domainId"));
|
||||||
Assert.assertEquals(domainName, ReflectionTestUtils.getField(response, "domainName"));
|
Assert.assertEquals(domainName, ReflectionTestUtils.getField(response, "domainName"));
|
||||||
Assert.assertTrue(((Map)ReflectionTestUtils.getField(response, "details")).containsKey(detailName));
|
Assert.assertTrue(((Map) ReflectionTestUtils.getField(response, "details")).containsKey(detailName));
|
||||||
Assert.assertEquals(detailValue, ((Map)ReflectionTestUtils.getField(response, "details")).get(detailName));
|
Assert.assertEquals(detailValue, ((Map) ReflectionTestUtils.getField(response, "details")).get(detailName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateTemplateJoinVO() {
|
private void populateTemplateJoinVO() {
|
||||||
|
|
@ -111,5 +127,27 @@ public class TemplateJoinDaoImplTest extends GenericDaoBaseWithTagInformationBas
|
||||||
ReflectionTestUtils.setField(template, "domainName", domainName);
|
ReflectionTestUtils.setField(template, "domainName", domainName);
|
||||||
ReflectionTestUtils.setField(template, "detailName", detailName);
|
ReflectionTestUtils.setField(template, "detailName", detailName);
|
||||||
ReflectionTestUtils.setField(template, "detailValue", detailValue);
|
ReflectionTestUtils.setField(template, "detailValue", detailValue);
|
||||||
|
ReflectionTestUtils.setField(template, "templateType", templateType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewUpdateResponseForVnf() {
|
||||||
|
ReflectionTestUtils.setField(template, "id", templateId);
|
||||||
|
ReflectionTestUtils.setField(template, "templateType", templateType);
|
||||||
|
|
||||||
|
VnfTemplateNicVO vnfNic1 = new VnfTemplateNicVO(templateId, 0L, "eth0", true, true, "first");
|
||||||
|
VnfTemplateNicVO vnfNic2 = new VnfTemplateNicVO(templateId, 1L, "eth1", true, true, "second");
|
||||||
|
Mockito.doReturn(Arrays.asList(vnfNic1, vnfNic2)).when(vnfTemplateNicDao).listByTemplateId(templateId);
|
||||||
|
|
||||||
|
VnfTemplateDetailVO detail1 = new VnfTemplateDetailVO(templateId, "name1", "value1", true);
|
||||||
|
VnfTemplateDetailVO detail2 = new VnfTemplateDetailVO(templateId, "name2", "value2", true);
|
||||||
|
VnfTemplateDetailVO detail3 = new VnfTemplateDetailVO(templateId, "name3", "value3", true);
|
||||||
|
Mockito.doReturn(Arrays.asList(detail1, detail2, detail3)).when(vnfTemplateDetailsDao).listDetails(templateId);
|
||||||
|
|
||||||
|
final TemplateResponse response = _templateJoinDaoImpl.newUpdateResponse(template);
|
||||||
|
Assert.assertTrue(response instanceof VnfTemplateResponse);
|
||||||
|
Assert.assertEquals(2, ((VnfTemplateResponse)response).getVnfNics().size());
|
||||||
|
Assert.assertEquals(3, ((VnfTemplateResponse)response).getVnfDetails().size());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,23 +17,78 @@
|
||||||
package com.cloud.api.query.dao;
|
package com.cloud.api.query.dao;
|
||||||
|
|
||||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.user.AccountManager;
|
||||||
|
import com.cloud.user.UserStatisticsVO;
|
||||||
|
import com.cloud.user.dao.UserDao;
|
||||||
|
import com.cloud.user.dao.UserStatisticsDao;
|
||||||
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
|
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||||
|
import org.apache.cloudstack.annotation.dao.AnnotationDao;
|
||||||
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
|
import org.apache.cloudstack.api.ResponseObject;
|
||||||
import org.apache.cloudstack.api.response.UserVmResponse;
|
import org.apache.cloudstack.api.response.UserVmResponse;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest<UserVmJoinVO, UserVmResponse> {
|
public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseTest<UserVmJoinVO, UserVmResponse> {
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private UserVmJoinDaoImpl _userVmJoinDaoImpl;
|
private UserVmJoinDaoImpl _userVmJoinDaoImpl;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private UserDao userDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AnnotationDao annotationDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private AccountManager accountMgr;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private UserVmDetailsDao _userVmDetailsDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private UserStatisticsDao userStatsDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private VnfTemplateNicDao vnfTemplateNicDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private VnfTemplateDetailsDao vnfTemplateDetailsDao;
|
||||||
|
|
||||||
private UserVmJoinVO userVm = new UserVmJoinVO();
|
private UserVmJoinVO userVm = new UserVmJoinVO();
|
||||||
private UserVmResponse userVmResponse = new UserVmResponse();
|
private UserVmResponse userVmResponse = new UserVmResponse();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
Account caller;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
UserVmJoinVO userVmMock;
|
||||||
|
|
||||||
|
private Long vmId = 100L;
|
||||||
|
|
||||||
|
private Long templateId = 101L;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
prepareSetup();
|
prepareSetup();
|
||||||
|
|
@ -50,4 +105,51 @@ public class UserVmJoinDaoImplTest extends GenericDaoBaseWithTagInformationBaseT
|
||||||
testUpdateTagInformation(_userVmJoinDaoImpl, userVm, userVmResponse);
|
testUpdateTagInformation(_userVmJoinDaoImpl, userVm, userVmResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void prepareNewUserVmResponseForVnfAppliance() {
|
||||||
|
Mockito.when(userVmMock.getId()).thenReturn(vmId);
|
||||||
|
Mockito.when(userVmMock.getTemplateId()).thenReturn(templateId);
|
||||||
|
Mockito.when(userVmMock.getTemplateType()).thenReturn(Storage.TemplateType.VNF);
|
||||||
|
|
||||||
|
Mockito.when(caller.getId()).thenReturn(2L);
|
||||||
|
Mockito.when(accountMgr.isRootAdmin(nullable(Long.class))).thenReturn(true);
|
||||||
|
|
||||||
|
SearchBuilder<UserStatisticsVO> searchBuilderMock = Mockito.mock(SearchBuilder.class);
|
||||||
|
Mockito.doReturn(searchBuilderMock).when(userStatsDao).createSearchBuilder();
|
||||||
|
UserStatisticsVO userStatisticsVOMock = Mockito.mock(UserStatisticsVO.class);
|
||||||
|
Mockito.when(searchBuilderMock.entity()).thenReturn(userStatisticsVOMock);
|
||||||
|
SearchCriteria<UserStatisticsVO> searchCriteriaMock = Mockito.mock(SearchCriteria.class);
|
||||||
|
Mockito.doReturn(searchCriteriaMock).when(searchBuilderMock).create();
|
||||||
|
Mockito.doReturn(Arrays.asList()).when(userStatsDao).search(searchCriteriaMock, null);
|
||||||
|
|
||||||
|
VnfTemplateNicVO vnfNic1 = new VnfTemplateNicVO(templateId, 0L, "eth0", true, true, "first");
|
||||||
|
VnfTemplateNicVO vnfNic2 = new VnfTemplateNicVO(templateId, 1L, "eth1", true, true, "second");
|
||||||
|
Mockito.doReturn(Arrays.asList(vnfNic1, vnfNic2)).when(vnfTemplateNicDao).listByTemplateId(templateId);
|
||||||
|
|
||||||
|
VnfTemplateDetailVO detail1 = new VnfTemplateDetailVO(templateId, "name1", "value1", true);
|
||||||
|
VnfTemplateDetailVO detail2 = new VnfTemplateDetailVO(templateId, "name2", "value2", true);
|
||||||
|
VnfTemplateDetailVO detail3 = new VnfTemplateDetailVO(templateId, "name3", "value3", true);
|
||||||
|
Mockito.doReturn(Arrays.asList(detail1, detail2, detail3)).when(vnfTemplateDetailsDao).listDetails(templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewUserVmResponseForVnfAppliance() {
|
||||||
|
prepareNewUserVmResponseForVnfAppliance();
|
||||||
|
|
||||||
|
UserVmResponse response = _userVmJoinDaoImpl.newUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVmMock,
|
||||||
|
EnumSet.of(ApiConstants.VMDetails.all), null, null, caller);
|
||||||
|
|
||||||
|
Assert.assertEquals(2, response.getVnfNics().size());
|
||||||
|
Assert.assertEquals(3, response.getVnfDetails().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNewUserVmResponseForVnfApplianceVnfNics() {
|
||||||
|
prepareNewUserVmResponseForVnfAppliance();
|
||||||
|
|
||||||
|
UserVmResponse response = _userVmJoinDaoImpl.newUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVmMock,
|
||||||
|
EnumSet.of(ApiConstants.VMDetails.vnfnics), null, null, caller);
|
||||||
|
|
||||||
|
Assert.assertEquals(2, response.getVnfNics().size());
|
||||||
|
Assert.assertEquals(3, response.getVnfDetails().size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
|
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
import org.apache.cloudstack.api.command.user.userdata.LinkUserDataToTemplateCmd;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
|
||||||
|
|
@ -68,6 +72,7 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateManager;
|
||||||
import org.apache.cloudstack.test.utils.SpringUtils;
|
import org.apache.cloudstack.test.utils.SpringUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
@ -193,6 +198,8 @@ public class TemplateManagerImplTest {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AccountManager _accountMgr;
|
AccountManager _accountMgr;
|
||||||
|
@Inject
|
||||||
|
VnfTemplateManager vnfTemplateManager;
|
||||||
|
|
||||||
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
|
||||||
AtomicInteger ai = new AtomicInteger(0);
|
AtomicInteger ai = new AtomicInteger(0);
|
||||||
|
|
@ -589,6 +596,109 @@ public class TemplateManagerImplTest {
|
||||||
Assert.assertEquals(template, resultTemplate);
|
Assert.assertEquals(template, resultTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterTemplateWithTemplateType() {
|
||||||
|
RegisterTemplateCmd cmd = Mockito.mock(RegisterTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM.toString());
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, true);
|
||||||
|
Assert.assertEquals(Storage.TemplateType.SYSTEM, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterTemplateWithoutTemplateType() {
|
||||||
|
RegisterTemplateCmd cmd = Mockito.mock(RegisterTemplateCmd.class);
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, true);
|
||||||
|
Assert.assertEquals(Storage.TemplateType.USER, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testRegisterTemplateWithSystemTemplateTypeByUser() {
|
||||||
|
RegisterVnfTemplateCmd cmd = Mockito.mock(RegisterVnfTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM.toString());
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testRegisterVnfTemplateWithTemplateType() {
|
||||||
|
RegisterVnfTemplateCmd cmd = Mockito.mock(RegisterVnfTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM.toString());
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, false, true);
|
||||||
|
Assert.assertEquals(Storage.TemplateType.VNF, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterVnfTemplateWithoutTemplateType() {
|
||||||
|
RegisterVnfTemplateCmd cmd = Mockito.mock(RegisterVnfTemplateCmd.class);
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, false, true);
|
||||||
|
Assert.assertEquals(Storage.TemplateType.VNF, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateTemplateWithTemplateType() {
|
||||||
|
UpdateTemplateCmd cmd = Mockito.mock(UpdateTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM.toString());
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, true);
|
||||||
|
Assert.assertEquals(Storage.TemplateType.SYSTEM, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateTemplateWithoutTemplateType() {
|
||||||
|
UpdateTemplateCmd cmd = Mockito.mock(UpdateTemplateCmd.class);
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, true);
|
||||||
|
Assert.assertNull(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testUpdateTemplateWithInvalidTemplateType() {
|
||||||
|
UpdateTemplateCmd cmd = Mockito.mock(UpdateTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn("invalidtype");
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testUpdateTemplateWithInvalidTemplateTypeForRouting() {
|
||||||
|
UpdateTemplateCmd cmd = Mockito.mock(UpdateTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.USER.toString());
|
||||||
|
when(cmd.isRoutingType()).thenReturn(true);
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testUpdateTemplateWithInvalidCrossZonesForSystem() {
|
||||||
|
UpdateTemplateCmd cmd = Mockito.mock(UpdateTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM.toString());
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testUpdateTemplateWithSystemTemplateTypeByUser() {
|
||||||
|
UpdateVnfTemplateCmd cmd = Mockito.mock(UpdateVnfTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM.toString());
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testUpdateVnfTemplateWithTemplateType() {
|
||||||
|
UpdateVnfTemplateCmd cmd = Mockito.mock(UpdateVnfTemplateCmd.class);
|
||||||
|
when(cmd.getTemplateType()).thenReturn(Storage.TemplateType.SYSTEM.toString());
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, false, true);
|
||||||
|
Assert.assertEquals(Storage.TemplateType.VNF, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateVnfTemplateWithoutTemplateType() {
|
||||||
|
UpdateVnfTemplateCmd cmd = Mockito.mock(UpdateVnfTemplateCmd.class);
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, false, true);
|
||||||
|
Assert.assertNull(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteTemplateWithTemplateType() {
|
||||||
|
DeleteTemplateCmd cmd = new DeleteTemplateCmd();
|
||||||
|
Storage.TemplateType type = templateManager.validateTemplateType(cmd, true, true);
|
||||||
|
Assert.assertNull(type);
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackageClasses = {TemplateManagerImpl.class},
|
@ComponentScan(basePackageClasses = {TemplateManagerImpl.class},
|
||||||
includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)},
|
includeFilters = {@ComponentScan.Filter(value = TestConfiguration.Library.class, type = FilterType.CUSTOM)},
|
||||||
|
|
@ -790,6 +900,11 @@ public class TemplateManagerImplTest {
|
||||||
return Mockito.mock(HypervisorGuruManager.class);
|
return Mockito.mock(HypervisorGuruManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public VnfTemplateManager vnfTemplateManager() {
|
||||||
|
return Mockito.mock(VnfTemplateManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SnapshotHelper snapshotHelper() {
|
public SnapshotHelper snapshotHelper() {
|
||||||
return Mockito.mock(SnapshotHelper.class);
|
return Mockito.mock(SnapshotHelper.class);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
// under the License.
|
// under the License.
|
||||||
package com.cloud.vm;
|
package com.cloud.vm;
|
||||||
|
|
||||||
|
import com.cloud.api.query.dao.ServiceOfferingJoinDao;
|
||||||
|
import com.cloud.api.query.vo.ServiceOfferingJoinVO;
|
||||||
import com.cloud.configuration.Resource;
|
import com.cloud.configuration.Resource;
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
import com.cloud.dc.DataCenterVO;
|
import com.cloud.dc.DataCenterVO;
|
||||||
|
|
@ -37,6 +39,7 @@ import com.cloud.hypervisor.Hypervisor;
|
||||||
import com.cloud.network.NetworkModel;
|
import com.cloud.network.NetworkModel;
|
||||||
import com.cloud.network.dao.NetworkDao;
|
import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
|
import com.cloud.network.security.SecurityGroupVO;
|
||||||
import com.cloud.offering.ServiceOffering;
|
import com.cloud.offering.ServiceOffering;
|
||||||
import com.cloud.server.ManagementService;
|
import com.cloud.server.ManagementService;
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
|
|
@ -44,6 +47,7 @@ import com.cloud.service.dao.ServiceOfferingDao;
|
||||||
import com.cloud.storage.DiskOfferingVO;
|
import com.cloud.storage.DiskOfferingVO;
|
||||||
import com.cloud.storage.GuestOSVO;
|
import com.cloud.storage.GuestOSVO;
|
||||||
import com.cloud.storage.ScopeType;
|
import com.cloud.storage.ScopeType;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.storage.VMTemplateVO;
|
import com.cloud.storage.VMTemplateVO;
|
||||||
import com.cloud.storage.Volume;
|
import com.cloud.storage.Volume;
|
||||||
import com.cloud.storage.VolumeApiService;
|
import com.cloud.storage.VolumeApiService;
|
||||||
|
|
@ -72,6 +76,7 @@ import com.cloud.vm.dao.UserVmDao;
|
||||||
import com.cloud.vm.dao.UserVmDetailsDao;
|
import com.cloud.vm.dao.UserVmDetailsDao;
|
||||||
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
|
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
|
||||||
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
|
||||||
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
|
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
|
||||||
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
|
||||||
|
|
@ -79,6 +84,7 @@ import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
|
||||||
|
import org.apache.cloudstack.storage.template.VnfTemplateManager;
|
||||||
import org.apache.cloudstack.userdata.UserDataManager;
|
import org.apache.cloudstack.userdata.UserDataManager;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
@ -229,10 +235,20 @@ public class UserVmManagerImplTest {
|
||||||
@Mock
|
@Mock
|
||||||
VirtualMachineProfile virtualMachineProfile;
|
VirtualMachineProfile virtualMachineProfile;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VirtualMachineTemplate templateMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VnfTemplateManager vnfTemplateManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
ServiceOfferingJoinDao serviceOfferingJoinDao;
|
||||||
|
|
||||||
private static final long vmId = 1l;
|
private static final long vmId = 1l;
|
||||||
private static final long zoneId = 2L;
|
private static final long zoneId = 2L;
|
||||||
private static final long accountId = 3L;
|
private static final long accountId = 3L;
|
||||||
private static final long serviceOfferingId = 10L;
|
private static final long serviceOfferingId = 10L;
|
||||||
|
private static final long templateId = 11L;
|
||||||
|
|
||||||
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
|
private static final long GiB_TO_BYTES = 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
@ -941,6 +957,43 @@ public class UserVmManagerImplTest {
|
||||||
userVmManagerImpl.createVirtualMachine(deployVMCmd);
|
userVmManagerImpl.createVirtualMachine(deployVMCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createVirtualMachine() throws ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException {
|
||||||
|
DeployVMCmd deployVMCmd = new DeployVMCmd();
|
||||||
|
ReflectionTestUtils.setField(deployVMCmd, "zoneId", zoneId);
|
||||||
|
ReflectionTestUtils.setField(deployVMCmd, "templateId", templateId);
|
||||||
|
ReflectionTestUtils.setField(deployVMCmd, "serviceOfferingId", serviceOfferingId);
|
||||||
|
deployVMCmd._accountService = accountService;
|
||||||
|
|
||||||
|
when(accountService.finalyzeAccountId(nullable(String.class), nullable(Long.class), nullable(Long.class), eq(true))).thenReturn(accountId);
|
||||||
|
when(accountService.getActiveAccountById(accountId)).thenReturn(account);
|
||||||
|
when(entityManager.findById(DataCenter.class, zoneId)).thenReturn(_dcMock);
|
||||||
|
when(entityManager.findById(ServiceOffering.class, serviceOfferingId)).thenReturn(serviceOffering);
|
||||||
|
when(serviceOffering.getState()).thenReturn(ServiceOffering.State.Active);
|
||||||
|
|
||||||
|
when(entityManager.findById(VirtualMachineTemplate.class, templateId)).thenReturn(templateMock);
|
||||||
|
when(templateMock.getTemplateType()).thenReturn(Storage.TemplateType.VNF);
|
||||||
|
when(templateMock.isDeployAsIs()).thenReturn(false);
|
||||||
|
when(templateMock.getFormat()).thenReturn(Storage.ImageFormat.QCOW2);
|
||||||
|
when(templateMock.getUserDataId()).thenReturn(null);
|
||||||
|
Mockito.doNothing().when(vnfTemplateManager).validateVnfApplianceNics(any(), nullable(List.class));
|
||||||
|
|
||||||
|
ServiceOfferingJoinVO svcOfferingMock = Mockito.mock(ServiceOfferingJoinVO.class);
|
||||||
|
when(serviceOfferingJoinDao.findById(anyLong())).thenReturn(svcOfferingMock);
|
||||||
|
when(_dcMock.isLocalStorageEnabled()).thenReturn(true);
|
||||||
|
when(_dcMock.getNetworkType()).thenReturn(DataCenter.NetworkType.Basic);
|
||||||
|
Mockito.doReturn(userVmVoMock).when(userVmManagerImpl).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
|
||||||
|
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), nullable(Boolean.class), any(), any(), any(),
|
||||||
|
any(), any(), any(), any(), eq(true), any());
|
||||||
|
|
||||||
|
UserVm result = userVmManagerImpl.createVirtualMachine(deployVMCmd);
|
||||||
|
assertEquals(userVmVoMock, result);
|
||||||
|
Mockito.verify(vnfTemplateManager).validateVnfApplianceNics(templateMock, null);
|
||||||
|
Mockito.verify(userVmManagerImpl).createBasicSecurityGroupVirtualMachine(any(), any(), any(), any(), any(), any(), any(),
|
||||||
|
any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), nullable(Boolean.class), any(), any(), any(),
|
||||||
|
any(), any(), any(), any(), eq(true), any());
|
||||||
|
}
|
||||||
|
|
||||||
private List<VolumeVO> mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(int localVolumes, int nonLocalVolumes) {
|
private List<VolumeVO> mockVolumesForIsAnyVmVolumeUsingLocalStorageTest(int localVolumes, int nonLocalVolumes) {
|
||||||
List<VolumeVO> volumes = new ArrayList<>();
|
List<VolumeVO> volumes = new ArrayList<>();
|
||||||
for (int i=0; i< localVolumes + nonLocalVolumes; ++i) {
|
for (int i=0; i< localVolumes + nonLocalVolumes; ++i) {
|
||||||
|
|
@ -1076,6 +1129,24 @@ public class UserVmManagerImplTest {
|
||||||
Mockito.verify(userVmDao).update(vmId, userVmVoMock);
|
Mockito.verify(userVmDao).update(vmId, userVmVoMock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSecurityGroupIdList() {
|
||||||
|
DeployVnfApplianceCmd cmd = Mockito.mock(DeployVnfApplianceCmd.class);
|
||||||
|
Mockito.doReturn(new ArrayList<Long>()).when(userVmManagerImpl).getSecurityGroupIdList(cmd);
|
||||||
|
SecurityGroupVO securityGroupVO = Mockito.mock(SecurityGroupVO.class);
|
||||||
|
long securityGroupId = 100L;
|
||||||
|
when(securityGroupVO.getId()).thenReturn(securityGroupId);
|
||||||
|
Mockito.doReturn(securityGroupVO).when(vnfTemplateManager).createSecurityGroupForVnfAppliance(any(), any(), any(), any(DeployVnfApplianceCmd.class));
|
||||||
|
|
||||||
|
List<Long> securityGroupIds = userVmManagerImpl.getSecurityGroupIdList(cmd, null, null, null);
|
||||||
|
|
||||||
|
Assert.assertEquals(1, securityGroupIds.size());
|
||||||
|
Assert.assertEquals(securityGroupId, securityGroupIds.get(0).longValue());
|
||||||
|
|
||||||
|
Mockito.verify(userVmManagerImpl).getSecurityGroupIdList(cmd);
|
||||||
|
Mockito.verify(vnfTemplateManager).createSecurityGroupForVnfAppliance(any(), any(), any(), any(DeployVnfApplianceCmd.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getCurrentVmPasswordOrDefineNewPasswordTestTemplateIsNotPasswordEnabledReturnPreDefinedString() {
|
public void getCurrentVmPasswordOrDefineNewPasswordTestTemplateIsNotPasswordEnabledReturnPreDefinedString() {
|
||||||
String expected = "saved_password";
|
String expected = "saved_password";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,389 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
package org.apache.cloudstack.storage.template;
|
||||||
|
|
||||||
|
import com.cloud.dc.DataCenter;
|
||||||
|
import com.cloud.exception.InsufficientAddressCapacityException;
|
||||||
|
import com.cloud.exception.InvalidParameterValueException;
|
||||||
|
import com.cloud.exception.NetworkRuleConflictException;
|
||||||
|
import com.cloud.exception.ResourceAllocationException;
|
||||||
|
import com.cloud.exception.ResourceUnavailableException;
|
||||||
|
import com.cloud.network.IpAddressManager;
|
||||||
|
import com.cloud.network.Network;
|
||||||
|
import com.cloud.network.NetworkModel;
|
||||||
|
import com.cloud.network.NetworkService;
|
||||||
|
import com.cloud.network.VNF;
|
||||||
|
import com.cloud.network.dao.FirewallRulesDao;
|
||||||
|
import com.cloud.network.dao.IPAddressVO;
|
||||||
|
import com.cloud.network.dao.NetworkDao;
|
||||||
|
import com.cloud.network.dao.NetworkVO;
|
||||||
|
import com.cloud.network.firewall.FirewallService;
|
||||||
|
import com.cloud.network.rules.FirewallRuleVO;
|
||||||
|
import com.cloud.network.rules.RulesService;
|
||||||
|
import com.cloud.network.security.SecurityGroup;
|
||||||
|
import com.cloud.network.security.SecurityGroupManager;
|
||||||
|
import com.cloud.network.security.SecurityGroupRuleVO;
|
||||||
|
import com.cloud.network.security.SecurityGroupService;
|
||||||
|
import com.cloud.network.security.SecurityGroupVO;
|
||||||
|
import com.cloud.storage.VnfTemplateDetailVO;
|
||||||
|
import com.cloud.storage.VnfTemplateNicVO;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateDetailsDao;
|
||||||
|
import com.cloud.storage.dao.VnfTemplateNicDao;
|
||||||
|
import com.cloud.template.VirtualMachineTemplate;
|
||||||
|
import com.cloud.user.Account;
|
||||||
|
import com.cloud.uservm.UserVm;
|
||||||
|
import com.cloud.vm.NicVO;
|
||||||
|
import com.cloud.vm.dao.NicDao;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.RegisterVnfTemplateCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.template.UpdateVnfTemplateCmd;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.api.command.user.vm.DeployVnfApplianceCmd;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class VnfTemplateManagerImplTest {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
@InjectMocks
|
||||||
|
VnfTemplateManagerImpl vnfTemplateManagerImpl;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VnfTemplateDetailsDao vnfTemplateDetailsDao;
|
||||||
|
@Mock
|
||||||
|
VnfTemplateNicDao vnfTemplateNicDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
VirtualMachineTemplate template;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NicDao nicDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NetworkDao networkDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NetworkModel networkModel;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
SecurityGroupManager securityGroupManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
SecurityGroupService securityGroupService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
NetworkService networkService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
IpAddressManager ipAddressManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
RulesService rulesService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
FirewallRulesDao firewallRulesDao;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
FirewallService firewallService;
|
||||||
|
|
||||||
|
final static long templateId = 100L;
|
||||||
|
final static long vmId = 101L;
|
||||||
|
final static long networkId = 101L;
|
||||||
|
final static long securityGroupId = 102L;
|
||||||
|
final static long zoneId = 103L;
|
||||||
|
final static long publicIpId = 104L;
|
||||||
|
final static String ipAddress = "10.10.10.10";
|
||||||
|
final static Integer sshPort = 2222;
|
||||||
|
final static Integer httpPort = 8080;
|
||||||
|
final static Integer httpsPort = 8443;
|
||||||
|
final Map<String, Object> vnfNics = new HashMap<>();
|
||||||
|
final Map<String, Object> vnfDetails = new HashMap<>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
vnfNics.put("0", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "1"),
|
||||||
|
Map.entry("name", "eth1"),
|
||||||
|
Map.entry("required", "true"),
|
||||||
|
Map.entry("description", "The second NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
vnfNics.put("1", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "2"),
|
||||||
|
Map.entry("name", "eth2"),
|
||||||
|
Map.entry("required", "false"),
|
||||||
|
Map.entry("description", "The third NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
vnfNics.put("2", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("deviceid", "0"),
|
||||||
|
Map.entry("name", "eth0"),
|
||||||
|
Map.entry("description", "The first NIC of VNF appliance")
|
||||||
|
)));
|
||||||
|
|
||||||
|
vnfDetails.put("0", new HashMap<>(Map.ofEntries(
|
||||||
|
Map.entry("accessMethods", "console,http,https"),
|
||||||
|
Map.entry("username", "admin"),
|
||||||
|
Map.entry("password", "password"),
|
||||||
|
Map.entry("version", "4.19.0"),
|
||||||
|
Map.entry("vendor", "cloudstack")
|
||||||
|
)));
|
||||||
|
|
||||||
|
VnfTemplateNicVO vnfNic1 = new VnfTemplateNicVO(templateId, 0L, "eth0", true, true, "first");
|
||||||
|
VnfTemplateNicVO vnfNic2 = new VnfTemplateNicVO(templateId, 1L, "eth1", true, true, "second");
|
||||||
|
VnfTemplateNicVO vnfNic3 = new VnfTemplateNicVO(templateId, 2L, "eth2", false, true, "third");
|
||||||
|
Mockito.doReturn(Arrays.asList(vnfNic1, vnfNic2, vnfNic3)).when(vnfTemplateNicDao).listByTemplateId(templateId);
|
||||||
|
|
||||||
|
when(template.getId()).thenReturn(templateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistVnfTemplateRegister() {
|
||||||
|
RegisterVnfTemplateCmd cmd = new RegisterVnfTemplateCmd();
|
||||||
|
ReflectionTestUtils.setField(cmd,"vnfNics", vnfNics);
|
||||||
|
ReflectionTestUtils.setField(cmd,"vnfDetails", vnfDetails);
|
||||||
|
|
||||||
|
vnfTemplateManagerImpl.persistVnfTemplate(templateId, cmd);
|
||||||
|
|
||||||
|
Mockito.verify(vnfTemplateNicDao, Mockito.times(vnfNics.size())).persist(any(VnfTemplateNicVO.class));
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(0)).removeDetails(templateId);
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(5)).addDetail(eq(templateId), anyString(), anyString(), eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistVnfTemplateUpdate() {
|
||||||
|
UpdateVnfTemplateCmd cmd = new UpdateVnfTemplateCmd();
|
||||||
|
ReflectionTestUtils.setField(cmd,"vnfNics", vnfNics);
|
||||||
|
ReflectionTestUtils.setField(cmd,"vnfDetails", vnfDetails);
|
||||||
|
|
||||||
|
vnfTemplateManagerImpl.updateVnfTemplate(templateId, cmd);
|
||||||
|
|
||||||
|
Mockito.verify(vnfTemplateNicDao, Mockito.times(vnfNics.size())).persist(any(VnfTemplateNicVO.class));
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(1)).removeDetails(templateId);
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(5)).addDetail(eq(templateId), anyString(), anyString(), eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistVnfTemplateUpdateWithoutNics() {
|
||||||
|
UpdateVnfTemplateCmd cmd = new UpdateVnfTemplateCmd();
|
||||||
|
ReflectionTestUtils.setField(cmd,"vnfDetails", vnfDetails);
|
||||||
|
ReflectionTestUtils.setField(cmd,"cleanupVnfNics", true);
|
||||||
|
|
||||||
|
vnfTemplateManagerImpl.updateVnfTemplate(templateId, cmd);
|
||||||
|
|
||||||
|
Mockito.verify(vnfTemplateNicDao, Mockito.times(1)).deleteByTemplateId(templateId);
|
||||||
|
Mockito.verify(vnfTemplateNicDao, Mockito.times(0)).persist(any(VnfTemplateNicVO.class));
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(1)).removeDetails(templateId);
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(5)).addDetail(eq(templateId), anyString(), anyString(), eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistVnfTemplateUpdateWithoutDetails() {
|
||||||
|
UpdateVnfTemplateCmd cmd = new UpdateVnfTemplateCmd();
|
||||||
|
ReflectionTestUtils.setField(cmd,"vnfNics", vnfNics);
|
||||||
|
ReflectionTestUtils.setField(cmd,"cleanupVnfDetails", true);
|
||||||
|
|
||||||
|
vnfTemplateManagerImpl.updateVnfTemplate(templateId, cmd);
|
||||||
|
|
||||||
|
Mockito.verify(vnfTemplateNicDao, Mockito.times(vnfNics.size())).persist(any(VnfTemplateNicVO.class));
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(1)).removeDetails(templateId);
|
||||||
|
Mockito.verify(vnfTemplateDetailsDao, Mockito.times(0)).addDetail(eq(templateId), anyString(), anyString(), eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateVnfApplianceNicsWithRequiredNics() {
|
||||||
|
List<Long> networkIds = Arrays.asList(200L, 201L);
|
||||||
|
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateVnfApplianceNicsWithAllNics() {
|
||||||
|
List<Long> networkIds = Arrays.asList(200L, 201L, 202L);
|
||||||
|
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateVnfApplianceNicsWithEmptyList() {
|
||||||
|
List<Long> networkIds = new ArrayList<>();
|
||||||
|
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = InvalidParameterValueException.class)
|
||||||
|
public void testValidateVnfApplianceNicsWithMissingNetworkId() {
|
||||||
|
List<Long> networkIds = Arrays.asList(200L);
|
||||||
|
vnfTemplateManagerImpl.validateVnfApplianceNics(template, networkIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetManagementNetworkAndIp() {
|
||||||
|
when(template.getId()).thenReturn(templateId);
|
||||||
|
VnfTemplateNicVO vnfNic1 = new VnfTemplateNicVO(templateId, 0L, "eth0", true, true, "first");
|
||||||
|
VnfTemplateNicVO vnfNic2 = new VnfTemplateNicVO(templateId, 1L, "eth1", true, false, "second");
|
||||||
|
VnfTemplateNicVO vnfNic3 = new VnfTemplateNicVO(templateId, 2L, "eth2", false, false, "third");
|
||||||
|
Mockito.doReturn(Arrays.asList(vnfNic1, vnfNic2, vnfNic3)).when(vnfTemplateNicDao).listByTemplateId(templateId);
|
||||||
|
|
||||||
|
UserVm vm = Mockito.mock(UserVm.class);
|
||||||
|
when(vm.getId()).thenReturn(vmId);
|
||||||
|
NicVO nic1 = Mockito.mock(NicVO.class);
|
||||||
|
NicVO nic2 = Mockito.mock(NicVO.class);
|
||||||
|
NicVO nic3 = Mockito.mock(NicVO.class);
|
||||||
|
when(nic1.getDeviceId()).thenReturn(0);
|
||||||
|
when(nic1.getIPv4Address()).thenReturn(ipAddress);
|
||||||
|
when(nic1.getNetworkId()).thenReturn(networkId);
|
||||||
|
when(nic2.getDeviceId()).thenReturn(1);
|
||||||
|
when(nic3.getDeviceId()).thenReturn(2);
|
||||||
|
Mockito.doReturn(Arrays.asList(nic1, nic2, nic3)).when(nicDao).listByVmId(vmId);
|
||||||
|
|
||||||
|
NetworkVO network = Mockito.mock(NetworkVO.class);
|
||||||
|
when(network.getId()).thenReturn(networkId);
|
||||||
|
when(network.getGuestType()).thenReturn(Network.GuestType.Isolated);
|
||||||
|
when(network.getVpcId()).thenReturn(null);
|
||||||
|
Mockito.doReturn(network).when(networkDao).findById(networkId);
|
||||||
|
when(networkModel.areServicesSupportedInNetwork(networkId, Network.Service.StaticNat)).thenReturn(true);
|
||||||
|
when(networkModel.areServicesSupportedInNetwork(networkId, Network.Service.Firewall)).thenReturn(true);
|
||||||
|
|
||||||
|
Map<Network, String> networkAndIpMap = vnfTemplateManagerImpl.getManagementNetworkAndIp(template, vm);
|
||||||
|
|
||||||
|
Assert.assertEquals(1, networkAndIpMap.size());
|
||||||
|
Assert.assertTrue(networkAndIpMap.containsKey(network));
|
||||||
|
Assert.assertTrue(networkAndIpMap.containsValue(ipAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOpenPortsForVnfAppliance() {
|
||||||
|
when(template.getId()).thenReturn(templateId);
|
||||||
|
VnfTemplateDetailVO accessMethodsDetail = Mockito.mock(VnfTemplateDetailVO.class);
|
||||||
|
when(accessMethodsDetail.getValue()).thenReturn("console,ssh-password,http,https");
|
||||||
|
when(vnfTemplateDetailsDao.findDetail(templateId, VNF.AccessDetail.ACCESS_METHODS.name().toLowerCase())).thenReturn(accessMethodsDetail);
|
||||||
|
|
||||||
|
VnfTemplateDetailVO sshPortDetail = Mockito.mock(VnfTemplateDetailVO.class);
|
||||||
|
when(sshPortDetail.getValue()).thenReturn(String.valueOf(sshPort));
|
||||||
|
when(vnfTemplateDetailsDao.findDetail(templateId, VNF.AccessDetail.SSH_PORT.name().toLowerCase())).thenReturn(sshPortDetail);
|
||||||
|
|
||||||
|
VnfTemplateDetailVO httpPortDetail = Mockito.mock(VnfTemplateDetailVO.class);
|
||||||
|
when(httpPortDetail.getValue()).thenReturn(String.valueOf(httpPort));
|
||||||
|
when(vnfTemplateDetailsDao.findDetail(templateId, VNF.AccessDetail.HTTP_PORT.name().toLowerCase())).thenReturn(httpPortDetail);
|
||||||
|
|
||||||
|
VnfTemplateDetailVO httpsPortDetail = Mockito.mock(VnfTemplateDetailVO.class);
|
||||||
|
when(httpsPortDetail.getValue()).thenReturn(String.valueOf(httpsPort));
|
||||||
|
when(vnfTemplateDetailsDao.findDetail(templateId, VNF.AccessDetail.HTTPS_PORT.name().toLowerCase())).thenReturn(httpsPortDetail);
|
||||||
|
|
||||||
|
Set<Integer> ports = vnfTemplateManagerImpl.getOpenPortsForVnfAppliance(template);
|
||||||
|
|
||||||
|
Assert.assertEquals(3, ports.size());
|
||||||
|
Assert.assertTrue(ports.contains(sshPort));
|
||||||
|
Assert.assertTrue(ports.contains(httpPort));
|
||||||
|
Assert.assertTrue(ports.contains(httpsPort));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateSecurityGroupForVnfAppliance() {
|
||||||
|
DataCenter zone = Mockito.mock(DataCenter.class);
|
||||||
|
when(zone.isSecurityGroupEnabled()).thenReturn(true);
|
||||||
|
|
||||||
|
DeployVnfApplianceCmd cmd = Mockito.mock(DeployVnfApplianceCmd.class);
|
||||||
|
when(cmd.getVnfConfigureManagement()).thenReturn(true);
|
||||||
|
when(cmd.getVnfCidrlist()).thenReturn(Arrays.asList("0.0.0.0/0"));
|
||||||
|
|
||||||
|
Set<Integer> ports = new HashSet<>();
|
||||||
|
ports.add(sshPort);
|
||||||
|
ports.add(httpPort);
|
||||||
|
ports.add(httpsPort);
|
||||||
|
Mockito.doReturn(ports).when(vnfTemplateManagerImpl).getOpenPortsForVnfAppliance(template);
|
||||||
|
|
||||||
|
Account owner = Mockito.mock(Account.class);
|
||||||
|
when(owner.getDomainId()).thenReturn(1L);
|
||||||
|
when(owner.getAccountName()).thenReturn("admin");
|
||||||
|
|
||||||
|
SecurityGroupVO securityGroupVO = Mockito.mock(SecurityGroupVO.class);
|
||||||
|
when(securityGroupVO.getId()).thenReturn(securityGroupId);
|
||||||
|
Mockito.doReturn(securityGroupVO).when(securityGroupManager).createSecurityGroup(anyString(), anyString(), anyLong(), anyLong(), anyString());
|
||||||
|
SecurityGroupRuleVO securityGroupRuleVO = Mockito.mock(SecurityGroupRuleVO.class);
|
||||||
|
Mockito.doReturn(Arrays.asList(securityGroupRuleVO)).when(securityGroupService).authorizeSecurityGroupRule(anyLong(), anyString(), anyInt(), anyInt(),
|
||||||
|
any(), any(), any(), any(), any());
|
||||||
|
|
||||||
|
SecurityGroup result = vnfTemplateManagerImpl.createSecurityGroupForVnfAppliance(zone, template, owner, cmd);
|
||||||
|
|
||||||
|
Assert.assertEquals(result, securityGroupVO);
|
||||||
|
Mockito.verify(securityGroupService, Mockito.times(3)).authorizeSecurityGroupRule(anyLong(), anyString(), anyInt(), anyInt(),
|
||||||
|
any(), any(), any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateIsolatedNetworkRulesForVnfAppliance() throws InsufficientAddressCapacityException, ResourceUnavailableException,
|
||||||
|
ResourceAllocationException, NetworkRuleConflictException {
|
||||||
|
DataCenter zone = Mockito.mock(DataCenter.class);
|
||||||
|
when(zone.getId()).thenReturn(zoneId);
|
||||||
|
Account owner = Mockito.mock(Account.class);
|
||||||
|
UserVm vm = Mockito.mock(UserVm.class);
|
||||||
|
when(vm.getId()).thenReturn(vmId);
|
||||||
|
DeployVnfApplianceCmd cmd = Mockito.mock(DeployVnfApplianceCmd.class);
|
||||||
|
|
||||||
|
Map<Network, String> networkAndIpMap = new HashMap<>();
|
||||||
|
NetworkVO network = Mockito.mock(NetworkVO.class);
|
||||||
|
when(network.getId()).thenReturn(networkId);
|
||||||
|
when(network.getVpcId()).thenReturn(null);
|
||||||
|
networkAndIpMap.put(network, ipAddress);
|
||||||
|
Mockito.doReturn(networkAndIpMap).when(vnfTemplateManagerImpl).getManagementNetworkAndIp(template, vm);
|
||||||
|
|
||||||
|
Set<Integer> ports = new HashSet<>();
|
||||||
|
ports.add(sshPort);
|
||||||
|
ports.add(httpPort);
|
||||||
|
ports.add(httpsPort);
|
||||||
|
Mockito.doReturn(ports).when(vnfTemplateManagerImpl).getOpenPortsForVnfAppliance(template);
|
||||||
|
|
||||||
|
FirewallRuleVO firewallRuleVO = Mockito.mock(FirewallRuleVO.class);
|
||||||
|
|
||||||
|
IPAddressVO publicIp = Mockito.mock(IPAddressVO.class);
|
||||||
|
when(publicIp.getId()).thenReturn(publicIpId);
|
||||||
|
when(publicIp.isSourceNat()).thenReturn(true).thenReturn(false);
|
||||||
|
Mockito.doReturn(publicIp).when(networkService).allocateIP(owner, zoneId, networkId, null, null);
|
||||||
|
Mockito.doReturn(publicIp).when(ipAddressManager).associateIPToGuestNetwork(publicIpId, networkId, false);
|
||||||
|
Mockito.doReturn(true).when(rulesService).enableStaticNat(publicIpId, vmId, networkId, ipAddress);
|
||||||
|
when(firewallRulesDao.persist(any())).thenReturn(firewallRuleVO);
|
||||||
|
Mockito.doReturn(true).when(firewallService).applyIngressFwRules(publicIpId, owner);
|
||||||
|
|
||||||
|
vnfTemplateManagerImpl.createIsolatedNetworkRulesForVnfAppliance(zone, template, owner, vm, cmd);
|
||||||
|
|
||||||
|
Mockito.verify(networkService, Mockito.times(2)).allocateIP(owner, zoneId, networkId, null, null);
|
||||||
|
Mockito.verify(ipAddressManager, Mockito.times(2)).associateIPToGuestNetwork(publicIpId, networkId, false);
|
||||||
|
Mockito.verify(rulesService, Mockito.times(1)).enableStaticNat(publicIpId, vmId, networkId, ipAddress);
|
||||||
|
Mockito.verify(firewallRulesDao, Mockito.times(3)).persist(any());
|
||||||
|
Mockito.verify(firewallService, Mockito.times(1)).applyIngressFwRules(publicIpId, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,341 @@
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you 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.
|
||||||
|
|
||||||
|
""" Smoke tests for VNF templates/appliances
|
||||||
|
"""
|
||||||
|
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||||
|
from marvin.lib.base import (Account,
|
||||||
|
Domain,
|
||||||
|
Configurations,
|
||||||
|
ServiceOffering,
|
||||||
|
VirtualMachine,
|
||||||
|
Network,
|
||||||
|
NetworkOffering,
|
||||||
|
VnfAppliance,
|
||||||
|
VnfTemplate,
|
||||||
|
Zone)
|
||||||
|
from marvin.lib.common import get_zone, get_template
|
||||||
|
from nose.plugins.attrib import attr
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
VNF_NICS = [{"deviceid": "0", "name": "WAN", "required": "true", "description": "Public WAN"},
|
||||||
|
{"deviceid": "1", "name": "LAN-1", "required": "true", "description": "Private LAN-1"}]
|
||||||
|
NEW_VNF_NICS = [{"deviceid": "0", "name": "WAN", "required": "true", "description": "Public WAN"},
|
||||||
|
{"deviceid": "1", "name": "LAN-1", "required": "true", "description": "Private LAN-1"},
|
||||||
|
{"deviceid": "2", "name": "LAN-2", "required": "false", "description": "Private LAN-2"}]
|
||||||
|
VNF_DETAILS = [{"access_methods": "console,https,http", "username": "root"}]
|
||||||
|
NEW_VNF_DETAILS = [{"access_methods": "console,https,http", "username": "root", "password": "cloudstack"}]
|
||||||
|
|
||||||
|
class TestVnfTemplates(cloudstackTestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
|
||||||
|
testClient = super(TestVnfTemplates, cls).getClsTestClient()
|
||||||
|
cls.apiclient = testClient.getApiClient()
|
||||||
|
cls._cleanup = []
|
||||||
|
cls.services = testClient.getParsedTestDataConfig()
|
||||||
|
|
||||||
|
# Get Zone, Domain and templates
|
||||||
|
cls.hypervisor = cls.testClient.getHypervisorInfo()
|
||||||
|
zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
|
||||||
|
cls.zone = Zone(zone.__dict__)
|
||||||
|
cls.template = get_template(cls.apiclient, cls.zone.id)
|
||||||
|
|
||||||
|
cls.domain = Domain.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["domain"]
|
||||||
|
)
|
||||||
|
cls._cleanup.append(cls.domain)
|
||||||
|
|
||||||
|
cls.account = Account.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["account"],
|
||||||
|
admin=True,
|
||||||
|
domainid=cls.domain.id
|
||||||
|
)
|
||||||
|
cls._cleanup.append(cls.account)
|
||||||
|
|
||||||
|
cls.user = cls.account.user[0]
|
||||||
|
cls.user_apiclient = cls.testClient.getUserApiClient(
|
||||||
|
cls.user.username, cls.domain.name
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.service_offering = ServiceOffering.create(
|
||||||
|
cls.apiclient,
|
||||||
|
cls.services["service_offerings"]["big"]
|
||||||
|
)
|
||||||
|
cls._cleanup.append(cls.service_offering)
|
||||||
|
|
||||||
|
cls.vnf_template_config = {
|
||||||
|
"name": "pfsense",
|
||||||
|
"displaytext": "pfsense",
|
||||||
|
"format": cls.template.format,
|
||||||
|
"url": cls.template.url,
|
||||||
|
"requireshvm": "True",
|
||||||
|
"ispublic": "True",
|
||||||
|
"isextractable": "True",
|
||||||
|
"hypervisor": cls.hypervisor,
|
||||||
|
"zoneid": cls.zone.id,
|
||||||
|
"ostype": "FreeBSD 12 (64-bit)",
|
||||||
|
"directdownload": False
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.initial_setting = Configurations.list(
|
||||||
|
cls.apiclient,
|
||||||
|
name="vnf.template.appliance.enabled")[0].value
|
||||||
|
|
||||||
|
Configurations.update(cls.apiclient, "vnf.template.appliance.enabled", "true")
|
||||||
|
|
||||||
|
cls.vnf_templates = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Configurations.update(cls.apiclient, "vnf.template.appliance.enabled", cls.initial_setting)
|
||||||
|
if len(cls.vnf_templates) > 0:
|
||||||
|
for vnf_template in cls.vnf_templates:
|
||||||
|
vnf_template.delete(cls.user_apiclient)
|
||||||
|
super(TestVnfTemplates, cls).tearDownClass()
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.apiclient = self.testClient.getApiClient()
|
||||||
|
self.dbclient = self.testClient.getDbConnection()
|
||||||
|
self.cleanup = []
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
super(TestVnfTemplates, self).tearDown()
|
||||||
|
|
||||||
|
def ensureVnfTemplateExists(self):
|
||||||
|
if len(self.vnf_templates) == 0:
|
||||||
|
self.vnf_template = VnfTemplate.register(self.user_apiclient,
|
||||||
|
self.vnf_template_config,
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
hypervisor=self.hypervisor,
|
||||||
|
vnfnics=VNF_NICS,
|
||||||
|
vnfdetails=VNF_DETAILS)
|
||||||
|
self.vnf_templates.append(self.vnf_template)
|
||||||
|
else:
|
||||||
|
self.vnf_template = self.vnf_templates[0]
|
||||||
|
|
||||||
|
def ensureVnfTemplateDownloaded(self):
|
||||||
|
"""Check if template download will finish in 5 minutes"""
|
||||||
|
retries = 30
|
||||||
|
interval = 10
|
||||||
|
while retries > -1:
|
||||||
|
time.sleep(interval)
|
||||||
|
templates_response = VnfTemplate.list(
|
||||||
|
self.user_apiclient,
|
||||||
|
id=self.vnf_template.id,
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
templatefilter='self'
|
||||||
|
)
|
||||||
|
template = templates_response[0]
|
||||||
|
|
||||||
|
if not hasattr(template, 'status') or not template or not template.status:
|
||||||
|
retries = retries - 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if 'Failed' in template.status:
|
||||||
|
raise Exception(
|
||||||
|
"Failed to download template: status - %s" %
|
||||||
|
template.status)
|
||||||
|
elif template.status == 'Download Complete' and template.isready:
|
||||||
|
return
|
||||||
|
elif 'Downloaded' in template.status:
|
||||||
|
retries = retries - 1
|
||||||
|
continue
|
||||||
|
elif 'Installing' not in template.status:
|
||||||
|
if retries >= 0:
|
||||||
|
retries = retries - 1
|
||||||
|
continue
|
||||||
|
raise Exception(
|
||||||
|
"Error in downloading template: status - %s" %
|
||||||
|
template.status)
|
||||||
|
else:
|
||||||
|
retries = retries - 1
|
||||||
|
raise Exception("Template download failed exception.")
|
||||||
|
|
||||||
|
@attr(tags=["advanced"], required_hardware="false")
|
||||||
|
def test_01_register_vnf_template(self):
|
||||||
|
"""Test register VNF template
|
||||||
|
"""
|
||||||
|
self.ensureVnfTemplateExists()
|
||||||
|
|
||||||
|
@attr(tags=["advanced"], required_hardware="false")
|
||||||
|
def test_02_list_vnf_template(self):
|
||||||
|
"""Test list VNF template
|
||||||
|
"""
|
||||||
|
self.ensureVnfTemplateExists()
|
||||||
|
|
||||||
|
templates_response = VnfTemplate.list(
|
||||||
|
self.user_apiclient,
|
||||||
|
id=self.vnf_template.id,
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
templatefilter='self'
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(templates_response, list) and len(templates_response) > 0:
|
||||||
|
template = templates_response[0]
|
||||||
|
self.assertEqual("VNF", template.templatetype,
|
||||||
|
"The template type of VNF template should be VNF but actually it is %s" % template.templatetype)
|
||||||
|
self.assertTrue(isinstance(template.vnfnics, list), "The template vnfnics must be a list")
|
||||||
|
self.assertEqual(2, len(template.vnfnics), "The VNF template should have 2 VNF nics")
|
||||||
|
self.assertEqual(2, len(template.vnfdetails.__dict__), "The VNF template should have 2 VNF details")
|
||||||
|
else:
|
||||||
|
self.fail("Failed to get VNF templates by listVnfTemplates API")
|
||||||
|
|
||||||
|
@attr(tags=["advanced"], required_hardware="false")
|
||||||
|
def test_03_edit_vnf_template(self):
|
||||||
|
"""Test edit VNF template
|
||||||
|
"""
|
||||||
|
self.ensureVnfTemplateExists()
|
||||||
|
|
||||||
|
self.vnf_template.update(
|
||||||
|
self.user_apiclient,
|
||||||
|
id=self.vnf_template.id,
|
||||||
|
vnfnics=NEW_VNF_NICS,
|
||||||
|
vnfdetails=NEW_VNF_DETAILS
|
||||||
|
)
|
||||||
|
|
||||||
|
templates_response = VnfTemplate.list(
|
||||||
|
self.user_apiclient,
|
||||||
|
id=self.vnf_template.id,
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
templatefilter='self'
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(templates_response, list) and len(templates_response) > 0:
|
||||||
|
template = templates_response[0]
|
||||||
|
self.assertEqual("VNF", template.templatetype,
|
||||||
|
"The template type of VNF template should be VNF but actually it is %s" % template.templatetype)
|
||||||
|
self.assertEqual(3, len(template.vnfnics), "The VNF template should have 2 VNF nics")
|
||||||
|
self.assertEqual(3, len(template.vnfdetails.__dict__), "The VNF template should have 3 VNF details")
|
||||||
|
else:
|
||||||
|
self.fail("Failed to get VNF templates by listVnfTemplates API")
|
||||||
|
|
||||||
|
@attr(tags=["advanced"], required_hardware="false")
|
||||||
|
def test_04_deploy_vnf_appliance(self):
|
||||||
|
"""Test deploy VNF appliance
|
||||||
|
"""
|
||||||
|
self.ensureVnfTemplateExists()
|
||||||
|
self.ensureVnfTemplateDownloaded()
|
||||||
|
|
||||||
|
templates_response = VnfTemplate.list(
|
||||||
|
self.user_apiclient,
|
||||||
|
id=self.vnf_template.id,
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
templatefilter='self'
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(templates_response, list) and len(templates_response) > 0:
|
||||||
|
template = templates_response[0]
|
||||||
|
if not template.isready:
|
||||||
|
self.fail("VNF template is not Ready")
|
||||||
|
else:
|
||||||
|
self.fail("Failed to find VNF template")
|
||||||
|
|
||||||
|
# Create network offerings
|
||||||
|
self.isolated_network_offering = NetworkOffering.create(
|
||||||
|
self.apiclient,
|
||||||
|
self.services["isolated_network_offering"])
|
||||||
|
self.cleanup.append(self.isolated_network_offering)
|
||||||
|
self.isolated_network_offering.update(
|
||||||
|
self.apiclient,
|
||||||
|
state='Enabled')
|
||||||
|
|
||||||
|
self.l2_network_offering = NetworkOffering.create(
|
||||||
|
self.apiclient,
|
||||||
|
self.services["l2-network_offering"])
|
||||||
|
self.cleanup.append(self.l2_network_offering)
|
||||||
|
self.l2_network_offering.update(
|
||||||
|
self.apiclient,
|
||||||
|
state='Enabled')
|
||||||
|
|
||||||
|
# Create networks
|
||||||
|
isolated_network = Network.create(
|
||||||
|
self.user_apiclient,
|
||||||
|
self.services["network"],
|
||||||
|
networkofferingid=self.isolated_network_offering.id,
|
||||||
|
zoneid=self.zone.id
|
||||||
|
)
|
||||||
|
self.cleanup.append(isolated_network)
|
||||||
|
|
||||||
|
l2_network_1 = Network.create(
|
||||||
|
self.user_apiclient,
|
||||||
|
self.services["l2-network"],
|
||||||
|
networkofferingid=self.l2_network_offering.id,
|
||||||
|
zoneid=self.zone.id
|
||||||
|
)
|
||||||
|
self.cleanup.append(l2_network_1)
|
||||||
|
|
||||||
|
l2_network_2 = Network.create(
|
||||||
|
self.user_apiclient,
|
||||||
|
self.services["l2-network"],
|
||||||
|
networkofferingid=self.l2_network_offering.id,
|
||||||
|
zoneid=self.zone.id
|
||||||
|
)
|
||||||
|
self.cleanup.append(l2_network_2)
|
||||||
|
|
||||||
|
# failed deployment
|
||||||
|
try:
|
||||||
|
self.virtual_machine = VirtualMachine.create(
|
||||||
|
self.user_apiclient,
|
||||||
|
self.services["virtual_machine"],
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
templateid=self.vnf_template.id,
|
||||||
|
accountid=self.account.name,
|
||||||
|
domainid=self.account.domainid,
|
||||||
|
serviceofferingid=self.service_offering.id,
|
||||||
|
networkids=[isolated_network.id]
|
||||||
|
)
|
||||||
|
self.cleanup.append(self.virtual_machine)
|
||||||
|
self.fail("The deployment should fail")
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# success deployment
|
||||||
|
self.vnf_appliance = VnfAppliance.create(
|
||||||
|
self.user_apiclient,
|
||||||
|
self.services["virtual_machine"],
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
templateid=self.vnf_template.id,
|
||||||
|
accountid=self.account.name,
|
||||||
|
domainid=self.account.domainid,
|
||||||
|
serviceofferingid=self.service_offering.id,
|
||||||
|
networkids=[isolated_network.id, l2_network_1.id, l2_network_2.id],
|
||||||
|
vnfconfiguremanagement='true'
|
||||||
|
)
|
||||||
|
self.cleanup.append(self.vnf_appliance)
|
||||||
|
|
||||||
|
@attr(tags=["advanced"], required_hardware="false")
|
||||||
|
def test_05_delete_vnf_template(self):
|
||||||
|
"""Test delete VNF template
|
||||||
|
"""
|
||||||
|
self.ensureVnfTemplateExists()
|
||||||
|
|
||||||
|
self.vnf_template.delete(self.user_apiclient)
|
||||||
|
|
||||||
|
templates_response = VnfTemplate.list(
|
||||||
|
self.user_apiclient,
|
||||||
|
id=self.vnf_template.id,
|
||||||
|
zoneid=self.zone.id,
|
||||||
|
templatefilter='self'
|
||||||
|
)
|
||||||
|
self.assertIsNone(templates_response, "The VNF template should be removed")
|
||||||
|
|
||||||
|
self.vnf_templates.remove(self.vnf_template)
|
||||||
|
|
@ -50,6 +50,7 @@ known_categories = {
|
||||||
'SystemVm': 'System VM',
|
'SystemVm': 'System VM',
|
||||||
'VirtualMachine': 'Virtual Machine',
|
'VirtualMachine': 'Virtual Machine',
|
||||||
'VM': 'Virtual Machine',
|
'VM': 'Virtual Machine',
|
||||||
|
'Vnf': 'Virtual Network Functions',
|
||||||
'Domain': 'Domain',
|
'Domain': 'Domain',
|
||||||
'Template': 'Template',
|
'Template': 'Template',
|
||||||
'Iso': 'ISO',
|
'Iso': 'ISO',
|
||||||
|
|
|
||||||
|
|
@ -6731,3 +6731,315 @@ class VMSchedule:
|
||||||
cmd.id = self.id
|
cmd.id = self.id
|
||||||
cmd.virtualmachineid = self.virtualmachineid
|
cmd.virtualmachineid = self.virtualmachineid
|
||||||
return (apiclient.deleteVMSchedule(cmd))
|
return (apiclient.deleteVMSchedule(cmd))
|
||||||
|
|
||||||
|
class VnfTemplate:
|
||||||
|
"""Manage VNF template life cycle"""
|
||||||
|
|
||||||
|
def __init__(self, items):
|
||||||
|
self.__dict__.update(items)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def register(cls, apiclient, services, zoneid=None,
|
||||||
|
account=None, domainid=None, hypervisor=None,
|
||||||
|
projectid=None, details=None, randomize_name=True,
|
||||||
|
vnfnics=None, vnfdetails=None):
|
||||||
|
"""Create VNF template from URL"""
|
||||||
|
|
||||||
|
# Create template from Virtual machine and Volume ID
|
||||||
|
cmd = registerVnfTemplate.registerVnfTemplateCmd()
|
||||||
|
cmd.displaytext = services["displaytext"]
|
||||||
|
if randomize_name:
|
||||||
|
cmd.name = "-".join([services["name"], random_gen()])
|
||||||
|
else:
|
||||||
|
cmd.name = services["name"]
|
||||||
|
cmd.format = services["format"]
|
||||||
|
if hypervisor:
|
||||||
|
cmd.hypervisor = hypervisor
|
||||||
|
elif "hypervisor" in services:
|
||||||
|
cmd.hypervisor = services["hypervisor"]
|
||||||
|
|
||||||
|
if "ostypeid" in services:
|
||||||
|
cmd.ostypeid = services["ostypeid"]
|
||||||
|
elif "ostype" in services:
|
||||||
|
# Find OSTypeId from Os type
|
||||||
|
sub_cmd = listOsTypes.listOsTypesCmd()
|
||||||
|
sub_cmd.description = services["ostype"]
|
||||||
|
ostypes = apiclient.listOsTypes(sub_cmd)
|
||||||
|
|
||||||
|
if not isinstance(ostypes, list):
|
||||||
|
raise Exception(
|
||||||
|
"Unable to find Ostype id with desc: %s" %
|
||||||
|
services["ostype"])
|
||||||
|
cmd.ostypeid = ostypes[0].id
|
||||||
|
else:
|
||||||
|
raise Exception(
|
||||||
|
"Unable to find Ostype is required for registering template")
|
||||||
|
|
||||||
|
cmd.url = services["url"]
|
||||||
|
|
||||||
|
if zoneid:
|
||||||
|
cmd.zoneid = zoneid
|
||||||
|
else:
|
||||||
|
cmd.zoneid = services["zoneid"]
|
||||||
|
|
||||||
|
cmd.isfeatured = services[
|
||||||
|
"isfeatured"] if "isfeatured" in services else False
|
||||||
|
cmd.ispublic = services[
|
||||||
|
"ispublic"] if "ispublic" in services else False
|
||||||
|
cmd.isextractable = services[
|
||||||
|
"isextractable"] if "isextractable" in services else False
|
||||||
|
cmd.isdynamicallyscalable = services["isdynamicallyscalable"] if "isdynamicallyscalable" in services else False
|
||||||
|
cmd.passwordenabled = services[
|
||||||
|
"passwordenabled"] if "passwordenabled" in services else False
|
||||||
|
cmd.deployasis = services["deployasis"] if "deployasis" in services else False
|
||||||
|
|
||||||
|
if account:
|
||||||
|
cmd.account = account
|
||||||
|
|
||||||
|
if domainid:
|
||||||
|
cmd.domainid = domainid
|
||||||
|
|
||||||
|
if projectid:
|
||||||
|
cmd.projectid = projectid
|
||||||
|
elif "projectid" in services:
|
||||||
|
cmd.projectid = services["projectid"]
|
||||||
|
|
||||||
|
if details:
|
||||||
|
cmd.details = details
|
||||||
|
|
||||||
|
if "directdownload" in services:
|
||||||
|
cmd.directdownload = services["directdownload"]
|
||||||
|
|
||||||
|
if vnfnics:
|
||||||
|
cmd.vnfnics = vnfnics
|
||||||
|
|
||||||
|
if vnfdetails:
|
||||||
|
cmd.vnfdetails = vnfdetails
|
||||||
|
|
||||||
|
# Register Template
|
||||||
|
template = apiclient.registerVnfTemplate(cmd)
|
||||||
|
|
||||||
|
if isinstance(template, list):
|
||||||
|
return VnfTemplate(template[0].__dict__)
|
||||||
|
|
||||||
|
def delete(self, apiclient, zoneid=None):
|
||||||
|
"""Delete VNF Template"""
|
||||||
|
|
||||||
|
cmd = deleteVnfTemplate.deleteVnfTemplateCmd()
|
||||||
|
cmd.id = self.id
|
||||||
|
if zoneid:
|
||||||
|
cmd.zoneid = zoneid
|
||||||
|
apiclient.deleteVnfTemplate(cmd)
|
||||||
|
|
||||||
|
def update(self, apiclient, **kwargs):
|
||||||
|
"""Updates the template details"""
|
||||||
|
|
||||||
|
cmd = updateVnfTemplate.updateVnfTemplateCmd()
|
||||||
|
cmd.id = self.id
|
||||||
|
[setattr(cmd, k, v) for k, v in list(kwargs.items())]
|
||||||
|
return (apiclient.updateVnfTemplate(cmd))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def list(cls, apiclient, **kwargs):
|
||||||
|
"""List all templates matching criteria"""
|
||||||
|
|
||||||
|
cmd = listVnfTemplates.listVnfTemplatesCmd()
|
||||||
|
[setattr(cmd, k, v) for k, v in list(kwargs.items())]
|
||||||
|
if 'account' in list(kwargs.keys()) and 'domainid' in list(kwargs.keys()):
|
||||||
|
cmd.listall = True
|
||||||
|
return (apiclient.listVnfTemplates(cmd))
|
||||||
|
|
||||||
|
class VnfAppliance:
|
||||||
|
"""Manage VNF Appliance life cycle"""
|
||||||
|
|
||||||
|
def __init__(self, items):
|
||||||
|
self.__dict__.update(items)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, apiclient, services, templateid=None, accountid=None,
|
||||||
|
domainid=None, zoneid=None, networkids=None,
|
||||||
|
serviceofferingid=None, securitygroupids=None,
|
||||||
|
projectid=None, startvm=None, diskofferingid=None,
|
||||||
|
affinitygroupnames=None, affinitygroupids=None, group=None,
|
||||||
|
hostid=None, clusterid=None, keypair=None, ipaddress=None, mode='default',
|
||||||
|
method='GET', hypervisor=None, customcpunumber=None,
|
||||||
|
customcpuspeed=None, custommemory=None, rootdisksize=None,
|
||||||
|
rootdiskcontroller=None, vpcid=None, macaddress=None, datadisktemplate_diskoffering_list={},
|
||||||
|
properties=None, nicnetworklist=None, bootmode=None, boottype=None, dynamicscalingenabled=None,
|
||||||
|
userdataid=None, userdatadetails=None, extraconfig=None,
|
||||||
|
vnfconfiguremanagement=None, vnfcidrlist=None):
|
||||||
|
"""Create the VNF appliance"""
|
||||||
|
|
||||||
|
cmd = deployVnfAppliance.deployVnfApplianceCmd()
|
||||||
|
|
||||||
|
if serviceofferingid:
|
||||||
|
cmd.serviceofferingid = serviceofferingid
|
||||||
|
elif "serviceoffering" in services:
|
||||||
|
cmd.serviceofferingid = services["serviceoffering"]
|
||||||
|
|
||||||
|
if zoneid:
|
||||||
|
cmd.zoneid = zoneid
|
||||||
|
elif "zoneid" in services:
|
||||||
|
cmd.zoneid = services["zoneid"]
|
||||||
|
|
||||||
|
if hypervisor:
|
||||||
|
cmd.hypervisor = hypervisor
|
||||||
|
|
||||||
|
if "displayname" in services:
|
||||||
|
cmd.displayname = services["displayname"]
|
||||||
|
|
||||||
|
if "name" in services:
|
||||||
|
cmd.name = services["name"]
|
||||||
|
|
||||||
|
if accountid:
|
||||||
|
cmd.account = accountid
|
||||||
|
elif "account" in services:
|
||||||
|
cmd.account = services["account"]
|
||||||
|
|
||||||
|
if domainid:
|
||||||
|
cmd.domainid = domainid
|
||||||
|
elif "domainid" in services:
|
||||||
|
cmd.domainid = services["domainid"]
|
||||||
|
|
||||||
|
if networkids:
|
||||||
|
cmd.networkids = networkids
|
||||||
|
allow_egress = False
|
||||||
|
elif "networkids" in services:
|
||||||
|
cmd.networkids = services["networkids"]
|
||||||
|
allow_egress = False
|
||||||
|
else:
|
||||||
|
# When no networkids are passed, network
|
||||||
|
# is created using the "defaultOfferingWithSourceNAT"
|
||||||
|
# which has an egress policy of DENY. But guests in tests
|
||||||
|
# need access to test network connectivity
|
||||||
|
allow_egress = True
|
||||||
|
|
||||||
|
if templateid:
|
||||||
|
cmd.templateid = templateid
|
||||||
|
elif "template" in services:
|
||||||
|
cmd.templateid = services["template"]
|
||||||
|
|
||||||
|
if diskofferingid:
|
||||||
|
cmd.diskofferingid = diskofferingid
|
||||||
|
elif "diskoffering" in services:
|
||||||
|
cmd.diskofferingid = services["diskoffering"]
|
||||||
|
|
||||||
|
if keypair:
|
||||||
|
cmd.keypair = keypair
|
||||||
|
elif "keypair" in services:
|
||||||
|
cmd.keypair = services["keypair"]
|
||||||
|
|
||||||
|
if ipaddress:
|
||||||
|
cmd.ipaddress = ipaddress
|
||||||
|
elif "ipaddress" in services:
|
||||||
|
cmd.ipaddress = services["ipaddress"]
|
||||||
|
|
||||||
|
if securitygroupids:
|
||||||
|
cmd.securitygroupids = [str(sg_id) for sg_id in securitygroupids]
|
||||||
|
|
||||||
|
if "affinitygroupnames" in services:
|
||||||
|
cmd.affinitygroupnames = services["affinitygroupnames"]
|
||||||
|
elif affinitygroupnames:
|
||||||
|
cmd.affinitygroupnames = affinitygroupnames
|
||||||
|
|
||||||
|
if affinitygroupids:
|
||||||
|
cmd.affinitygroupids = affinitygroupids
|
||||||
|
|
||||||
|
if projectid:
|
||||||
|
cmd.projectid = projectid
|
||||||
|
|
||||||
|
if startvm is not None:
|
||||||
|
cmd.startvm = startvm
|
||||||
|
|
||||||
|
if hostid:
|
||||||
|
cmd.hostid = hostid
|
||||||
|
|
||||||
|
if clusterid:
|
||||||
|
cmd.clusterid = clusterid
|
||||||
|
|
||||||
|
if "userdata" in services:
|
||||||
|
cmd.userdata = base64.urlsafe_b64encode(services["userdata"].encode()).decode()
|
||||||
|
|
||||||
|
if userdataid is not None:
|
||||||
|
cmd.userdataid = userdataid
|
||||||
|
|
||||||
|
if userdatadetails is not None:
|
||||||
|
cmd.userdatadetails = userdatadetails
|
||||||
|
|
||||||
|
if "dhcpoptionsnetworklist" in services:
|
||||||
|
cmd.dhcpoptionsnetworklist = services["dhcpoptionsnetworklist"]
|
||||||
|
|
||||||
|
if dynamicscalingenabled is not None:
|
||||||
|
cmd.dynamicscalingenabled = dynamicscalingenabled
|
||||||
|
|
||||||
|
cmd.details = [{}]
|
||||||
|
|
||||||
|
if customcpunumber:
|
||||||
|
cmd.details[0]["cpuNumber"] = customcpunumber
|
||||||
|
|
||||||
|
if customcpuspeed:
|
||||||
|
cmd.details[0]["cpuSpeed"] = customcpuspeed
|
||||||
|
|
||||||
|
if custommemory:
|
||||||
|
cmd.details[0]["memory"] = custommemory
|
||||||
|
|
||||||
|
if not rootdisksize is None and rootdisksize >= 0:
|
||||||
|
cmd.details[0]["rootdisksize"] = rootdisksize
|
||||||
|
|
||||||
|
if rootdiskcontroller:
|
||||||
|
cmd.details[0]["rootDiskController"] = rootdiskcontroller
|
||||||
|
|
||||||
|
if "size" in services:
|
||||||
|
cmd.size = services["size"]
|
||||||
|
|
||||||
|
if group:
|
||||||
|
cmd.group = group
|
||||||
|
|
||||||
|
cmd.datadisktemplatetodiskofferinglist = []
|
||||||
|
for datadisktemplate, diskoffering in list(datadisktemplate_diskoffering_list.items()):
|
||||||
|
cmd.datadisktemplatetodiskofferinglist.append({
|
||||||
|
'datadisktemplateid': datadisktemplate,
|
||||||
|
'diskofferingid': diskoffering
|
||||||
|
})
|
||||||
|
|
||||||
|
# program default access to ssh
|
||||||
|
if mode.lower() == 'basic':
|
||||||
|
cls.ssh_access_group(apiclient, cmd)
|
||||||
|
|
||||||
|
if macaddress:
|
||||||
|
cmd.macaddress = macaddress
|
||||||
|
elif macaddress in services:
|
||||||
|
cmd.macaddress = services["macaddress"]
|
||||||
|
|
||||||
|
if properties:
|
||||||
|
cmd.properties = properties
|
||||||
|
|
||||||
|
if nicnetworklist:
|
||||||
|
cmd.nicnetworklist = nicnetworklist
|
||||||
|
|
||||||
|
if bootmode:
|
||||||
|
cmd.bootmode = bootmode
|
||||||
|
|
||||||
|
if boottype:
|
||||||
|
cmd.boottype = boottype
|
||||||
|
|
||||||
|
if extraconfig:
|
||||||
|
cmd.extraconfig = extraconfig
|
||||||
|
|
||||||
|
if vnfconfiguremanagement:
|
||||||
|
cmd.vnfconfiguremanagement = vnfconfiguremanagement
|
||||||
|
|
||||||
|
if vnfcidrlist:
|
||||||
|
cmd.vnfcidrlist = vnfcidrlist
|
||||||
|
|
||||||
|
vnf_app = apiclient.deployVnfAppliance(cmd, method=method)
|
||||||
|
|
||||||
|
return VnfAppliance(vnf_app.__dict__)
|
||||||
|
|
||||||
|
def delete(self, apiclient, expunge=True, **kwargs):
|
||||||
|
"""Destroy an VNF appliance"""
|
||||||
|
cmd = destroyVirtualMachine.destroyVirtualMachineCmd()
|
||||||
|
cmd.id = self.id
|
||||||
|
cmd.expunge = expunge
|
||||||
|
[setattr(cmd, k, v) for k, v in list(kwargs.items())]
|
||||||
|
apiclient.destroyVirtualMachine(cmd)
|
||||||
|
|
|
||||||
|
|
@ -372,6 +372,7 @@
|
||||||
"label.back": "Back",
|
"label.back": "Back",
|
||||||
"label.backup": "Backups",
|
"label.backup": "Backups",
|
||||||
"label.backup.attach.restore": "Restore and attach backup volume",
|
"label.backup.attach.restore": "Restore and attach backup volume",
|
||||||
|
"label.backup.configure.schedule": "Configure Backup Schedule",
|
||||||
"label.backup.offering.assign": "Assign VM to backup offering",
|
"label.backup.offering.assign": "Assign VM to backup offering",
|
||||||
"label.backup.offering.remove": "Remove VM from backup offering",
|
"label.backup.offering.remove": "Remove VM from backup offering",
|
||||||
"label.backup.offerings": "Backup offerings",
|
"label.backup.offerings": "Backup offerings",
|
||||||
|
|
@ -1151,6 +1152,8 @@
|
||||||
"label.launch": "Launch",
|
"label.launch": "Launch",
|
||||||
"label.launch.vm": "Launch instance",
|
"label.launch.vm": "Launch instance",
|
||||||
"label.launch.vm.and.stay": "Launch instance & stay on this page",
|
"label.launch.vm.and.stay": "Launch instance & stay on this page",
|
||||||
|
"label.launch.vnf.appliance": "Launch VNF appliance",
|
||||||
|
"label.launch.vnf.appliance.and.stay": "Launch VNF appliance & stay on this page",
|
||||||
"label.launch.zone": "Launch zone",
|
"label.launch.zone": "Launch zone",
|
||||||
"label.lb.algorithm.leastconn": "Least connections",
|
"label.lb.algorithm.leastconn": "Least connections",
|
||||||
"label.lb.algorithm.roundrobin": "Round-robin",
|
"label.lb.algorithm.roundrobin": "Round-robin",
|
||||||
|
|
@ -1460,6 +1463,7 @@
|
||||||
"label.parentname": "Parent",
|
"label.parentname": "Parent",
|
||||||
"label.passive": "Passive",
|
"label.passive": "Passive",
|
||||||
"label.password": "Password",
|
"label.password": "Password",
|
||||||
|
"label.password.default": "Default Password",
|
||||||
"label.password.reset.confirm": "Password has been reset to ",
|
"label.password.reset.confirm": "Password has been reset to ",
|
||||||
"label.passwordenabled": "Password enabled",
|
"label.passwordenabled": "Password enabled",
|
||||||
"label.path": "Path",
|
"label.path": "Path",
|
||||||
|
|
@ -2191,6 +2195,42 @@
|
||||||
"label.vmwaredcname": "VMware datacenter name",
|
"label.vmwaredcname": "VMware datacenter name",
|
||||||
"label.vmwaredcvcenter": "VMware datacenter vCenter",
|
"label.vmwaredcvcenter": "VMware datacenter vCenter",
|
||||||
"label.vmwarenetworklabel": "VMware traffic label",
|
"label.vmwarenetworklabel": "VMware traffic label",
|
||||||
|
"label.vnf.appliance": "VNF Appliance",
|
||||||
|
"label.vnf.appliances": "VNF appliances",
|
||||||
|
"label.vnf.appliance.add": "Add VNF Appliance",
|
||||||
|
"label.vnf.appliance.access.methods": "Management access information of this VNF appliance",
|
||||||
|
"label.vnf.app.action.destroy": "Destroy VNF appliance",
|
||||||
|
"label.vnf.app.action.edit": "Edit VNF appliance",
|
||||||
|
"label.vnf.app.action.expunge": "Expunge VNF appliance",
|
||||||
|
"label.vnf.app.action.migrate.to.host": "Migrate VNF appliance to another host",
|
||||||
|
"label.vnf.app.action.migrate.to.ps": "Migrate VNF appliance to another primary storage",
|
||||||
|
"label.vnf.app.action.recover": "Recover VNF appliance",
|
||||||
|
"label.vnf.app.action.scale": "Scale VNF appliance",
|
||||||
|
"label.vnf.app.action.start": "Start VNF appliance",
|
||||||
|
"label.vnf.app.action.stop": "Stop VNF appliance",
|
||||||
|
"label.vnf.app.action.reboot": "Reboot VNF appliance",
|
||||||
|
"label.vnf.app.action.reinstall": "Reinstall VNF appliance",
|
||||||
|
"label.vnf.cidr.list": "Source cidr list of rules",
|
||||||
|
"label.vnf.cidr.list.tooltip": "the CIDR list to forward traffic from to the VNF management interface. Multiple entries must be separated by a single comma character (,). The default value is 0.0.0.0/0.",
|
||||||
|
"label.vnf.configure.management": "Configure rules for VNF management interfaces",
|
||||||
|
"label.vnf.configure.management.tooltip": "True by default, security group or network rules (source nat and firewall rules) will be configured for VNF management interfaces. False otherwise.",
|
||||||
|
"label.vnf.detail.add": "Add VNF detail",
|
||||||
|
"label.vnf.detail.remove": "Remove VNF detail",
|
||||||
|
"label.vnf.details": "VNF details",
|
||||||
|
"label.vnf.nic.add": "Add VNF nic",
|
||||||
|
"label.vnf.nic.delete": "Delete VNF nic",
|
||||||
|
"label.vnf.nic.description": "Description of VNF nic",
|
||||||
|
"label.vnf.nic.deviceid": "Device ID of VNF nic. It starts with 0",
|
||||||
|
"label.vnf.nic.edit": "Edit VNF nic",
|
||||||
|
"label.vnf.nic.management": "Management NIC",
|
||||||
|
"label.vnf.nic.management.description": "True if the VNF nic is a management interface. False otherwise",
|
||||||
|
"label.vnf.nic.name": "Name of VNF nic",
|
||||||
|
"label.vnf.nic.remove": "Remove VNF nic",
|
||||||
|
"label.vnf.nic.required": "True if VNF nic is required. Otherwise optional",
|
||||||
|
"label.vnf.nics": "VNF nics",
|
||||||
|
"label.vnf.settings": "VNF settings",
|
||||||
|
"label.vnf.templates": "VNF templates",
|
||||||
|
"label.vnf.template.register": "Register VNF template",
|
||||||
"label.vnmc": "VNMC",
|
"label.vnmc": "VNMC",
|
||||||
"label.volgroup": "Volume group",
|
"label.volgroup": "Volume group",
|
||||||
"label.volume": "Volume",
|
"label.volume": "Volume",
|
||||||
|
|
@ -3145,6 +3185,17 @@
|
||||||
"message.vm.state.stopped": "VM is stopped.",
|
"message.vm.state.stopped": "VM is stopped.",
|
||||||
"message.vm.state.stopping": "VM is being stopped.",
|
"message.vm.state.stopping": "VM is being stopped.",
|
||||||
"message.vm.state.unknown": "VM state is unknown.",
|
"message.vm.state.unknown": "VM state is unknown.",
|
||||||
|
"message.vnf.appliance.networks": "Please select networks for the new VNF appliance.",
|
||||||
|
"message.vnf.credentials.change": "Please change the password(s) of the VNF appliance immediately.",
|
||||||
|
"message.vnf.credentials.default": "The default credentials(s) of the VNF appliance",
|
||||||
|
"message.vnf.credentials.in.template.vnf.details": "Please find the default credentials for this VNF in the details of the VNF template.",
|
||||||
|
"message.vnf.error.deviceid.should.be.continuous": "The deviceid of selected VNF nics should be continuous.",
|
||||||
|
"message.vnf.error.network.is.already.used": "Network has been used by multiple nics of the new VNF appliance.",
|
||||||
|
"message.vnf.error.no.networks": "Please select networks for nics of the new VNF appliance.",
|
||||||
|
"message.vnf.error.no.network.for.required.deviceid": "Please select a network for required nic of the new VNF appliance.",
|
||||||
|
"message.vnf.nic.move.up.fail": "Failed to move up this NIC",
|
||||||
|
"message.vnf.nic.move.down.fail": "Failed to move down this NIC",
|
||||||
|
"message.vnf.select.networks": "Please select a network for each VNF nic. ",
|
||||||
"message.volume.state.allocated": "The volume is allocated but has not been created yet.",
|
"message.volume.state.allocated": "The volume is allocated but has not been created yet.",
|
||||||
"message.volume.state.attaching": "The volume is attaching to a volume from Ready state.",
|
"message.volume.state.attaching": "The volume is attaching to a volume from Ready state.",
|
||||||
"message.volume.state.copying": "The volume is being copied from the image store to primary storage, in case it's an uploaded volume.",
|
"message.volume.state.copying": "The volume is being copied from the image store to primary storage, in case it's an uploaded volume.",
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,11 @@
|
||||||
<p v-html="ip6routes" />
|
<p v-html="ip6routes" />
|
||||||
</template>
|
</template>
|
||||||
</a-alert>
|
</a-alert>
|
||||||
|
<a-alert v-if="vnfAccessMethods" type="info" :showIcon="true" :message="$t('label.vnf.appliance.access.methods')">
|
||||||
|
<template #description>
|
||||||
|
<p v-html="vnfAccessMethods" />
|
||||||
|
</template>
|
||||||
|
</a-alert>
|
||||||
<a-list
|
<a-list
|
||||||
size="small"
|
size="small"
|
||||||
:dataSource="fetchDetails()">
|
:dataSource="fetchDetails()">
|
||||||
|
|
@ -159,11 +164,99 @@ export default {
|
||||||
customDisplayItems () {
|
customDisplayItems () {
|
||||||
return ['ip6routes', 'privatemtu', 'publicmtu']
|
return ['ip6routes', 'privatemtu', 'publicmtu']
|
||||||
},
|
},
|
||||||
|
vnfAccessMethods () {
|
||||||
|
if (this.resource.templatetype === 'VNF' && ['vm', 'vnfapp'].includes(this.$route.meta.name)) {
|
||||||
|
const accessMethodsDescription = []
|
||||||
|
const accessMethods = this.resource.vnfdetails?.access_methods || null
|
||||||
|
const username = this.resource.vnfdetails?.username || null
|
||||||
|
const password = this.resource.vnfdetails?.password || null
|
||||||
|
const sshPort = this.resource.vnfdetails?.ssh_port || 22
|
||||||
|
const sshUsername = this.resource.vnfdetails?.ssh_user || null
|
||||||
|
const sshPassword = this.resource.vnfdetails?.ssh_password || null
|
||||||
|
let httpPath = this.resource.vnfdetails?.http_path || ''
|
||||||
|
if (!httpPath.startsWith('/')) {
|
||||||
|
httpPath = '/' + httpPath
|
||||||
|
}
|
||||||
|
const httpPort = this.resource.vnfdetails?.http_port || null
|
||||||
|
let httpsPath = this.resource.vnfdetails?.https_path || ''
|
||||||
|
if (!httpsPath.startsWith('/')) {
|
||||||
|
httpsPath = '/' + httpsPath
|
||||||
|
}
|
||||||
|
const httpsPort = this.resource.vnfdetails?.https_port || null
|
||||||
|
const webUsername = this.resource.vnfdetails?.web_user || null
|
||||||
|
const webPassword = this.resource.vnfdetails?.web_password || null
|
||||||
|
|
||||||
|
const credentials = []
|
||||||
|
if (username) {
|
||||||
|
credentials.push(this.$t('label.username') + ' : ' + username)
|
||||||
|
}
|
||||||
|
if (password) {
|
||||||
|
credentials.push(this.$t('label.password.default') + ' : ' + password)
|
||||||
|
}
|
||||||
|
if (webUsername) {
|
||||||
|
credentials.push('Web ' + this.$t('label.username') + ' : ' + webUsername)
|
||||||
|
}
|
||||||
|
if (webPassword) {
|
||||||
|
credentials.push('Web ' + this.$t('label.password.default') + ' : ' + webPassword)
|
||||||
|
}
|
||||||
|
if (sshUsername) {
|
||||||
|
credentials.push('SSH ' + this.$t('label.username') + ' : ' + sshUsername)
|
||||||
|
}
|
||||||
|
if (sshPassword) {
|
||||||
|
credentials.push('SSH ' + this.$t('label.password.default') + ' : ' + sshPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
const managementDeviceIds = []
|
||||||
|
for (const vnfnic of this.resource.vnfnics) {
|
||||||
|
if (vnfnic.management) {
|
||||||
|
managementDeviceIds.push(vnfnic.deviceid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const managementIps = []
|
||||||
|
for (const nic of this.resource.nic) {
|
||||||
|
if (managementDeviceIds.includes(parseInt(nic.deviceid)) && nic.ipaddress) {
|
||||||
|
managementIps.push(nic.ipaddress)
|
||||||
|
if (nic.publicip) {
|
||||||
|
managementIps.push(nic.publicip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accessMethods) {
|
||||||
|
const accessMethodsArray = accessMethods.split(',')
|
||||||
|
for (const accessMethod of accessMethodsArray) {
|
||||||
|
if (accessMethod === 'console') {
|
||||||
|
accessMethodsDescription.push('- VM Console.')
|
||||||
|
} else if (accessMethod === 'ssh-password') {
|
||||||
|
accessMethodsDescription.push('- SSH with password' + (sshPort ? ' (SSH port is ' + sshPort + ').' : '.'))
|
||||||
|
} else if (accessMethod === 'ssh-key') {
|
||||||
|
accessMethodsDescription.push('- SSH with key' + (sshPort ? ' (SSH port is ' + sshPort + ').' : '.'))
|
||||||
|
} else if (accessMethod === 'http') {
|
||||||
|
for (const managementIp of managementIps) {
|
||||||
|
const url = 'http://' + managementIp + (httpPort ? ':' + httpPort : '') + httpPath
|
||||||
|
accessMethodsDescription.push('- Webpage: <a href="' + url + '" target="_blank>">' + url + '</a>')
|
||||||
|
}
|
||||||
|
} else if (accessMethod === 'https') {
|
||||||
|
for (const managementIp of managementIps) {
|
||||||
|
const url = 'https://' + managementIp + (httpsPort ? ':' + httpsPort : '') + httpsPath
|
||||||
|
accessMethodsDescription.push('- Webpage: <a href="' + url + '" target="_blank">' + url + '</a>')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
accessMethodsDescription.push('- VM Console.')
|
||||||
|
}
|
||||||
|
if (credentials) {
|
||||||
|
accessMethodsDescription.push('<br>' + this.$t('message.vnf.credentials.in.template.vnf.details'))
|
||||||
|
}
|
||||||
|
return accessMethodsDescription.join('<br>')
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
ipV6Address () {
|
ipV6Address () {
|
||||||
if (this.dataResource.nic && this.dataResource.nic.length > 0) {
|
if (this.dataResource.nic && this.dataResource.nic.length > 0) {
|
||||||
return this.dataResource.nic.filter(e => { return e.ip6address }).map(e => { return e.ip6address }).join(', ')
|
return this.dataResource.nic.filter(e => { return e.ip6address }).map(e => { return e.ip6address }).join(', ')
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
ip6routes () {
|
ip6routes () {
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template #bodyCell="{ column, text, record }">
|
<template #bodyCell="{ column, text, record }">
|
||||||
<template v-if="column.key === 'name'">
|
<template v-if="column.key === 'name'">
|
||||||
<span v-if="['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
<span v-if="['vm', 'vnfapp'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
||||||
<span v-if="record.icon && record.icon.base64image">
|
<span v-if="record.icon && record.icon.base64image">
|
||||||
<resource-icon :image="record.icon.base64image" size="2x"/>
|
<resource-icon :image="record.icon.base64image" size="2x"/>
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
<span v-if="$route.path.startsWith('/project')" style="margin-right: 5px">
|
<span v-if="$route.path.startsWith('/project')" style="margin-right: 5px">
|
||||||
<tooltip-button type="dashed" size="small" icon="LoginOutlined" @onClick="changeProject(record)" />
|
<tooltip-button type="dashed" size="small" icon="LoginOutlined" @onClick="changeProject(record)" />
|
||||||
</span>
|
</span>
|
||||||
<span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
<span v-if="$showIcon() && !['vm', 'vnfapp'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
||||||
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="2x"/>
|
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="2x"/>
|
||||||
<os-logo v-else-if="record.ostypename" :osName="record.ostypename" size="2x" />
|
<os-logo v-else-if="record.ostypename" :osName="record.ostypename" size="2x" />
|
||||||
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px;" :icon="$route.meta.icon"/>
|
<render-icon v-else-if="typeof $route.meta.icon ==='string'" style="font-size: 16px;" :icon="$route.meta.icon"/>
|
||||||
|
|
@ -96,7 +96,7 @@
|
||||||
<span>{{ text <= 0 ? 'N/A' : text }}</span>
|
<span>{{ text <= 0 ? 'N/A' : text }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'templatetype'">
|
<template v-if="column.key === 'templatetype'">
|
||||||
<router-link :to="{ path: $route.path + '/' + record.templatetype }">{{ text }}</router-link>
|
<span>{{ text }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'type'">
|
<template v-if="column.key === 'type'">
|
||||||
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(text)">{{ $t(text.toLowerCase()) }}</span>
|
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(text)">{{ $t(text.toLowerCase()) }}</span>
|
||||||
|
|
@ -118,7 +118,7 @@
|
||||||
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'username'">
|
<template v-if="column.key === 'username'">
|
||||||
<span v-if="$showIcon() && !['vm'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
<span v-if="$showIcon() && !['vm', 'vnfapp'].includes($route.path.split('/')[1])" style="margin-right: 5px">
|
||||||
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="2x"/>
|
<resource-icon v-if="$showIcon() && record.icon && record.icon.base64image" :image="record.icon.base64image" size="2x"/>
|
||||||
<user-outlined v-else style="font-size: 16px;" />
|
<user-outlined v-else style="font-size: 16px;" />
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -355,7 +355,7 @@
|
||||||
<template v-if="['created', 'sent'].includes(column.key)">
|
<template v-if="['created', 'sent'].includes(column.key)">
|
||||||
{{ $toLocaleDate(text) }}
|
{{ $toLocaleDate(text) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-if="['startdate', 'enddate'].includes(column.key) && ['vm'].includes($route.path.split('/')[1])">
|
<template v-if="['startdate', 'enddate'].includes(column.key) && ['vm', 'vnfapp'].includes($route.path.split('/')[1])">
|
||||||
{{ getDateAtTimeZone(text, record.timezone) }}
|
{{ getDateAtTimeZone(text, record.timezone) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'order'">
|
<template v-if="column.key === 'order'">
|
||||||
|
|
@ -581,7 +581,7 @@ export default {
|
||||||
quickViewEnabled () {
|
quickViewEnabled () {
|
||||||
return new RegExp(['/vm', '/kubernetes', '/ssh', '/userdata', '/vmgroup', '/affinitygroup', '/autoscalevmgroup',
|
return new RegExp(['/vm', '/kubernetes', '/ssh', '/userdata', '/vmgroup', '/affinitygroup', '/autoscalevmgroup',
|
||||||
'/volume', '/snapshot', '/vmsnapshot', '/backup',
|
'/volume', '/snapshot', '/vmsnapshot', '/backup',
|
||||||
'/guestnetwork', '/vpc', '/vpncustomergateway',
|
'/guestnetwork', '/vpc', '/vpncustomergateway', '/vnfapp',
|
||||||
'/template', '/iso',
|
'/template', '/iso',
|
||||||
'/project', '/account',
|
'/project', '/account',
|
||||||
'/zone', '/pod', '/cluster', '/host', '/storagepool', '/imagestore', '/systemvm', '/router', '/ilbvm', '/annotation',
|
'/zone', '/pod', '/cluster', '/host', '/storagepool', '/imagestore', '/systemvm', '/router', '/ilbvm', '/annotation',
|
||||||
|
|
@ -591,7 +591,7 @@ export default {
|
||||||
},
|
},
|
||||||
enableGroupAction () {
|
enableGroupAction () {
|
||||||
return ['vm', 'alert', 'vmgroup', 'ssh', 'userdata', 'affinitygroup', 'autoscalevmgroup', 'volume', 'snapshot',
|
return ['vm', 'alert', 'vmgroup', 'ssh', 'userdata', 'affinitygroup', 'autoscalevmgroup', 'volume', 'snapshot',
|
||||||
'vmsnapshot', 'guestnetwork', 'vpc', 'publicip', 'vpnuser', 'vpncustomergateway',
|
'vmsnapshot', 'guestnetwork', 'vpc', 'publicip', 'vpnuser', 'vpncustomergateway', 'vnfapp',
|
||||||
'project', 'account', 'systemvm', 'router', 'computeoffering', 'systemoffering',
|
'project', 'account', 'systemvm', 'router', 'computeoffering', 'systemoffering',
|
||||||
'diskoffering', 'backupoffering', 'networkoffering', 'vpcoffering', 'ilbvm', 'kubernetes', 'comment'
|
'diskoffering', 'backupoffering', 'networkoffering', 'vpcoffering', 'ilbvm', 'kubernetes', 'comment'
|
||||||
].includes(this.$route.name)
|
].includes(this.$route.name)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<a
|
<a
|
||||||
v-if="['vm', 'systemvm', 'router', 'ilbvm'].includes($route.meta.name) && 'listVirtualMachines' in $store.getters.apis && 'createConsoleEndpoint' in $store.getters.apis"
|
v-if="['vm', 'systemvm', 'router', 'ilbvm', 'vnfapp'].includes($route.meta.name) && 'listVirtualMachines' in $store.getters.apis && 'createConsoleEndpoint' in $store.getters.apis"
|
||||||
@click="consoleUrl">
|
@click="consoleUrl">
|
||||||
<a-button style="margin-left: 5px" shape="circle" type="dashed" :size="size" :disabled="['Stopped', 'Error', 'Destroyed'].includes(resource.state) || resource.hostcontrolstate === 'Offline'" >
|
<a-button style="margin-left: 5px" shape="circle" type="dashed" :size="size" :disabled="['Stopped', 'Error', 'Destroyed'].includes(resource.state) || resource.hostcontrolstate === 'Offline'" >
|
||||||
<code-outlined v-if="!copyUrlToClipboard"/>
|
<code-outlined v-if="!copyUrlToClipboard"/>
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ export default {
|
||||||
if (store.getters.metrics) {
|
if (store.getters.metrics) {
|
||||||
params = { details: 'servoff,tmpl,nics,stats' }
|
params = { details: 'servoff,tmpl,nics,stats' }
|
||||||
}
|
}
|
||||||
|
params.isvnf = false
|
||||||
return params
|
return params
|
||||||
},
|
},
|
||||||
filters: () => {
|
filters: () => {
|
||||||
|
|
@ -255,7 +256,7 @@ export default {
|
||||||
{
|
{
|
||||||
api: 'createBackupSchedule',
|
api: 'createBackupSchedule',
|
||||||
icon: 'schedule-outlined',
|
icon: 'schedule-outlined',
|
||||||
label: 'Configure Backup Schedule',
|
label: 'label.backup.configure.schedule',
|
||||||
docHelp: 'adminguide/virtual_machines.html#creating-vm-backups',
|
docHelp: 'adminguide/virtual_machines.html#creating-vm-backups',
|
||||||
dataView: true,
|
dataView: true,
|
||||||
popup: true,
|
popup: true,
|
||||||
|
|
|
||||||
|
|
@ -48,16 +48,17 @@ export default {
|
||||||
fields.push('account')
|
fields.push('account')
|
||||||
}
|
}
|
||||||
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
||||||
|
fields.push('templatetype')
|
||||||
fields.push('order')
|
fields.push('order')
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
},
|
},
|
||||||
details: () => {
|
details: () => {
|
||||||
var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'format', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
|
var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'format', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
|
||||||
'crossZones', 'directdownload', 'deployasis', 'ispublic', 'isfeatured', 'isextractable', 'isdynamicallyscalable', 'crosszones', 'type',
|
'crossZones', 'templatetype', 'directdownload', 'deployasis', 'ispublic', 'isfeatured', 'isextractable', 'isdynamicallyscalable', 'crosszones', 'type',
|
||||||
'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy']
|
'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy']
|
||||||
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
||||||
fields.push('templatetype', 'url')
|
fields.push('url')
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
},
|
},
|
||||||
|
|
@ -76,6 +77,10 @@ export default {
|
||||||
}, {
|
}, {
|
||||||
name: 'settings',
|
name: 'settings',
|
||||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailSettings')))
|
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailSettings')))
|
||||||
|
}, {
|
||||||
|
name: 'vnf.settings',
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/image/TemplateVnfSettings.vue'))),
|
||||||
|
show: (record) => { return record.templatetype === 'VNF' }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'events',
|
name: 'events',
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,10 @@ export default {
|
||||||
name: 'virtual.routers',
|
name: 'virtual.routers',
|
||||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/RoutersTab.vue'))),
|
component: shallowRef(defineAsyncComponent(() => import('@/views/network/RoutersTab.vue'))),
|
||||||
show: (record) => { return (record.type === 'Isolated' || record.type === 'Shared') && 'listRouters' in store.getters.apis && isAdmin() }
|
show: (record) => { return (record.type === 'Isolated' || record.type === 'Shared') && 'listRouters' in store.getters.apis && isAdmin() }
|
||||||
|
}, {
|
||||||
|
name: 'vnf.appliances',
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/network/VnfAppliancesTab.vue'))),
|
||||||
|
show: () => { return 'deployVnfAppliance' in store.getters.apis }
|
||||||
}, {
|
}, {
|
||||||
name: 'guest.ip.range',
|
name: 'guest.ip.range',
|
||||||
component: shallowRef(defineAsyncComponent(() => import('@/views/network/GuestIpRanges.vue'))),
|
component: shallowRef(defineAsyncComponent(() => import('@/views/network/GuestIpRanges.vue'))),
|
||||||
|
|
@ -316,6 +320,408 @@ export default {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'vnfapp',
|
||||||
|
title: 'label.vnf.appliances',
|
||||||
|
icon: 'gateway-outlined',
|
||||||
|
permission: ['listVirtualMachinesMetrics'],
|
||||||
|
params: () => {
|
||||||
|
return { details: 'servoff,tmpl,nics', isvnf: true }
|
||||||
|
},
|
||||||
|
columns: () => {
|
||||||
|
const fields = ['name', 'state', 'ipaddress']
|
||||||
|
if (store.getters.userInfo.roletype === 'Admin') {
|
||||||
|
fields.splice(2, 0, 'instancename')
|
||||||
|
fields.push('account')
|
||||||
|
fields.push('domain')
|
||||||
|
fields.push('hostname')
|
||||||
|
} else if (store.getters.userInfo.roletype === 'DomainAdmin') {
|
||||||
|
fields.push('account')
|
||||||
|
} else {
|
||||||
|
fields.push('serviceofferingname')
|
||||||
|
}
|
||||||
|
fields.push('zonename')
|
||||||
|
return fields
|
||||||
|
},
|
||||||
|
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'groupid', 'tags'],
|
||||||
|
details: () => {
|
||||||
|
var fields = ['name', 'displayname', 'id', 'state', 'ipaddress', 'ip6address', 'templatename', 'ostypename',
|
||||||
|
'serviceofferingname', 'isdynamicallyscalable', 'haenable', 'hypervisor', 'boottype', 'bootmode', 'account',
|
||||||
|
'domain', 'zonename', 'userdataid', 'userdataname', 'userdataparams', 'userdatadetails', 'userdatapolicy', 'hostcontrolstate']
|
||||||
|
const listZoneHaveSGEnabled = store.getters.zones.filter(zone => zone.securitygroupsenabled === true)
|
||||||
|
if (!listZoneHaveSGEnabled || listZoneHaveSGEnabled.length === 0) {
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
fields.push('securitygroup')
|
||||||
|
return fields
|
||||||
|
},
|
||||||
|
tabs: [{
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/InstanceTab.vue')))
|
||||||
|
}],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
api: 'deployVnfAppliance',
|
||||||
|
icon: 'plus-outlined',
|
||||||
|
label: 'label.vnf.appliance.add',
|
||||||
|
docHelp: 'adminguide/networking/vnf_templates_appliances.html#deploying-vnf-appliances',
|
||||||
|
listView: true,
|
||||||
|
component: () => import('@/views/compute/DeployVnfAppliance.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'updateVirtualMachine',
|
||||||
|
icon: 'edit-outlined',
|
||||||
|
label: 'label.vnf.app.action.edit',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#changing-the-vm-name-os-or-group',
|
||||||
|
dataView: true,
|
||||||
|
popup: true,
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/EditVM.vue')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'startVirtualMachine',
|
||||||
|
icon: 'caret-right-outlined',
|
||||||
|
label: 'label.vnf.app.action.start',
|
||||||
|
message: 'message.action.start.instance',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms',
|
||||||
|
dataView: true,
|
||||||
|
groupAction: true,
|
||||||
|
popup: true,
|
||||||
|
groupMap: (selection, values) => { return selection.map(x => { return { id: x, considerlasthost: values.considerlasthost } }) },
|
||||||
|
args: ['considerlasthost'],
|
||||||
|
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/StartVirtualMachine.vue')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'stopVirtualMachine',
|
||||||
|
icon: 'poweroff-outlined',
|
||||||
|
label: 'label.vnf.app.action.stop',
|
||||||
|
message: 'message.action.stop.instance',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms',
|
||||||
|
dataView: true,
|
||||||
|
groupAction: true,
|
||||||
|
groupMap: (selection, values) => { return selection.map(x => { return { id: x, forced: values.forced } }) },
|
||||||
|
args: ['forced'],
|
||||||
|
show: (record) => { return ['Running'].includes(record.state) }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'rebootVirtualMachine',
|
||||||
|
icon: 'reload-outlined',
|
||||||
|
label: 'label.vnf.app.action.reboot',
|
||||||
|
message: 'message.action.reboot.instance',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms',
|
||||||
|
dataView: true,
|
||||||
|
show: (record) => { return ['Running'].includes(record.state) },
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||||
|
args: (record, store) => {
|
||||||
|
var fields = []
|
||||||
|
fields.push('forced')
|
||||||
|
if (record.hypervisor === 'VMware') {
|
||||||
|
if (store.apis.rebootVirtualMachine.params.filter(x => x.name === 'bootintosetup').length > 0) {
|
||||||
|
fields.push('bootintosetup')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
},
|
||||||
|
groupAction: true,
|
||||||
|
popup: true,
|
||||||
|
groupMap: (selection, values) => { return selection.map(x => { return { id: x, forced: values.forced } }) }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'restoreVirtualMachine',
|
||||||
|
icon: 'sync-outlined',
|
||||||
|
label: 'label.vnf.app.action.reinstall',
|
||||||
|
message: 'message.reinstall.vm',
|
||||||
|
dataView: true,
|
||||||
|
args: ['virtualmachineid', 'templateid'],
|
||||||
|
filters: (record) => {
|
||||||
|
var filters = {}
|
||||||
|
var filterParams = {}
|
||||||
|
filterParams.hypervisortype = record.hypervisor
|
||||||
|
filterParams.zoneid = record.zoneid
|
||||||
|
filters.templateid = filterParams
|
||||||
|
return filters
|
||||||
|
},
|
||||||
|
show: (record) => { return ['Running', 'Stopped'].includes(record.state) },
|
||||||
|
mapping: {
|
||||||
|
virtualmachineid: {
|
||||||
|
value: (record) => { return record.id }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||||
|
successMethod: (obj, result) => {
|
||||||
|
const vm = result.jobresult.virtualmachine || {}
|
||||||
|
if (result.jobstatus === 1 && vm.password) {
|
||||||
|
const name = vm.displayname || vm.name || vm.id
|
||||||
|
obj.$notification.success({
|
||||||
|
message: `${obj.$t('label.reinstall.vm')}: ` + name,
|
||||||
|
description: `${obj.$t('label.password.reset.confirm')}: ` + vm.password,
|
||||||
|
duration: 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'createVMSnapshot',
|
||||||
|
icon: 'camera-outlined',
|
||||||
|
label: 'label.action.vmsnapshot.create',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#virtual-machine-snapshots',
|
||||||
|
dataView: true,
|
||||||
|
args: ['virtualmachineid', 'name', 'description', 'snapshotmemory', 'quiescevm'],
|
||||||
|
show: (record) => {
|
||||||
|
return ((['Running'].includes(record.state) && record.hypervisor !== 'LXC') ||
|
||||||
|
(['Stopped'].includes(record.state) && ((record.hypervisor !== 'KVM' && record.hypervisor !== 'LXC') ||
|
||||||
|
(record.hypervisor === 'KVM' && record.pooltype === 'PowerFlex'))))
|
||||||
|
},
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' && record.hypervisor === 'KVM' },
|
||||||
|
mapping: {
|
||||||
|
virtualmachineid: {
|
||||||
|
value: (record, params) => { return record.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'createSnapshot',
|
||||||
|
icon: ['fas', 'camera-retro'],
|
||||||
|
label: 'label.action.vmstoragesnapshot.create',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#virtual-machine-snapshots',
|
||||||
|
dataView: true,
|
||||||
|
popup: true,
|
||||||
|
show: (record) => {
|
||||||
|
return ((['Running'].includes(record.state) && record.hypervisor !== 'LXC') ||
|
||||||
|
(['Stopped'].includes(record.state) && !['KVM', 'LXC'].includes(record.hypervisor)))
|
||||||
|
},
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' && record.hypervisor === 'KVM' },
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/CreateSnapshotWizard.vue')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'assignVirtualMachineToBackupOffering',
|
||||||
|
icon: 'folder-add-outlined',
|
||||||
|
label: 'label.backup.offering.assign',
|
||||||
|
message: 'label.backup.offering.assign',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#backup-offerings',
|
||||||
|
dataView: true,
|
||||||
|
args: ['virtualmachineid', 'backupofferingid'],
|
||||||
|
show: (record) => { return !record.backupofferingid },
|
||||||
|
mapping: {
|
||||||
|
virtualmachineid: {
|
||||||
|
value: (record, params) => { return record.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'createBackup',
|
||||||
|
icon: 'cloud-upload-outlined',
|
||||||
|
label: 'label.create.backup',
|
||||||
|
message: 'message.backup.create',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#creating-vm-backups',
|
||||||
|
dataView: true,
|
||||||
|
args: ['virtualmachineid'],
|
||||||
|
show: (record) => { return record.backupofferingid },
|
||||||
|
mapping: {
|
||||||
|
virtualmachineid: {
|
||||||
|
value: (record, params) => { return record.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'createBackupSchedule',
|
||||||
|
icon: 'schedule-outlined',
|
||||||
|
label: 'label.backup.configure.schedule',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#creating-vm-backups',
|
||||||
|
dataView: true,
|
||||||
|
popup: true,
|
||||||
|
show: (record) => { return record.backupofferingid },
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/BackupScheduleWizard.vue'))),
|
||||||
|
mapping: {
|
||||||
|
virtualmachineid: {
|
||||||
|
value: (record, params) => { return record.id }
|
||||||
|
},
|
||||||
|
intervaltype: {
|
||||||
|
options: ['HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'removeVirtualMachineFromBackupOffering',
|
||||||
|
icon: 'scissor-outlined',
|
||||||
|
label: 'label.backup.offering.remove',
|
||||||
|
message: 'label.backup.offering.remove',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#restoring-vm-backups',
|
||||||
|
dataView: true,
|
||||||
|
args: ['virtualmachineid', 'forced'],
|
||||||
|
show: (record) => { return record.backupofferingid },
|
||||||
|
mapping: {
|
||||||
|
virtualmachineid: {
|
||||||
|
value: (record, params) => { return record.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'attachIso',
|
||||||
|
icon: 'paper-clip-outlined',
|
||||||
|
label: 'label.action.attach.iso',
|
||||||
|
docHelp: 'adminguide/templates.html#attaching-an-iso-to-a-vm',
|
||||||
|
dataView: true,
|
||||||
|
popup: true,
|
||||||
|
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && !record.isoid },
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' || record.hostcontrolstate === 'Maintenance' },
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/AttachIso.vue')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'detachIso',
|
||||||
|
icon: 'link-outlined',
|
||||||
|
label: 'label.action.detach.iso',
|
||||||
|
message: 'message.detach.iso.confirm',
|
||||||
|
dataView: true,
|
||||||
|
args: (record, store) => {
|
||||||
|
var args = ['virtualmachineid']
|
||||||
|
if (record && record.hypervisor && record.hypervisor === 'VMware') {
|
||||||
|
args.push('forced')
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
},
|
||||||
|
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && 'isoid' in record && record.isoid },
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' || record.hostcontrolstate === 'Maintenance' },
|
||||||
|
mapping: {
|
||||||
|
virtualmachineid: {
|
||||||
|
value: (record, params) => { return record.id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'updateVMAffinityGroup',
|
||||||
|
icon: 'swap-outlined',
|
||||||
|
label: 'label.change.affinity',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#change-affinity-group-for-an-existing-vm',
|
||||||
|
dataView: true,
|
||||||
|
args: ['affinitygroupids'],
|
||||||
|
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ChangeAffinity'))),
|
||||||
|
popup: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'scaleVirtualMachine',
|
||||||
|
icon: 'arrows-alt-outlined',
|
||||||
|
label: 'label.vnf.app.action.scale',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#how-to-dynamically-scale-cpu-and-ram',
|
||||||
|
dataView: true,
|
||||||
|
show: (record) => { return ['Stopped'].includes(record.state) || (['Running'].includes(record.state) && record.hypervisor !== 'LXC') },
|
||||||
|
disabled: (record) => { return record.state === 'Running' && !record.isdynamicallyscalable },
|
||||||
|
popup: true,
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ScaleVM.vue')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'migrateVirtualMachine',
|
||||||
|
icon: 'drag-outlined',
|
||||||
|
label: 'label.vnf.app.action.migrate.to.host',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#moving-vms-between-hosts-manual-live-migration',
|
||||||
|
dataView: true,
|
||||||
|
show: (record, store) => { return ['Running'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||||
|
popup: true,
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateWizard.vue')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'migrateVirtualMachine',
|
||||||
|
icon: 'drag-outlined',
|
||||||
|
label: 'label.vnf.app.action.migrate.to.ps',
|
||||||
|
message: 'message.migrate.instance.to.ps',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#moving-vms-between-hosts-manual-live-migration',
|
||||||
|
dataView: true,
|
||||||
|
show: (record, store) => { return ['Stopped'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||||
|
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/MigrateVMStorage'))),
|
||||||
|
popup: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'resetPasswordForVirtualMachine',
|
||||||
|
icon: 'key-outlined',
|
||||||
|
label: 'label.action.reset.password',
|
||||||
|
message: 'message.action.instance.reset.password',
|
||||||
|
dataView: true,
|
||||||
|
show: (record) => { return ['Stopped'].includes(record.state) && record.passwordenabled },
|
||||||
|
response: (result) => {
|
||||||
|
return {
|
||||||
|
message: result.virtualmachine && result.virtualmachine.password ? `The password of VM <b>${result.virtualmachine.displayname}</b> is <b>${result.virtualmachine.password}</b>` : null,
|
||||||
|
copybuttontext: result.virtualmachine.password ? 'label.copy.password' : null,
|
||||||
|
copytext: result.virtualmachine.password ? result.virtualmachine.password : null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'resetSSHKeyForVirtualMachine',
|
||||||
|
icon: 'lock-outlined',
|
||||||
|
label: 'label.reset.ssh.key.pair',
|
||||||
|
message: 'message.desc.reset.ssh.key.pair',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#resetting-ssh-keys',
|
||||||
|
dataView: true,
|
||||||
|
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||||
|
popup: true,
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ResetSshKeyPair')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'resetUserDataForVirtualMachine',
|
||||||
|
icon: 'solution-outlined',
|
||||||
|
label: 'label.reset.userdata.on.vm',
|
||||||
|
message: 'message.desc.reset.userdata',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#resetting-userdata',
|
||||||
|
dataView: true,
|
||||||
|
show: (record) => { return ['Stopped'].includes(record.state) },
|
||||||
|
popup: true,
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/ResetUserData')))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'assignVirtualMachine',
|
||||||
|
icon: 'user-add-outlined',
|
||||||
|
label: 'label.assign.instance.another',
|
||||||
|
dataView: true,
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/AssignInstance'))),
|
||||||
|
popup: true,
|
||||||
|
show: (record) => { return ['Stopped'].includes(record.state) }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'recoverVirtualMachine',
|
||||||
|
icon: 'medicine-box-outlined',
|
||||||
|
label: 'label.vnf.app.action.recover',
|
||||||
|
message: 'message.recover.vm',
|
||||||
|
dataView: true,
|
||||||
|
show: (record, store) => { return ['Destroyed'].includes(record.state) && store.features.allowuserexpungerecovervm }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'unmanageVirtualMachine',
|
||||||
|
icon: 'disconnect-outlined',
|
||||||
|
label: 'label.action.unmanage.virtualmachine',
|
||||||
|
message: 'message.action.unmanage.virtualmachine',
|
||||||
|
dataView: true,
|
||||||
|
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && record.hypervisor === 'VMware' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'expungeVirtualMachine',
|
||||||
|
icon: 'delete-outlined',
|
||||||
|
label: 'label.vnf.app.action.expunge',
|
||||||
|
message: (record) => { return record.backupofferingid ? 'message.action.expunge.instance.with.backups' : 'message.action.expunge.instance' },
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#deleting-vms',
|
||||||
|
dataView: true,
|
||||||
|
show: (record, store) => { return ['Destroyed', 'Expunging'].includes(record.state) && store.features.allowuserexpungerecovervm }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
api: 'destroyVirtualMachine',
|
||||||
|
icon: 'delete-outlined',
|
||||||
|
label: 'label.vnf.app.action.destroy',
|
||||||
|
message: 'message.action.destroy.instance',
|
||||||
|
docHelp: 'adminguide/virtual_machines.html#deleting-vms',
|
||||||
|
dataView: true,
|
||||||
|
groupAction: true,
|
||||||
|
args: (record, store, group) => {
|
||||||
|
return (['Admin'].includes(store.userInfo.roletype) || store.features.allowuserexpungerecovervm)
|
||||||
|
? ['expunge'] : []
|
||||||
|
},
|
||||||
|
popup: true,
|
||||||
|
groupMap: (selection, values) => { return selection.map(x => { return { id: x, expunge: values.expunge } }) },
|
||||||
|
show: (record) => { return ['Running', 'Stopped', 'Error'].includes(record.state) },
|
||||||
|
component: shallowRef(defineAsyncComponent(() => import('@/views/compute/DestroyVM.vue')))
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'publicip',
|
name: 'publicip',
|
||||||
title: 'label.public.ip.addresses',
|
title: 'label.public.ip.addresses',
|
||||||
|
|
|
||||||
|
|
@ -762,7 +762,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) &&
|
if (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) &&
|
||||||
'templatefilter' in params && this.routeName === 'template') {
|
'templatefilter' in params && (['template'].includes(this.routeName))) {
|
||||||
params.templatefilter = 'all'
|
params.templatefilter = 'all'
|
||||||
}
|
}
|
||||||
if (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) &&
|
if (['Admin', 'DomainAdmin'].includes(this.$store.getters.userInfo.roletype) &&
|
||||||
|
|
@ -789,7 +789,9 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.projectView = Boolean(store.getters.project && store.getters.project.id)
|
this.projectView = Boolean(store.getters.project && store.getters.project.id)
|
||||||
this.hasProjectId = ['vm', 'vmgroup', 'ssh', 'affinitygroup', 'volume', 'snapshot', 'vmsnapshot', 'guestnetwork', 'vpc', 'securitygroups', 'publicip', 'vpncustomergateway', 'template', 'iso', 'event', 'kubernetes', 'autoscalevmgroup'].includes(this.$route.name)
|
this.hasProjectId = ['vm', 'vmgroup', 'ssh', 'affinitygroup', 'volume', 'snapshot', 'vmsnapshot', 'guestnetwork',
|
||||||
|
'vpc', 'securitygroups', 'publicip', 'vpncustomergateway', 'template', 'iso', 'event', 'kubernetes',
|
||||||
|
'autoscalevmgroup', 'vnfapp'].includes(this.$route.name)
|
||||||
|
|
||||||
if ((this.$route && this.$route.params && this.$route.params.id) || this.$route.query.dataView) {
|
if ((this.$route && this.$route.params && this.$route.params.id) || this.$route.query.dataView) {
|
||||||
this.dataView = true
|
this.dataView = true
|
||||||
|
|
@ -891,6 +893,7 @@ export default {
|
||||||
|
|
||||||
if (['listVirtualMachinesMetrics'].includes(this.apiName) && this.dataView) {
|
if (['listVirtualMachinesMetrics'].includes(this.apiName) && this.dataView) {
|
||||||
delete params.details
|
delete params.details
|
||||||
|
delete params.isvnf
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loading = true
|
this.loading = true
|
||||||
|
|
@ -1101,7 +1104,7 @@ export default {
|
||||||
this.rules = reactive({})
|
this.rules = reactive({})
|
||||||
if (action.component && action.api && !action.popup) {
|
if (action.component && action.api && !action.popup) {
|
||||||
const query = {}
|
const query = {}
|
||||||
if (this.$route.path.startsWith('/vm')) {
|
if (this.$route.path.startsWith('/vm') || this.$route.path.startsWith('/vnfapp')) {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case ('templateid' in this.$route.query):
|
case ('templateid' in this.$route.query):
|
||||||
query.templateid = this.$route.query.templateid
|
query.templateid = this.$route.query.templateid
|
||||||
|
|
|
||||||
|
|
@ -522,7 +522,7 @@
|
||||||
{{ $t('label.isadvanced') }}
|
{{ $t('label.isadvanced') }}
|
||||||
<a-switch v-model:checked="showDetails" style="margin-left: 10px"/>
|
<a-switch v-model:checked="showDetails" style="margin-left: 10px"/>
|
||||||
</span>
|
</span>
|
||||||
<div style="margin-top: 15px" v-show="showDetails">
|
<div style="margin-top: 15px" v-if="showDetails">
|
||||||
<div
|
<div
|
||||||
v-if="vm.templateid && ['KVM', 'VMware', 'XenServer'].includes(hypervisor) && !template.deployasis">
|
v-if="vm.templateid && ['KVM', 'VMware', 'XenServer'].includes(hypervisor) && !template.deployasis">
|
||||||
<a-form-item :label="$t('label.boottype')" name="boottype" ref="boottype">
|
<a-form-item :label="$t('label.boottype')" name="boottype" ref="boottype">
|
||||||
|
|
@ -2292,6 +2292,7 @@ export default {
|
||||||
args.details = 'all'
|
args.details = 'all'
|
||||||
args.showicon = 'true'
|
args.showicon = 'true'
|
||||||
args.id = this.templateId
|
args.id = this.templateId
|
||||||
|
args.isvnf = false
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
api('listTemplates', args).then((response) => {
|
api('listTemplates', args).then((response) => {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -91,6 +91,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => false
|
default: () => false
|
||||||
},
|
},
|
||||||
|
vnf: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => false
|
||||||
|
},
|
||||||
preFillContent: {
|
preFillContent: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
|
|
@ -138,6 +142,9 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
rowSelection () {
|
rowSelection () {
|
||||||
|
if (this.vnf) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
selectedRowKeys: this.selectedRowKeys,
|
selectedRowKeys: this.selectedRowKeys,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
:placeholder="$t('label.search')"
|
:placeholder="$t('label.search')"
|
||||||
v-model:value="filter"
|
v-model:value="filter"
|
||||||
@search="handleSearch" />
|
@search="handleSearch" />
|
||||||
<a-button type="primary" @click="onCreateNetworkClick" style="float: right; margin-right: 5px; z-index: 8" v-if="showCreateButton">
|
<a-button type="primary" @click="onCreateNetworkClick" style="float: right; margin-right: 5px; z-index: 8" v-if="showCreateButton && !this.vnf">
|
||||||
{{ $t('label.create.network') }}
|
{{ $t('label.create.network') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-table
|
<a-table
|
||||||
|
|
@ -138,6 +138,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => false
|
default: () => false
|
||||||
},
|
},
|
||||||
|
vnf: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => false
|
||||||
|
},
|
||||||
preFillContent: {
|
preFillContent: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
<label>{{ $t('message.vnf.select.networks') }}</label>
|
||||||
|
</div>
|
||||||
|
<a-form
|
||||||
|
:ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules">
|
||||||
|
<a-table
|
||||||
|
:columns="columns"
|
||||||
|
:dataSource="items"
|
||||||
|
:pagination="false"
|
||||||
|
:rowKey="record => record.deviceid"
|
||||||
|
size="middle"
|
||||||
|
:scroll="{ y: 225 }">
|
||||||
|
<template #deviceid="{ text }">
|
||||||
|
<div>{{ text }}</div>
|
||||||
|
</template>
|
||||||
|
<template #name="{ text }">
|
||||||
|
<div>{{ text }}</div>
|
||||||
|
</template>
|
||||||
|
<template #required="{ record }">
|
||||||
|
<span v-if="record.required">{{ $t('label.yes') }}</span>
|
||||||
|
<span v-else>{{ $t('label.no') }}</span>
|
||||||
|
</template>
|
||||||
|
<template #management="{ record }">
|
||||||
|
<span v-if="record.management">{{ $t('label.yes') }}</span>
|
||||||
|
<span v-else>{{ $t('label.no') }}</span>
|
||||||
|
</template>
|
||||||
|
<template #description="{record}">
|
||||||
|
<span> {{ record.description }} </span>
|
||||||
|
</template>
|
||||||
|
<template #network="{ record }">
|
||||||
|
<a-form-item style="display: block" :name="'nic-' + record.deviceid">
|
||||||
|
<a-select
|
||||||
|
@change="updateNicNetworkValue($event, record.deviceid)"
|
||||||
|
optionFilterProp="label"
|
||||||
|
:filterOption="(input, option) => {
|
||||||
|
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
}" >
|
||||||
|
<a-select-option key="" >{{ }}</a-select-option>
|
||||||
|
<a-select-option v-for="network in networks" :key="network.id">
|
||||||
|
{{ network.name }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
export default {
|
||||||
|
name: 'VnfNicsSelection',
|
||||||
|
props: {
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
networks: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
preFillContent: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
values: {},
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
dataIndex: 'deviceid',
|
||||||
|
title: this.$t('label.deviceid'),
|
||||||
|
width: '10%',
|
||||||
|
slots: { customRender: 'deviceid' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'name',
|
||||||
|
title: this.$t('label.name'),
|
||||||
|
width: '15%',
|
||||||
|
slots: { customRender: 'name' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'required',
|
||||||
|
title: this.$t('label.required'),
|
||||||
|
width: '10%',
|
||||||
|
slots: { customRender: 'required' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'management',
|
||||||
|
title: this.$t('label.vnf.nic.management'),
|
||||||
|
width: '15%',
|
||||||
|
slots: { customRender: 'management' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'description',
|
||||||
|
title: this.$t('label.description'),
|
||||||
|
width: '35%',
|
||||||
|
slots: { customRender: 'description' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dataIndex: 'network',
|
||||||
|
title: this.$t('label.network'),
|
||||||
|
width: '25%',
|
||||||
|
slots: { customRender: 'network' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.initForm()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initForm () {
|
||||||
|
this.formRef = ref()
|
||||||
|
this.form = reactive({})
|
||||||
|
this.rules = reactive({})
|
||||||
|
|
||||||
|
const form = {}
|
||||||
|
const rules = {}
|
||||||
|
|
||||||
|
this.form = reactive(form)
|
||||||
|
this.rules = reactive(rules)
|
||||||
|
},
|
||||||
|
updateNicNetworkValue (value, deviceid) {
|
||||||
|
this.values[deviceid] = this.networks.filter(network => network.id === value)?.[0] || null
|
||||||
|
this.$emit('update-vnf-nic-networks', this.values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.ant-table-wrapper {
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-tbody) > tr > td {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form .ant-form-item {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -324,6 +324,25 @@
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
name="templatetype"
|
||||||
|
ref="templatetype">
|
||||||
|
<template #label>
|
||||||
|
<tooltip-label :title="$t('label.templatetype')" :tooltip="apiParams.templatetype.description"/>
|
||||||
|
</template>
|
||||||
|
<a-select
|
||||||
|
showSearch
|
||||||
|
optionFilterProp="label"
|
||||||
|
:filterOption="(input, option) => {
|
||||||
|
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||||
|
}"
|
||||||
|
v-model:value="form.templatetype"
|
||||||
|
:placeholder="apiParams.templatetype.description">
|
||||||
|
<a-select-option v-for="opt in templateTypes.opts" :key="opt.id">
|
||||||
|
{{ opt.name || opt.description }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
<a-row :gutter="12">
|
<a-row :gutter="12">
|
||||||
<a-col :md="24" :lg="12">
|
<a-col :md="24" :lg="12">
|
||||||
<a-form-item
|
<a-form-item
|
||||||
|
|
@ -405,11 +424,6 @@
|
||||||
{{ $t('label.ispublic') }}
|
{{ $t('label.ispublic') }}
|
||||||
</a-checkbox>
|
</a-checkbox>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="12" v-if="isAdminRole">
|
|
||||||
<a-checkbox value="isrouting">
|
|
||||||
{{ $t('label.isrouting') }}
|
|
||||||
</a-checkbox>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-checkbox-group>
|
</a-checkbox-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|
@ -465,6 +479,7 @@ export default {
|
||||||
format: {},
|
format: {},
|
||||||
osTypes: {},
|
osTypes: {},
|
||||||
defaultOsType: '',
|
defaultOsType: '',
|
||||||
|
templateTypes: {},
|
||||||
userdata: {},
|
userdata: {},
|
||||||
userdataid: null,
|
userdataid: null,
|
||||||
userdatapolicy: null,
|
userdatapolicy: null,
|
||||||
|
|
@ -539,6 +554,7 @@ export default {
|
||||||
this.fetchCustomHypervisorName()
|
this.fetchCustomHypervisorName()
|
||||||
this.fetchZone()
|
this.fetchZone()
|
||||||
this.fetchOsTypes()
|
this.fetchOsTypes()
|
||||||
|
this.fetchTemplateTypes()
|
||||||
this.fetchUserData()
|
this.fetchUserData()
|
||||||
this.fetchUserdataPolicy()
|
this.fetchUserdataPolicy()
|
||||||
if ('listDomains' in this.$store.getters.apis) {
|
if ('listDomains' in this.$store.getters.apis) {
|
||||||
|
|
@ -681,6 +697,33 @@ export default {
|
||||||
this.osTypes.loading = false
|
this.osTypes.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
fetchTemplateTypes () {
|
||||||
|
this.templateTypes.opts = []
|
||||||
|
const templatetypes = []
|
||||||
|
templatetypes.push({
|
||||||
|
id: 'USER',
|
||||||
|
description: 'USER'
|
||||||
|
})
|
||||||
|
templatetypes.push({
|
||||||
|
id: 'VNF',
|
||||||
|
description: 'VNF'
|
||||||
|
})
|
||||||
|
if (this.isAdminRole) {
|
||||||
|
templatetypes.push({
|
||||||
|
id: 'SYSTEM',
|
||||||
|
description: 'SYSTEM'
|
||||||
|
})
|
||||||
|
templatetypes.push({
|
||||||
|
id: 'BUILTIN',
|
||||||
|
description: 'BUILTIN'
|
||||||
|
})
|
||||||
|
templatetypes.push({
|
||||||
|
id: 'ROUTING',
|
||||||
|
description: 'ROUTING'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.templateTypes.opts = templatetypes
|
||||||
|
},
|
||||||
fetchUserData () {
|
fetchUserData () {
|
||||||
const params = {}
|
const params = {}
|
||||||
params.listAll = true
|
params.listAll = true
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,880 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-divider/>
|
||||||
|
|
||||||
|
<div class="title">
|
||||||
|
<div class="form__label">
|
||||||
|
<tooltip-label :title="$t('label.vnf.nics')" :tooltip="apiParams.vnfnics.description"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a-button
|
||||||
|
type="dashed"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="!('updateVnfTemplate' in $store.getters.apis && isAdminOrOwner())"
|
||||||
|
@click="onShowAddVnfNic">
|
||||||
|
<template #icon><plus-outlined /></template>
|
||||||
|
{{ $t('label.vnf.nic.add') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-table
|
||||||
|
size="small"
|
||||||
|
style="overflow-y: auto"
|
||||||
|
:loading="loading"
|
||||||
|
:columns="columns"
|
||||||
|
:dataSource="vnfNics"
|
||||||
|
:pagination="false"
|
||||||
|
:rowKey="record => record.deviceid">
|
||||||
|
<template #deviceid="{record}">
|
||||||
|
<span> {{ record.deviceid }} </span>
|
||||||
|
</template>
|
||||||
|
<template #name="{record}">
|
||||||
|
<span> {{ record.name }} </span>
|
||||||
|
</template>
|
||||||
|
<template #required="{ record }">
|
||||||
|
<span v-if="record.required">{{ $t('label.yes') }}</span>
|
||||||
|
<span v-else>{{ $t('label.no') }}</span>
|
||||||
|
</template>
|
||||||
|
<template #management="{ record }">
|
||||||
|
<span v-if="record.management">{{ $t('label.yes') }}</span>
|
||||||
|
<span v-else>{{ $t('label.no') }}</span>
|
||||||
|
</template>
|
||||||
|
<template #description="{record}">
|
||||||
|
<span> {{ record.description }} </span>
|
||||||
|
</template>
|
||||||
|
<template #actions="{ record }">
|
||||||
|
<div class="shift-btns" v-if="'updateVnfTemplate' in $store.getters.apis && isAdminOrOwner()">
|
||||||
|
<a-tooltip placement="top">
|
||||||
|
<template #title>{{ $t('label.vnf.nic.edit') }}</template>
|
||||||
|
<a-button shape="round" @click="onShowEditVnfNic(record)" class="shift-btn">
|
||||||
|
<EditOutlined class="shift-btn" />
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip placement="top">
|
||||||
|
<template #title>{{ $t('label.move.up.row') }}</template>
|
||||||
|
<a-button shape="round" @click="moveVnfNicUp(record)" class="shift-btn">
|
||||||
|
<CaretUpOutlined class="shift-btn" />
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip placement="top">
|
||||||
|
<template #title>{{ $t('label.move.down.row') }}</template>
|
||||||
|
<a-button shape="round" @click="moveVnfNicDown(record)" class="shift-btn">
|
||||||
|
<CaretDownOutlined class="shift-btn" />
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-popconfirm
|
||||||
|
:title="$t('label.vnf.nic.delete') + '?'"
|
||||||
|
@confirm="deleteVnfNic(record)"
|
||||||
|
:okText="$t('label.yes')"
|
||||||
|
:cancelText="$t('label.no')"
|
||||||
|
>
|
||||||
|
<template #title>{{ $t('label.vnf.nic.delete') }}</template>
|
||||||
|
<a-button shape="round" class="shift-btn" :danger="true" type="primary">
|
||||||
|
<DeleteOutlined class="shift-btn" />
|
||||||
|
</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
:title="$t('label.vnf.nic.add')"
|
||||||
|
:visible="showAddVnfNic"
|
||||||
|
:afterClose="closeVnfNicModal"
|
||||||
|
:maskClosable="false"
|
||||||
|
:closable="true"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="closeVnfNicModal">
|
||||||
|
|
||||||
|
<div class="new-vnf-nic" v-ctrl-enter="addVnfNic">
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.deviceid')" :tooltip="$t('label.vnf.nic.deviceid')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="newVnfNic.deviceid" type="number" v-focus="true"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.name')" :tooltip="$t('label.vnf.nic.name')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="newVnfNic.name"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.required')" :tooltip="$t('label.vnf.nic.required')"/>
|
||||||
|
</div>
|
||||||
|
<a-switch v-model:checked="newVnfNic.required" :checked="true" />
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.vnf.nic.management')" :tooltip="$t('label.vnf.nic.management.description')"/>
|
||||||
|
</div>
|
||||||
|
<a-switch v-model:checked="newVnfNic.management" :checked="false" />
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<tooltip-label :title="$t('label.description')" :tooltip="$t('label.vnf.nic.description')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="newVnfNic.description"></a-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div :span="24" class="action-button">
|
||||||
|
<a-button @click="showAddVnfNic = false">{{ $t('label.cancel') }}</a-button>
|
||||||
|
<a-button ref="submit" type="primary" @click="addVnfNic">{{ $t('label.ok') }}</a-button>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
:title="$t('label.vnf.nic.add')"
|
||||||
|
:visible="showAddVnfNic"
|
||||||
|
:afterClose="closeVnfNicModal"
|
||||||
|
:maskClosable="false"
|
||||||
|
:closable="true"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="closeVnfNicModal">
|
||||||
|
|
||||||
|
<div class="new-vnf-nic" v-ctrl-enter="addVnfNic">
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.deviceid')" :tooltip="$t('label.vnf.nic.deviceid')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="newVnfNic.deviceid" type="number" v-focus="true"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.name')" :tooltip="$t('label.vnf.nic.name')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="newVnfNic.name"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.required')" :tooltip="$t('label.vnf.nic.required')"/>
|
||||||
|
</div>
|
||||||
|
<a-switch v-model:checked="newVnfNic.required" :checked="true" />
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<span class="new-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.vnf.nic.management')" :tooltip="$t('label.vnf.nic.management.description')"/>
|
||||||
|
</div>
|
||||||
|
<a-switch v-model:checked="newVnfNic.management" :checked="false" />
|
||||||
|
</div>
|
||||||
|
<div class="new-vnf-nic__item">
|
||||||
|
<div class="new-vnf-nic__label">
|
||||||
|
<tooltip-label :title="$t('label.description')" :tooltip="$t('label.vnf.nic.description')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="newVnfNic.description"></a-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div :span="24" class="action-button">
|
||||||
|
<a-button @click="showAddVnfNic = false">{{ $t('label.cancel') }}</a-button>
|
||||||
|
<a-button ref="submit" type="primary" @click="addVnfNic">{{ $t('label.ok') }}</a-button>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
:title="$t('label.vnf.nic.edit')"
|
||||||
|
:visible="showEditVnfNic"
|
||||||
|
:afterClose="closeVnfNicModal"
|
||||||
|
:maskClosable="false"
|
||||||
|
:closable="true"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="closeVnfNicModal">
|
||||||
|
|
||||||
|
<div class="update-vnf-nic" v-ctrl-enter="editVnfNic">
|
||||||
|
<div class="update-vnf-nic__item">
|
||||||
|
<div class="update-vnf-nic__label">
|
||||||
|
<span class="update-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.deviceid')" :tooltip="$t('label.vnf.nic.deviceid')"/>
|
||||||
|
</div>
|
||||||
|
<span> {{ updateVnfNic.deviceid }} </span>
|
||||||
|
</div>
|
||||||
|
<div class="update-vnf-nic__item">
|
||||||
|
<div class="update-vnf-nic__label">
|
||||||
|
<span class="update-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.name')" :tooltip="$t('label.vnf.nic.name')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="updateVnfNic.name"></a-input>
|
||||||
|
</div>
|
||||||
|
<div class="update-vnf-nic__item">
|
||||||
|
<div class="update-vnf-nic__label">
|
||||||
|
<span class="update-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.required')" :tooltip="$t('label.vnf.nic.required')"/>
|
||||||
|
</div>
|
||||||
|
<a-switch v-model:checked="updateVnfNic.required" :checked="true" />
|
||||||
|
</div>
|
||||||
|
<div class="update-vnf-nic__item">
|
||||||
|
<div class="update-vnf-nic__label">
|
||||||
|
<span class="update-vnf-nic__required">*</span>
|
||||||
|
<tooltip-label :title="$t('label.vnf.nic.management')" :tooltip="$t('label.vnf.nic.management.description')"/>
|
||||||
|
</div>
|
||||||
|
<a-switch v-model:checked="updateVnfNic.management" :checked="false" />
|
||||||
|
</div>
|
||||||
|
<div class="update-vnf-nic__item">
|
||||||
|
<div class="update-vnf-nic__label">
|
||||||
|
<tooltip-label :title="$t('label.description')" :tooltip="$t('label.vnf.nic.description')"/>
|
||||||
|
</div>
|
||||||
|
<a-input v-model:value="updateVnfNic.description"></a-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div :span="24" class="action-button">
|
||||||
|
<a-button @click="showEditVnfNic = false">{{ $t('label.cancel') }}</a-button>
|
||||||
|
<a-button ref="submit" type="primary" @click="editVnfNic">{{ $t('label.ok') }}</a-button>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
|
||||||
|
<a-divider/>
|
||||||
|
<div class="title">
|
||||||
|
<div class="form__label">
|
||||||
|
<tooltip-label :title="$t('label.vnf.details')" :tooltip="apiParams.vnfdetails.description"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="!showAddVnfDetail">
|
||||||
|
<a-button
|
||||||
|
type="dashed"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="!('updateVnfTemplate' in $store.getters.apis && isAdminOrOwner())"
|
||||||
|
@click="onShowAddVnfDetail">
|
||||||
|
<template #icon><plus-outlined /></template>
|
||||||
|
{{ $t('label.vnf.detail.add') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="showAddVnfDetail">
|
||||||
|
<a-input-group
|
||||||
|
type="text"
|
||||||
|
compact>
|
||||||
|
<a-auto-complete
|
||||||
|
class="detail-input"
|
||||||
|
ref="keyElm"
|
||||||
|
:filterOption="filterOption"
|
||||||
|
v-model:value="newKey"
|
||||||
|
:options="detailKeys"
|
||||||
|
:placeholder="$t('label.name')" />
|
||||||
|
<a-input
|
||||||
|
class="tag-disabled-input"
|
||||||
|
style=" width: 30px; border-left: 0; pointer-events: none; text-align: center"
|
||||||
|
placeholder="="
|
||||||
|
disabled />
|
||||||
|
<a-select
|
||||||
|
v-if="newKey === 'access_methods'"
|
||||||
|
class="detail-input"
|
||||||
|
v-model:value="newValues"
|
||||||
|
mode="multiple"
|
||||||
|
:placeholder="$t('label.value')"
|
||||||
|
:filterOption="filterOption">
|
||||||
|
<a-select-option v-for="opt in detailValues" :key="opt.value" :label="opt.value">
|
||||||
|
<span>
|
||||||
|
{{ opt.value }}
|
||||||
|
</span>
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-input
|
||||||
|
v-else
|
||||||
|
class="detail-input"
|
||||||
|
:filterOption="filterOption"
|
||||||
|
v-model:value="newValue"
|
||||||
|
:options="detailValues"
|
||||||
|
:placeholder="$t('label.value')" />
|
||||||
|
<tooltip-button :tooltip="$t('label.add.setting')" :shape="null" icon="check-outlined" @onClick="addVnfDetail" buttonClass="detail-button" />
|
||||||
|
<tooltip-button :tooltip="$t('label.cancel')" :shape="null" icon="close-outlined" @onClick="closeVnfDetail" buttonClass="detail-button" />
|
||||||
|
</a-input-group>
|
||||||
|
<p v-if="error" style="color: red"> {{ $t(error) }} </p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-list size="large">
|
||||||
|
<a-list-item :key="index" v-for="(item, index) in vnfDetails">
|
||||||
|
<a-list-item-meta>
|
||||||
|
<template #title>
|
||||||
|
{{ item.name }}
|
||||||
|
</template>
|
||||||
|
<template #description>
|
||||||
|
<div v-if="item.edit" style="display: flex">
|
||||||
|
<a-select
|
||||||
|
v-if="item.name === 'access_methods'"
|
||||||
|
class="detail-input"
|
||||||
|
v-model:value="item.values"
|
||||||
|
mode="multiple"
|
||||||
|
:placeholder="$t('label.value')"
|
||||||
|
:filterOption="filterOption">
|
||||||
|
<a-select-option v-for="opt in getEditDetailOptions(vnfDetailOptions[item.name])" :key="opt.value" :label="opt.value">
|
||||||
|
<span>
|
||||||
|
{{ opt.value }}
|
||||||
|
</span>
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-auto-complete
|
||||||
|
v-else
|
||||||
|
style="width: 100%"
|
||||||
|
v-model:value="item.displayvalue"
|
||||||
|
:options="getEditDetailOptions(vnfDetailOptions[item.name])"
|
||||||
|
@change="val => handleInputChange(val, index)"
|
||||||
|
@pressEnter="e => updateVnfDetail(index)" />
|
||||||
|
<tooltip-button
|
||||||
|
buttonClass="edit-button"
|
||||||
|
:tooltip="$t('label.cancel')"
|
||||||
|
@onClick="hideEditVnfDetail(index)"
|
||||||
|
v-if="item.edit"
|
||||||
|
iconType="close-circle-two-tone"
|
||||||
|
iconTwoToneColor="#f5222d" />
|
||||||
|
<tooltip-button
|
||||||
|
buttonClass="edit-button"
|
||||||
|
:tooltip="$t('label.ok')"
|
||||||
|
@onClick="updateVnfDetail(index)"
|
||||||
|
v-if="item.edit"
|
||||||
|
iconType="check-circle-two-tone"
|
||||||
|
iconTwoToneColor="#52c41a" />
|
||||||
|
</div>
|
||||||
|
<span v-else style="word-break: break-all">{{ item.displayvalue }}</span>
|
||||||
|
</template>
|
||||||
|
</a-list-item-meta>
|
||||||
|
<template #actions>
|
||||||
|
<div
|
||||||
|
v-if="'updateVnfTemplate' in $store.getters.apis && isAdminOrOwner()">
|
||||||
|
<tooltip-button
|
||||||
|
:tooltip="$t('label.edit')"
|
||||||
|
icon="edit-outlined"
|
||||||
|
@onClick="showEditVnfDetail(index)" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="'updateVnfTemplate' in $store.getters.apis && isAdminOrOwner()">
|
||||||
|
<a-popconfirm
|
||||||
|
:title="`${$t('label.delete.setting')}?`"
|
||||||
|
@confirm="deleteVnfDetail(index)"
|
||||||
|
:okText="$t('label.yes')"
|
||||||
|
:cancelText="$t('label.no')"
|
||||||
|
placement="left"
|
||||||
|
>
|
||||||
|
<tooltip-button :tooltip="$t('label.delete')" type="primary" :danger="true" icon="delete-outlined" />
|
||||||
|
</a-popconfirm>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-list-item>
|
||||||
|
</a-list>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, reactive } from 'vue'
|
||||||
|
import { api } from '@/api'
|
||||||
|
import Status from '@/components/widgets/Status'
|
||||||
|
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||||
|
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TemplateVnfSettings',
|
||||||
|
components: {
|
||||||
|
TooltipButton,
|
||||||
|
TooltipLabel,
|
||||||
|
Status
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
resourceType: 'VnfTemplate',
|
||||||
|
vnfDetailOptions: {},
|
||||||
|
columns: [],
|
||||||
|
vnfNics: [],
|
||||||
|
previousVnfNics: [],
|
||||||
|
showAddVnfNic: false,
|
||||||
|
showEditVnfNic: false,
|
||||||
|
newVnfNic: {
|
||||||
|
deviceid: null,
|
||||||
|
name: null,
|
||||||
|
required: true,
|
||||||
|
management: false,
|
||||||
|
description: null
|
||||||
|
},
|
||||||
|
updateVnfNic: {
|
||||||
|
deviceid: null,
|
||||||
|
name: null,
|
||||||
|
required: true,
|
||||||
|
management: false,
|
||||||
|
description: null
|
||||||
|
},
|
||||||
|
vnfDetails: [],
|
||||||
|
previousVnfDetails: [],
|
||||||
|
showAddVnfDetail: false,
|
||||||
|
newKey: '',
|
||||||
|
newValue: '',
|
||||||
|
newValues: [],
|
||||||
|
error: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeCreate () {
|
||||||
|
this.apiParams = this.$getApiParams('updateVnfTemplate')
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
detailKeys () {
|
||||||
|
return Object.keys(this.vnfDetailOptions).map(key => {
|
||||||
|
return { value: key }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
detailValues () {
|
||||||
|
if (!this.newKey) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
if (!Array.isArray(this.vnfDetailOptions[this.newKey])) {
|
||||||
|
if (this.vnfDetailOptions[this.newKey]) {
|
||||||
|
return { value: this.vnfDetailOptions[this.newKey] }
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.vnfDetailOptions[this.newKey].map(value => {
|
||||||
|
return { value: value }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.columns = [
|
||||||
|
{
|
||||||
|
title: this.$t('label.deviceid'),
|
||||||
|
dataIndex: 'deviceid',
|
||||||
|
slots: { customRender: 'deviceid' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('label.name'),
|
||||||
|
dataIndex: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('label.required'),
|
||||||
|
dataIndex: 'required',
|
||||||
|
slots: { customRender: 'required' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('label.vnf.nic.management'),
|
||||||
|
dataIndex: 'management',
|
||||||
|
slots: { customRender: 'management' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('label.description'),
|
||||||
|
dataIndex: 'description',
|
||||||
|
slots: { customRender: 'description' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('label.action'),
|
||||||
|
slots: { customRender: 'actions' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.columns.push({
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'action',
|
||||||
|
width: 100,
|
||||||
|
slots: { customRender: 'action' }
|
||||||
|
})
|
||||||
|
|
||||||
|
const userInfo = this.$store.getters.userInfo
|
||||||
|
if (!['Admin'].includes(userInfo.roletype) &&
|
||||||
|
(userInfo.account !== this.resource.account || userInfo.domain !== this.resource.domain)) {
|
||||||
|
this.columns = this.columns.filter(col => { return col.dataIndex !== 'status' })
|
||||||
|
}
|
||||||
|
this.initForm()
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
loading (newData, oldData) {
|
||||||
|
if (!newData && !this.showGroupActionModal) {
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initForm () {
|
||||||
|
this.formRef = ref()
|
||||||
|
this.form = reactive({})
|
||||||
|
this.rules = reactive({
|
||||||
|
zoneid: [{ type: 'array', required: true, message: this.$t('message.error.select') }]
|
||||||
|
})
|
||||||
|
this.previousVnfNics = this.resource.vnfnics?.slice() || []
|
||||||
|
this.previousVnfDetails = []
|
||||||
|
if (this.resource.vnfdetails) {
|
||||||
|
this.previousVnfDetails = Object.keys(this.resource.vnfdetails).map(k => {
|
||||||
|
return {
|
||||||
|
name: k,
|
||||||
|
value: this.resource.vnfdetails[k],
|
||||||
|
displayvalue: this.getDisplayValue(k, this.resource.vnfdetails[k]),
|
||||||
|
values: k === 'access_methods' ? this.resource.vnfdetails[k].split(',') : null,
|
||||||
|
edit: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
api('listDetailOptions', { resourcetype: this.resourceType }).then(json => {
|
||||||
|
this.vnfDetailOptionsInApi = json.listdetailoptionsresponse.detailoptions.details
|
||||||
|
this.vnfDetailOptions = {}
|
||||||
|
Object.keys(this.vnfDetailOptionsInApi).sort().forEach(k => {
|
||||||
|
this.vnfDetailOptions[k] = this.vnfDetailOptionsInApi[k]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchData () {
|
||||||
|
this.vnfNics = this.previousVnfNics.slice() || []
|
||||||
|
this.vnfDetails = this.previousVnfDetails.slice() || []
|
||||||
|
},
|
||||||
|
isAdminOrOwner () {
|
||||||
|
return ['Admin'].includes(this.$store.getters.userInfo.roletype) ||
|
||||||
|
(this.resource.domainid === this.$store.getters.userInfo.domainid && this.resource.account === this.$store.getters.userInfo.account) ||
|
||||||
|
this.resource.project && this.resource.projectid === this.$store.getters.project.id
|
||||||
|
},
|
||||||
|
onShowAddVnfNic () {
|
||||||
|
this.showAddVnfNic = true
|
||||||
|
},
|
||||||
|
filterOption (input, option) {
|
||||||
|
return (
|
||||||
|
option.value.toUpperCase().indexOf(input.toUpperCase()) >= 0
|
||||||
|
)
|
||||||
|
},
|
||||||
|
addVnfNic () {
|
||||||
|
if (!this.newVnfNic.deviceid || !this.newVnfNic.name) {
|
||||||
|
this.$notification.error({
|
||||||
|
message: this.$t('message.request.failed'),
|
||||||
|
description: this.$t('message.please.enter.valid.value')
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.newVnfNic && this.newVnfNic.deviceid && this.newVnfNic.name) {
|
||||||
|
this.vnfNics.push({
|
||||||
|
deviceid: this.newVnfNic.deviceid,
|
||||||
|
name: this.newVnfNic.name,
|
||||||
|
required: this.newVnfNic.required,
|
||||||
|
management: this.newVnfNic.management,
|
||||||
|
description: this.newVnfNic.description
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.updateVnfTemplateNics()
|
||||||
|
},
|
||||||
|
deleteVnfNic (record) {
|
||||||
|
for (var index = 0; index < this.vnfNics.length; index++) {
|
||||||
|
var nic = this.vnfNics[index]
|
||||||
|
if (nic.deviceid === record.deviceid) {
|
||||||
|
this.vnfNics.splice(index, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.updateVnfTemplateNics()
|
||||||
|
},
|
||||||
|
onShowEditVnfNic (record) {
|
||||||
|
this.updateVnfNic.deviceid = record.deviceid
|
||||||
|
this.updateVnfNic.name = record.name
|
||||||
|
this.updateVnfNic.required = record.required
|
||||||
|
this.updateVnfNic.management = record.management
|
||||||
|
this.updateVnfNic.description = record.description
|
||||||
|
this.showEditVnfNic = true
|
||||||
|
},
|
||||||
|
getEditDetailOptions (values) {
|
||||||
|
if (!values) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var data = values.map(value => { return { value: value } })
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
editVnfNic () {
|
||||||
|
if (!this.updateVnfNic.name) {
|
||||||
|
this.$notification.error({
|
||||||
|
message: this.$t('message.request.failed'),
|
||||||
|
description: this.$t('message.please.enter.valid.value')
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.updateVnfNic && this.updateVnfNic.name) {
|
||||||
|
for (var index = 0; index < this.vnfNics.length; index++) {
|
||||||
|
var nic = this.vnfNics[index]
|
||||||
|
if (nic.deviceid === this.updateVnfNic.deviceid) {
|
||||||
|
this.vnfNics[index] = this.updateVnfNic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.updateVnfTemplateNics()
|
||||||
|
},
|
||||||
|
moveVnfNicUp (record) {
|
||||||
|
const deviceid = record.deviceid
|
||||||
|
let currentNic = null
|
||||||
|
let previousNic = null
|
||||||
|
for (var index = 0; index < this.vnfNics.length; index++) {
|
||||||
|
var nic = this.vnfNics[index]
|
||||||
|
if (nic.deviceid === record.deviceid) {
|
||||||
|
currentNic = JSON.parse(JSON.stringify(nic))
|
||||||
|
this.vnfNics[index] = currentNic
|
||||||
|
} else if (nic.deviceid === record.deviceid - 1) {
|
||||||
|
previousNic = JSON.parse(JSON.stringify(nic))
|
||||||
|
this.vnfNics[index] = previousNic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentNic && previousNic) {
|
||||||
|
currentNic.deviceid = deviceid - 1
|
||||||
|
previousNic.deviceid = deviceid
|
||||||
|
const currentRequired = currentNic.required
|
||||||
|
currentNic.required = previousNic.required
|
||||||
|
previousNic.required = currentRequired
|
||||||
|
this.updateVnfTemplateNics()
|
||||||
|
} else {
|
||||||
|
this.$notification.error({
|
||||||
|
message: this.$t('message.request.failed'),
|
||||||
|
description: this.$t('message.vnf.nic.move.up.fail')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
moveVnfNicDown (record) {
|
||||||
|
const deviceid = record.deviceid
|
||||||
|
let currentNic = null
|
||||||
|
let nextNic = null
|
||||||
|
for (var index = 0; index < this.vnfNics.length; index++) {
|
||||||
|
var nic = this.vnfNics[index]
|
||||||
|
if (nic.deviceid === record.deviceid) {
|
||||||
|
currentNic = JSON.parse(JSON.stringify(nic))
|
||||||
|
this.vnfNics[index] = currentNic
|
||||||
|
} else if (nic.deviceid === record.deviceid + 1) {
|
||||||
|
nextNic = JSON.parse(JSON.stringify(nic))
|
||||||
|
this.vnfNics[index] = nextNic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentNic && nextNic) {
|
||||||
|
currentNic.deviceid = deviceid + 1
|
||||||
|
nextNic.deviceid = deviceid
|
||||||
|
const currentRequired = currentNic.required
|
||||||
|
currentNic.required = nextNic.required
|
||||||
|
nextNic.required = currentRequired
|
||||||
|
this.updateVnfTemplateNics()
|
||||||
|
} else {
|
||||||
|
this.$notification.error({
|
||||||
|
message: this.$t('message.request.failed'),
|
||||||
|
description: this.$t('message.vnf.nic.move.down.fail')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateVnfTemplateDetails () {
|
||||||
|
this.updateVnfTemplate(true, false)
|
||||||
|
},
|
||||||
|
updateVnfTemplateNics () {
|
||||||
|
this.updateVnfTemplate(false, true)
|
||||||
|
},
|
||||||
|
updateVnfTemplate (areDetailsChanged, areNicsChanged) {
|
||||||
|
const apiName = 'updateVnfTemplate'
|
||||||
|
if (!(apiName in this.$store.getters.apis)) {
|
||||||
|
this.$notification.error({
|
||||||
|
message: this.$t('error.execute.api.failed') + ' ' + apiName,
|
||||||
|
description: this.$t('message.user.not.permitted.api')
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = { id: this.resource.id }
|
||||||
|
if (areDetailsChanged) {
|
||||||
|
if (this.vnfDetails.length === 0) {
|
||||||
|
params.cleanupvnfdetails = true
|
||||||
|
} else {
|
||||||
|
this.vnfDetails.forEach(function (item, index) {
|
||||||
|
params['vnfdetails[0].' + item.name] = item.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (areNicsChanged) {
|
||||||
|
let i = 0
|
||||||
|
if (this.vnfNics.length === 0) {
|
||||||
|
params.cleanupvnfnics = true
|
||||||
|
}
|
||||||
|
for (var index = 0; index < this.vnfNics.length; index++) {
|
||||||
|
var nic = this.vnfNics[index]
|
||||||
|
params['vnfnics[' + i + '].deviceid'] = nic.deviceid
|
||||||
|
params['vnfnics[' + i + '].name'] = nic.name
|
||||||
|
params['vnfnics[' + i + '].required'] = nic.required
|
||||||
|
params['vnfnics[' + i + '].management'] = nic.management
|
||||||
|
params['vnfnics[' + i + '].description'] = nic.description
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
api(apiName, params).then(json => {
|
||||||
|
this.vnfNics = json.updatetemplateresponse.template.vnfnics || []
|
||||||
|
const details = json.updatetemplateresponse.template.vnfdetails || []
|
||||||
|
this.vnfDetails = Object.keys(details).map(k => {
|
||||||
|
return {
|
||||||
|
name: k,
|
||||||
|
value: details[k],
|
||||||
|
displayvalue: this.getDisplayValue(k, details[k]),
|
||||||
|
values: k === 'access_methods' ? details[k].split(',') : null,
|
||||||
|
edit: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.previousVnfNics = this.vnfNics.slice()
|
||||||
|
this.previousVnfDetails = this.vnfDetails.slice()
|
||||||
|
this.closeVnfDetail()
|
||||||
|
this.closeVnfNicModal()
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notifyError(error)
|
||||||
|
this.fetchData()
|
||||||
|
}).finally(f => {
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getDisplayValue (name, value) {
|
||||||
|
return name.includes('password') ? '********' : value
|
||||||
|
},
|
||||||
|
showEditVnfDetail (index) {
|
||||||
|
this.vnfDetails[index].edit = true
|
||||||
|
this.vnfDetails[index].originalValue = this.vnfDetails[index].value
|
||||||
|
},
|
||||||
|
hideEditVnfDetail (index) {
|
||||||
|
this.vnfDetails[index].edit = false
|
||||||
|
this.vnfDetails[index].value = this.vnfDetails[index].originalValue
|
||||||
|
},
|
||||||
|
handleInputChange (val, index) {
|
||||||
|
this.vnfDetails[index].value = val
|
||||||
|
},
|
||||||
|
updateVnfDetail (index) {
|
||||||
|
if (Array.isArray(this.vnfDetails[index].values) && this.vnfDetails[index].values.length > 0) {
|
||||||
|
this.vnfDetails[index].value = this.vnfDetails[index].values.join(',')
|
||||||
|
}
|
||||||
|
this.vnfDetails[index].value = this.vnfDetails[index].displayvalue
|
||||||
|
this.vnfDetails[index].displayvalue = this.getDisplayValue(this.vnfDetails[index].name, this.vnfDetails[index].value)
|
||||||
|
this.updateVnfTemplateDetails()
|
||||||
|
},
|
||||||
|
onShowAddVnfDetail () {
|
||||||
|
this.showAddVnfDetail = true
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.keyElm.focus()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addVnfDetail () {
|
||||||
|
if (this.newKey === '' || (this.newValue === '' && this.newValues.length === 0)) {
|
||||||
|
this.error = this.$t('message.error.provide.setting')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.error = false
|
||||||
|
this.newValueString = ''
|
||||||
|
if (this.newValues.length > 0) {
|
||||||
|
this.newValueString = this.newValues.join(',')
|
||||||
|
} else {
|
||||||
|
this.newValueString = this.newValue
|
||||||
|
}
|
||||||
|
this.vnfDetails.push({ name: this.newKey, value: this.newValueString })
|
||||||
|
this.updateVnfTemplateDetails()
|
||||||
|
},
|
||||||
|
deleteVnfDetail (index) {
|
||||||
|
this.vnfDetails.splice(index, 1)
|
||||||
|
this.updateVnfTemplateDetails()
|
||||||
|
},
|
||||||
|
closeVnfDetail () {
|
||||||
|
this.newKey = ''
|
||||||
|
this.newValue = ''
|
||||||
|
this.newValues = []
|
||||||
|
this.error = false
|
||||||
|
this.showAddVnfDetail = false
|
||||||
|
},
|
||||||
|
closeVnfNicModal () {
|
||||||
|
this.showAddVnfNic = false
|
||||||
|
this.showEditVnfNic = false
|
||||||
|
this.newVnfNic = {
|
||||||
|
deviceid: null,
|
||||||
|
name: null,
|
||||||
|
required: true,
|
||||||
|
management: false,
|
||||||
|
description: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.row-element {
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-input {
|
||||||
|
width: calc(calc(100% / 2) - 45px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-button {
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shift-btns {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shift-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--rotated {
|
||||||
|
font-size: 10px;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-vnf-nic {
|
||||||
|
&__item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__required {
|
||||||
|
margin-right: 5px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-vnf-nic {
|
||||||
|
&__item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__required {
|
||||||
|
margin-right: 5px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -205,7 +205,7 @@ export default {
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
templatetypes: ['BUILTIN', 'USER', 'SYSTEM', 'ROUTING'],
|
templatetypes: ['BUILTIN', 'USER', 'SYSTEM', 'ROUTING', 'VNF'],
|
||||||
rootDisk: {},
|
rootDisk: {},
|
||||||
nicAdapterType: {},
|
nicAdapterType: {},
|
||||||
keyboardType: {},
|
keyboardType: {},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you 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.
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-table
|
||||||
|
size="small"
|
||||||
|
style="overflow-y: auto"
|
||||||
|
:columns="columns"
|
||||||
|
:dataSource="virtualmachines"
|
||||||
|
:rowKey="item => item.id"
|
||||||
|
:pagination="false"
|
||||||
|
:loading="fetchLoading"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, text, record }">
|
||||||
|
<template v-if="column.key === 'name'">
|
||||||
|
<router-link :to="{ path: '/vnfapp/' + record.id }" >{{ text }}</router-link>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'status'">
|
||||||
|
<status class="status" :text="record.state" displayText />
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'vmip'">
|
||||||
|
<status class="status" :text="record.vmip" displayText />
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'templatename'">
|
||||||
|
<router-link :to="{ path: '/template/' + record.templateid }" >{{ record.templatename || record.templateid }}</router-link>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'osdisplayname'">
|
||||||
|
<status class="status" :text="record.osdisplayname" displayText />
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'hostname'">
|
||||||
|
<router-link :to="{ path: '/host/' + record.hostid }" >{{ record.hostname || record.hostid }}</router-link>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { api } from '@/api'
|
||||||
|
import Status from '@/components/widgets/Status'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VnfAppliancesTab',
|
||||||
|
components: {
|
||||||
|
Status
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
resource: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
fetchLoading: false,
|
||||||
|
virtualmachines: [],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
title: this.$t('label.name'),
|
||||||
|
dataIndex: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
title: this.$t('label.status'),
|
||||||
|
dataIndex: 'state'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('label.ipaddress'),
|
||||||
|
dataIndex: 'vmip'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'templatename',
|
||||||
|
title: this.$t('label.templatename'),
|
||||||
|
dataIndex: 'templatename'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: this.$t('label.osdisplayname'),
|
||||||
|
dataIndex: 'osdisplayname'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'hostname',
|
||||||
|
title: this.$t('label.hostname'),
|
||||||
|
dataIndex: 'hostname'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.fetchData()
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
resource: {
|
||||||
|
deep: true,
|
||||||
|
handler (newItem) {
|
||||||
|
if (!newItem || !newItem.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.fetchData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchData () {
|
||||||
|
var params = {
|
||||||
|
details: 'servoff,tmpl,nics',
|
||||||
|
isVnf: true,
|
||||||
|
listAll: true
|
||||||
|
}
|
||||||
|
if (this.$route.fullPath.startsWith('/vpc')) {
|
||||||
|
params.vpcid = this.resource.id
|
||||||
|
} else {
|
||||||
|
params.networkid = this.resource.id
|
||||||
|
}
|
||||||
|
this.fetchLoading = true
|
||||||
|
api('listVirtualMachines', params).then(json => {
|
||||||
|
this.virtualmachines = json.listvirtualmachinesresponse.virtualmachine || []
|
||||||
|
for (const vm of this.virtualmachines) {
|
||||||
|
for (const vmnic of vm.nic) {
|
||||||
|
if (vmnic.networkid === this.resource.id) {
|
||||||
|
vm.vmip = vmnic.ipaddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
this.$notifyError(error)
|
||||||
|
}).finally(() => {
|
||||||
|
this.fetchLoading = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.status {
|
||||||
|
margin-top: -5px;
|
||||||
|
|
||||||
|
&--end {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -360,6 +360,9 @@
|
||||||
<a-tab-pane :tab="$t('label.virtual.routers')" key="vr" v-if="$store.getters.userInfo.roletype === 'Admin'">
|
<a-tab-pane :tab="$t('label.virtual.routers')" key="vr" v-if="$store.getters.userInfo.roletype === 'Admin'">
|
||||||
<RoutersTab :resource="resource" :loading="loading" />
|
<RoutersTab :resource="resource" :loading="loading" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<a-tab-pane :tab="$t('label.vnf.appliances')" key="vnf" v-if="'deployVnfAppliance' in $store.getters.apis">
|
||||||
|
<VnfAppliancesTab :resource="resource" :loading="loading" />
|
||||||
|
</a-tab-pane>
|
||||||
<a-tab-pane :tab="$t('label.events')" key="events" v-if="'listEvents' in $store.getters.apis">
|
<a-tab-pane :tab="$t('label.events')" key="events" v-if="'listEvents' in $store.getters.apis">
|
||||||
<events-tab :resource="resource" resourceType="Vpc" :loading="loading" />
|
<events-tab :resource="resource" resourceType="Vpc" :loading="loading" />
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
|
@ -382,6 +385,7 @@ import Status from '@/components/widgets/Status'
|
||||||
import IpAddressesTab from './IpAddressesTab'
|
import IpAddressesTab from './IpAddressesTab'
|
||||||
import RoutersTab from './RoutersTab'
|
import RoutersTab from './RoutersTab'
|
||||||
import VpcTiersTab from './VpcTiersTab'
|
import VpcTiersTab from './VpcTiersTab'
|
||||||
|
import VnfAppliancesTab from './VnfAppliancesTab'
|
||||||
import EventsTab from '@/components/view/EventsTab'
|
import EventsTab from '@/components/view/EventsTab'
|
||||||
import AnnotationsTab from '@/components/view/AnnotationsTab'
|
import AnnotationsTab from '@/components/view/AnnotationsTab'
|
||||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||||
|
|
@ -394,6 +398,7 @@ export default {
|
||||||
IpAddressesTab,
|
IpAddressesTab,
|
||||||
RoutersTab,
|
RoutersTab,
|
||||||
VpcTiersTab,
|
VpcTiersTab,
|
||||||
|
VnfAppliancesTab,
|
||||||
EventsTab,
|
EventsTab,
|
||||||
AnnotationsTab,
|
AnnotationsTab,
|
||||||
ResourceIcon
|
ResourceIcon
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue