From b091ea6ead7cc7be3c66d2173bfd2cab232a47ad Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Fri, 22 Feb 2013 02:07:08 +0530 Subject: [PATCH 001/120] scale UP CPU and memory UI --- ui/css/cloudstack3.css | 6 ++++-- ui/scripts/instances.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index efdae3523bf..0753cc4ed07 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -11277,7 +11277,8 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -168px -31px; } -.reset .icon { +.reset .icon , +.scaleUp .icon{ background-position: -168px -31px; } @@ -11286,7 +11287,8 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it background-position: -168px -613px; } -.reset:hover .icon { +.reset:hover .icon, +.scaleUp:hover .icon { background-position: -168px -613px; } diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 264b5a1cbbe..c21e0319f85 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -1240,6 +1240,44 @@ } }, + scaleUp:{ + label:'scaleUp VM', + action: function(args) { + $.ajax({ + url: createURL("scaleVirtualMachine&id=" + args.context.instances[0].id), + dataType: "json", + async: true, + success: function(json) { + var jid = json.scaleupvirtualmachineresponse.jobid; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.virtualmachine; + }, + getActionFilter: function() { + return vmActionfilter; + } + } + } + ); + } + }); + }, + messages: { + confirm: function(args) { + return 'Do you really want to scale Up your instance ?'; + }, + notification: function(args) { + return 'Instance Scaled Up'; + } + }, + notification: { + poll: pollAsyncJobResult + } + + }, + viewConsole: { label: 'label.view.console', action: { @@ -1488,6 +1526,7 @@ allowedActions.push("destroy"); allowedActions.push("changeService"); allowedActions.push("reset"); + allowedactions.push("scaleUp"); if (isAdmin()) allowedActions.push("migrate"); @@ -1511,6 +1550,8 @@ allowedActions.push("destroy"); allowedActions.push("reset"); allowedActions.push("snapshot"); + allowedActions.push("scaleUp"); + if(isAdmin()) allowedActions.push("migrateToAnotherStorage"); From 534f5540a33d47ea5bd84c58c94def2abfc0e9db Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Fri, 22 Feb 2013 02:16:20 +0530 Subject: [PATCH 002/120] scale UP CPU and memory UI --- ui/scripts/instances.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index c21e0319f85..a25e2405460 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -1526,7 +1526,7 @@ allowedActions.push("destroy"); allowedActions.push("changeService"); allowedActions.push("reset"); - allowedactions.push("scaleUp"); + allowedActions.push("scaleUp"); if (isAdmin()) allowedActions.push("migrate"); From cf72aa32747a44ef876b9566d5c85db2f189b84e Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Fri, 29 Mar 2013 16:24:24 -0700 Subject: [PATCH 003/120] Fixes/improvements for VPC feature: 1) Added comments to VPC/VPCService/VPCManager interfaces 2) Moved VPC offering related methods from VpcService to the new interface - VpcProvisioningService 3) Fixed static nat creation in the VPC - used to result in NPE due to invalid method referencing while obtaining VPC VR information --- api/src/com/cloud/network/NetworkModel.java | 2 + api/src/com/cloud/network/vpc/Vpc.java | 43 ++++++- .../com/cloud/network/vpc/VpcOffering.java | 21 +++- .../network/vpc/VpcProvisioningService.java | 46 ++++++++ api/src/com/cloud/network/vpc/VpcService.java | 101 +++++++++++------ .../org/apache/cloudstack/api/BaseCmd.java | 2 + .../admin/vpc/CreateVPCOfferingCmd.java | 4 +- .../admin/vpc/DeleteVPCOfferingCmd.java | 2 +- .../admin/vpc/UpdateVPCOfferingCmd.java | 2 +- .../user/network/UpdateNetworkCmd.java | 9 +- .../command/user/vpc/ListVPCOfferingsCmd.java | 2 +- server/src/com/cloud/api/ApiDBUtils.java | 77 +++++++++++-- .../src/com/cloud/network/NetworkManager.java | 4 +- .../com/cloud/network/NetworkManagerImpl.java | 1 - .../com/cloud/network/NetworkModelImpl.java | 13 +++ .../com/cloud/network/NetworkServiceImpl.java | 7 ++ .../element/VpcVirtualRouterElement.java | 21 ++-- .../VpcVirtualNetworkApplianceManager.java | 6 + ...VpcVirtualNetworkApplianceManagerImpl.java | 15 ++- .../src/com/cloud/network/vpc/VpcManager.java | 84 ++++++++------ .../com/cloud/network/vpc/VpcManagerImpl.java | 77 +++---------- .../com/cloud/network/vpc/VpcOfferingVO.java | 1 - server/src/com/cloud/network/vpc/VpcVO.java | 7 -- .../cloud/network/MockNetworkModelImpl.java | 6 + .../com/cloud/vpc/MockNetworkModelImpl.java | 6 + .../com/cloud/vpc/MockVpcManagerImpl.java | 106 ++---------------- ...MockVpcVirtualNetworkApplianceManager.java | 6 + server/test/com/cloud/vpc/VpcApiUnitTest.java | 37 +----- 28 files changed, 398 insertions(+), 310 deletions(-) create mode 100644 api/src/com/cloud/network/vpc/VpcProvisioningService.java diff --git a/api/src/com/cloud/network/NetworkModel.java b/api/src/com/cloud/network/NetworkModel.java index 916f28a00f2..c1f1674bad7 100644 --- a/api/src/com/cloud/network/NetworkModel.java +++ b/api/src/com/cloud/network/NetworkModel.java @@ -261,4 +261,6 @@ public interface NetworkModel { String getStartIpv6Address(long id); Nic getPlaceholderNic(Network network, Long podId); + + boolean isProviderEnabledInZone(long zoneId, String provider); } \ No newline at end of file diff --git a/api/src/com/cloud/network/vpc/Vpc.java b/api/src/com/cloud/network/vpc/Vpc.java index c07077f7b7e..249e80f1aff 100644 --- a/api/src/com/cloud/network/vpc/Vpc.java +++ b/api/src/com/cloud/network/vpc/Vpc.java @@ -20,32 +20,63 @@ import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; -import com.cloud.network.Network; - public interface Vpc extends ControlledEntity, Identity, InternalIdentity { + public enum State { Enabled, Inactive } - public static final String _supportedProviders = Network.Provider.VPCVirtualRouter.getName(); - - boolean readyToUse(); - + /** + * + * @return VPC name + */ String getName(); + + /** + * @return the id of the zone the VPC belongs to + */ long getZoneId(); + + /** + * @return super CIDR of the VPC. All the networks participating in VPC, should have CIDRs that are the part of the super cidr + */ String getCidr(); + /** + * + * @return VPC state + */ State getState(); + + /** + * + * @return VPC offering id - the offering that VPC is created from + */ long getVpcOfferingId(); + + /** + * + * @return VPC display text + */ String getDisplayText(); + + /** + * + * @return VPC network domain. All networks participating in the VPC, become the part of the same network domain + */ String getNetworkDomain(); + + /** + * + * @return true if restart is required for the VPC; false otherwise + */ boolean isRestartRequired(); } diff --git a/api/src/com/cloud/network/vpc/VpcOffering.java b/api/src/com/cloud/network/vpc/VpcOffering.java index 1acfcd21418..3961d0aaba7 100644 --- a/api/src/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/com/cloud/network/vpc/VpcOffering.java @@ -27,18 +27,33 @@ public interface VpcOffering extends InternalIdentity, Identity { public static final String defaultVPCOfferingName = "Default VPC offering"; + /** + * + * @return VPC offering name + */ String getName(); - String getUniqueName(); - + + /** + * @return VPC offering display text + */ String getDisplayText(); + + /** + * + * @return VPC offering state + */ State getState(); + /** + * + * @return true if offering is default - came with the cloudStack fresh install; false otherwise + */ boolean isDefault(); /** - * @return + * @return service offering id used by VPC virutal router */ Long getServiceOfferingId(); diff --git a/api/src/com/cloud/network/vpc/VpcProvisioningService.java b/api/src/com/cloud/network/vpc/VpcProvisioningService.java new file mode 100644 index 00000000000..70676ce07ab --- /dev/null +++ b/api/src/com/cloud/network/vpc/VpcProvisioningService.java @@ -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.network.vpc; + +import java.util.List; +import java.util.Map; + +public interface VpcProvisioningService { + + public VpcOffering getVpcOffering(long vpcOfferingId); + + public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders); + + List listVpcOfferings(Long id, String name, String displayText, List supportedServicesStr, + Boolean isDefault, String keyword, String state, Long startIndex, Long pageSizeVal); + + /** + * @param offId + * @return + */ + public boolean deleteVpcOffering(long offId); + + /** + * @param vpcOffId + * @param vpcOfferingName + * @param displayText + * @param state + * @return + */ + public VpcOffering updateVpcOffering(long vpcOffId, String vpcOfferingName, String displayText, String state); + +} diff --git a/api/src/com/cloud/network/vpc/VpcService.java b/api/src/com/cloud/network/vpc/VpcService.java index 9bf1beea5f0..07ce89b0a3f 100644 --- a/api/src/com/cloud/network/vpc/VpcService.java +++ b/api/src/com/cloud/network/vpc/VpcService.java @@ -18,7 +18,6 @@ package com.cloud.network.vpc; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; @@ -31,45 +30,29 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IpAddress; import com.cloud.network.Network; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; -import com.cloud.user.Account; -import com.cloud.user.User; import com.cloud.utils.Pair; public interface VpcService { - public VpcOffering getVpcOffering(long vpcOfferingId); - - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders); - + /**Returns existing VPC found by id + * + * @param vpcId + * @return + */ public Vpc getVpc(long vpcId); - public Vpc getActiveVpc(long vpcId); - + + /** + * Returns all the Guest networks that are part of VPC + * + * @param vpcId + * @return + */ public List getVpcNetworks(long vpcId); - Map> getVpcOffSvcProvidersMap(long vpcOffId); - - List listVpcOfferings(Long id, String name, String displayText, List supportedServicesStr, - Boolean isDefault, String keyword, String state, Long startIndex, Long pageSizeVal); - - /** - * @param offId - * @return - */ - public boolean deleteVpcOffering(long offId); - - /** - * @param vpcOffId - * @param vpcOfferingName - * @param displayText - * @param state - * @return - */ - public VpcOffering updateVpcOffering(long vpcOffId, String vpcOfferingName, String displayText, String state); - /** + * Persists VPC record in the database + * * @param zoneId * @param vpcOffId * @param vpcOwnerId @@ -83,7 +66,10 @@ public interface VpcService { public Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain) throws ResourceAllocationException; + /** + * Deletes a VPC + * * @param vpcId * @return * @throws InsufficientCapacityException @@ -92,7 +78,10 @@ public interface VpcService { */ public boolean deleteVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * Updates VPC with new name/displayText + * * @param vpcId * @param vpcName * @param displayText @@ -100,7 +89,10 @@ public interface VpcService { */ public Vpc updateVpc(long vpcId, String vpcName, String displayText); + /** + * Lists VPC(s) based on the parameters passed to the method call + * * @param id * @param vpcName * @param displayText @@ -127,6 +119,8 @@ public interface VpcService { Boolean restartRequired, Map tags, Long projectId); /** + * Starts VPC which includes starting VPC provider and applying all the neworking rules on the backend + * * @param vpcId * @param destroyOnFailure TODO * @return @@ -138,6 +132,8 @@ public interface VpcService { ResourceUnavailableException, InsufficientCapacityException; /** + * Shuts down the VPC which includes shutting down all VPC provider and rules cleanup on the backend + * * @param vpcId * @return * @throws ConcurrentOperationException @@ -145,16 +141,28 @@ public interface VpcService { */ boolean shutdownVpc(long vpcId) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * Restarts the VPC. VPC gets shutdown and started as a part of it + * * @param id * @return * @throws InsufficientCapacityException */ boolean restartVpc(long id) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; + /** + * Returns a Private gateway found in the VPC by id + * + * @param id + * @return + */ PrivateGateway getVpcPrivateGateway(long id); + /** + * Persists VPC private gateway in the Database. + * * @param vpcId TODO * @param physicalNetworkId * @param vlan @@ -172,6 +180,8 @@ public interface VpcService { ConcurrentOperationException, InsufficientCapacityException; /** + * Applies VPC private gateway on the backend, so it becomes functional + * * @param gatewayId * @param destroyOnFailure TODO * @return @@ -180,7 +190,10 @@ public interface VpcService { */ public PrivateGateway applyVpcPrivateGateway(long gatewayId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * Deletes VPC private gateway + * * @param id * @return * @throws ResourceUnavailableException @@ -188,52 +201,76 @@ public interface VpcService { */ boolean deleteVpcPrivateGateway(long gatewayId) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * Returns the list of Private gateways existing in the VPC + * * @param listPrivateGatewaysCmd * @return */ public Pair, Integer> listPrivateGateway(ListPrivateGatewaysCmd listPrivateGatewaysCmd); + /** + * Returns Static Route found by Id + * * @param routeId * @return */ StaticRoute getStaticRoute(long routeId); + /** + * Applies existing Static Routes to the VPC elements + * * @param vpcId * @return * @throws ResourceUnavailableException */ public boolean applyStaticRoutes(long vpcId) throws ResourceUnavailableException; + /** + * Deletes static route from the backend and the database + * * @param routeId * @return TODO * @throws ResourceUnavailableException */ public boolean revokeStaticRoute(long routeId) throws ResourceUnavailableException; + /** + * Persists static route entry in the Database + * * @param gatewayId * @param cidr * @return */ public StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException; + /** + * Lists static routes based on parameters passed to the call + * * @param listStaticRoutesCmd * @return */ public Pair, Integer> listStaticRoutes(ListStaticRoutesCmd cmd); + /** + * Returns gateway (VPN or Public) existign in the VPC + * * @param id * @return */ VpcGateway getVpcGateway(long id); + /** + * Associates IP address from the Public network, to the VPC + * * @param ipId * @param vpcId * @return @@ -245,6 +282,4 @@ public interface VpcService { IpAddress associateIPToVpc(long ipId, long vpcId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException; - public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr, String guestVmCidr); } diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 7ccb72e8fb9..78a2af36aa2 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -52,6 +52,7 @@ import com.cloud.network.firewall.NetworkACLService; import com.cloud.network.lb.LoadBalancingRulesService; import com.cloud.network.rules.RulesService; import com.cloud.network.security.SecurityGroupService; +import com.cloud.network.vpc.VpcProvisioningService; import com.cloud.network.vpc.VpcService; import com.cloud.network.vpn.RemoteAccessVpnService; import com.cloud.network.vpn.Site2SiteVpnService; @@ -132,6 +133,7 @@ public abstract class BaseCmd { @Inject public NetworkUsageService _networkUsageService; @Inject public VMSnapshotService _vmSnapshotService; @Inject public DataStoreProviderApiService dataStoreProviderApiService; + @Inject public VpcProvisioningService _vpcProvSvc; public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException; diff --git a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index 3c7956b7d7e..4a3a92a211c 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -98,7 +98,7 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd{ @Override public void create() throws ResourceAllocationException { - VpcOffering vpcOff = _vpcService.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices(), getServiceProviders()); + VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(getVpcOfferingName(), getDisplayText(), getSupportedServices(), getServiceProviders()); if (vpcOff != null) { this.setEntityId(vpcOff.getId()); this.setEntityUuid(vpcOff.getUuid()); @@ -109,7 +109,7 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd{ @Override public void execute() { - VpcOffering vpc = _vpcService.getVpcOffering(this.getEntityId()); + VpcOffering vpc = _vpcProvSvc.getVpcOffering(this.getEntityId()); if (vpc != null) { VpcOfferingResponse response = _responseGenerator.createVpcOfferingResponse(vpc); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/vpc/DeleteVPCOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vpc/DeleteVPCOfferingCmd.java index 9e2968e66fe..4b16fa5fcb9 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vpc/DeleteVPCOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vpc/DeleteVPCOfferingCmd.java @@ -66,7 +66,7 @@ public class DeleteVPCOfferingCmd extends BaseAsyncCmd{ @Override public void execute(){ - boolean result = _vpcService.deleteVpcOffering(getId()); + boolean result = _vpcProvSvc.deleteVpcOffering(getId()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java index de61ee74b31..9bbae064376 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/vpc/UpdateVPCOfferingCmd.java @@ -88,7 +88,7 @@ public class UpdateVPCOfferingCmd extends BaseAsyncCmd{ @Override public void execute(){ - VpcOffering result = _vpcService.updateVpcOffering(getId(), getVpcOfferingName(), getDisplayText(), getState()); + VpcOffering result = _vpcProvSvc.updateVpcOffering(getId(), getVpcOfferingName(), getDisplayText(), getState()); if (result != null) { VpcOfferingResponse response = _responseGenerator.createVpcOfferingResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java index 41aaaaada12..a61474e69d0 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/UpdateNetworkCmd.java @@ -129,14 +129,9 @@ public class UpdateNetworkCmd extends BaseAsyncCmd { throw new InvalidParameterValueException("Couldn't find network by id"); } - Network result = null; - if (network.getVpcId() != null) { - result = _vpcService.updateVpcGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount, + Network result = _networkService.updateGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount, callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr()); - } else { - result = _networkService.updateGuestNetwork(getId(), getNetworkName(), getDisplayText(), callerAccount, - callerUser, getNetworkDomain(), getNetworkOfferingId(), getChangeCidr(), getGuestVmCidr()); - } + if (result != null) { NetworkResponse response = _responseGenerator.createNetworkResponse(result); diff --git a/api/src/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java b/api/src/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java index 9aef26f016c..ddae7998784 100644 --- a/api/src/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/vpc/ListVPCOfferingsCmd.java @@ -92,7 +92,7 @@ public class ListVPCOfferingsCmd extends BaseListCmd{ @Override public void execute(){ - List offerings = _vpcService.listVpcOfferings(getId(), getVpcOffName(), getDisplayText(), + List offerings = _vpcProvSvc.listVpcOfferings(getId(), getVpcOffName(), getDisplayText(), getSupportedServices(), isDefault, this.getKeyword(), getState(), this.getStartIndex(), this.getPageSizeVal()); ListResponse response = new ListResponse(); List offeringResponses = new ArrayList(); diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 8e6f8062463..7b441901d5e 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -95,8 +95,20 @@ import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationService; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.*; -import com.cloud.dc.dao.*; +import com.cloud.dc.AccountVlanMapVO; +import com.cloud.dc.ClusterDetailsDao; +import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.Vlan; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.AccountVlanMapDao; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.dc.dao.VlanDao; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.Event; @@ -162,7 +174,12 @@ import com.cloud.network.security.SecurityGroup; import com.cloud.network.security.SecurityGroupManager; import com.cloud.network.security.SecurityGroupVO; import com.cloud.network.security.dao.SecurityGroupDao; -import com.cloud.network.vpc.*; +import com.cloud.network.vpc.StaticRouteVO; +import com.cloud.network.vpc.VpcGatewayVO; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.VpcOffering; +import com.cloud.network.vpc.VpcProvisioningService; +import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.StaticRouteDao; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcGatewayDao; @@ -177,19 +194,57 @@ import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.projects.ProjectService; import com.cloud.resource.ResourceManager; -import com.cloud.server.*; +import com.cloud.server.Criteria; +import com.cloud.server.ManagementServer; +import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag.TaggedResourceType; +import com.cloud.server.StatsCollector; +import com.cloud.server.TaggedResourceService; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.*; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.GuestOS; +import com.cloud.storage.GuestOSCategoryVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage.ImageFormat; - +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StorageStats; +import com.cloud.storage.UploadVO; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateS3VO; +import com.cloud.storage.VMTemplateSwiftVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; import com.cloud.storage.Volume.Type; -import com.cloud.storage.dao.*; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.GuestOSCategoryDao; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.UploadDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateDetailsDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplateS3Dao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.template.TemplateManager; -import com.cloud.user.*; - +import com.cloud.user.Account; +import com.cloud.user.AccountDetailsDao; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.SSHKeyPairVO; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import com.cloud.user.UserStatisticsVO; +import com.cloud.user.UserVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -202,7 +257,6 @@ import com.cloud.vm.DomainRouterVO; import com.cloud.vm.InstanceGroup; import com.cloud.vm.InstanceGroupVO; import com.cloud.vm.NicProfile; -import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.UserVmDetailVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; @@ -324,6 +378,7 @@ public class ApiDBUtils { static VMSnapshotDao _vmSnapshotDao; static ClusterDetailsDao _clusterDetailsDao; static NicSecondaryIpDao _nicSecondaryIpDao; + static VpcProvisioningService _vpcProvSvc; @Inject private ManagementServer ms; @Inject public AsyncJobManager asyncMgr; @@ -427,6 +482,7 @@ public class ApiDBUtils { @Inject private ClusterDetailsDao clusterDetailsDao; @Inject private VMSnapshotDao vmSnapshotDao; @Inject private NicSecondaryIpDao nicSecondaryIpDao; + @Inject private VpcProvisioningService vpcProvSvc; @PostConstruct void init() { _ms = ms; @@ -528,6 +584,7 @@ public class ApiDBUtils { _clusterDetailsDao = clusterDetailsDao; _vmSnapshotDao = vmSnapshotDao; _nicSecondaryIpDao = nicSecondaryIpDao; + _vpcProvSvc = vpcProvSvc; // Note: stats collector should already have been initialized by this time, otherwise a null instance is returned _statsCollector = StatsCollector.getInstance(); } diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index e961f049d73..851f7f54549 100755 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -20,8 +20,8 @@ import java.util.List; import java.util.Map; import org.apache.cloudstack.acl.ControlledEntity.ACLType; + import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.deploy.DataCenterDeployment; @@ -51,13 +51,11 @@ import com.cloud.user.User; import com.cloud.utils.Pair; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; -import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.VirtualMachineProfileImpl; /** * NetworkManager manages the network for the different end users. diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 42544ae1240..c0685ba2033 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1528,7 +1528,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L // associate a source NAT IP (if one isn't already associated with the network) boolean sharedSourceNat = offering.getSharedSourceNat(); - DataCenter zone = _dcDao.findById(network.getDataCenterId()); if (network.getGuestType() == Network.GuestType.Isolated && _networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat) && !sharedSourceNat) { diff --git a/server/src/com/cloud/network/NetworkModelImpl.java b/server/src/com/cloud/network/NetworkModelImpl.java index e7bdbca27c8..d967f3346bf 100644 --- a/server/src/com/cloud/network/NetworkModelImpl.java +++ b/server/src/com/cloud/network/NetworkModelImpl.java @@ -1212,6 +1212,19 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel { } return isProviderEnabled(ntwkSvcProvider); } + + @Override + public boolean isProviderEnabledInZone(long zoneId, String provider) + { + //the provider has to be enabled at least in one network in the zone + for (PhysicalNetwork pNtwk : _physicalNetworkDao.listByZone(zoneId)) { + if (isProviderEnabledInPhysicalNetwork(pNtwk.getId(), provider)) { + return true; + } + } + + return false; + } @Override public String getNetworkTag(HypervisorType hType, Network network) { diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index 846d79e93cf..d5034597f4f 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -94,6 +94,7 @@ import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.network.vpc.PrivateIpVO; +import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.dao.PrivateIpDao; import com.cloud.offering.NetworkOffering; @@ -1715,6 +1716,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { ex.addProxyObject("networks", networkId, "networkId"); throw ex; } + + //perform below validation if the network is vpc network + if (network.getVpcId() != null && networkOfferingId != null) { + Vpc vpc = _vpcMgr.getVpc(network.getVpcId()); + _vpcMgr.validateNtwkOffForNtwkInVpc(networkId, networkOfferingId, null, null, vpc, null, _accountMgr.getAccount(network.getAccountId())); + } // don't allow to update network in Destroy state if (network.getState() == Network.State.Destroy) { diff --git a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java index c7d4aeda344..08443698ea0 100644 --- a/server/src/com/cloud/network/element/VpcVirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VpcVirtualRouterElement.java @@ -37,6 +37,7 @@ import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.NetworkModel; import com.cloud.network.PublicIpAddress; import com.cloud.network.Site2SiteVpnConnection; import com.cloud.network.Site2SiteVpnGateway; @@ -76,6 +77,8 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc Site2SiteVpnGatewayDao _vpnGatewayDao; @Inject IPAddressDao _ipAddressDao; + @Inject + NetworkModel _ntwkModel; private static final Map> capabilities = setCapabilities(); @@ -322,7 +325,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc return false; } - List routers = _vpcMgr.getVpcRouters(gateway.getVpcId()); + List routers = _vpcRouterMgr.getVpcRouters(gateway.getVpcId()); if (routers == null || routers.isEmpty()) { s_logger.debug(this.getName() + " element doesn't need to create Private gateway on the backend; VPC virtual " + "router doesn't exist in the vpc id=" + gateway.getVpcId()); @@ -345,7 +348,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc return false; } - List routers = _vpcMgr.getVpcRouters(gateway.getVpcId()); + List routers = _vpcRouterMgr.getVpcRouters(gateway.getVpcId()); if (routers == null || routers.isEmpty()) { s_logger.debug(this.getName() + " element doesn't need to delete Private gateway on the backend; VPC virtual " + "router doesn't exist in the vpc id=" + gateway.getVpcId()); @@ -361,10 +364,6 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc return _vpcRouterMgr.destroyPrivateGateway(gateway, router); } - @Override - protected List getRouters(Network network, DeployDestination dest) { - return _vpcMgr.getVpcRouters(network.getVpcId()); - } @Override public boolean applyIps(Network network, List ipAddress, Set services) @@ -377,7 +376,7 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc } } if (canHandle) { - List routers = getRouters(network, null); + List routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER); if (routers == null || routers.isEmpty()) { s_logger.debug(this.getName() + " element doesn't need to associate ip addresses on the backend; VPC virtual " + "router doesn't exist in the network " + network.getId()); @@ -446,12 +445,12 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc Long vpcId = ip.getVpcId(); Vpc vpc = _vpcMgr.getVpc(vpcId); - if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { + if (!_ntwkModel.isProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { throw new ResourceUnavailableException("VPC provider is not enabled in zone " + vpc.getZoneId(), DataCenter.class, vpc.getZoneId()); } - List routers = _vpcMgr.getVpcRouters(ip.getVpcId()); + List routers = _vpcRouterMgr.getVpcRouters(ip.getVpcId()); if (routers == null || routers.size() != 1) { throw new ResourceUnavailableException("Cannot enable site-to-site VPN on the backend; virtual router doesn't exist in the vpc " + ip.getVpcId(), DataCenter.class, vpc.getZoneId()); @@ -474,12 +473,12 @@ public class VpcVirtualRouterElement extends VirtualRouterElement implements Vpc Long vpcId = ip.getVpcId(); Vpc vpc = _vpcMgr.getVpc(vpcId); - if (!_vpcMgr.vpcProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { + if (!_ntwkModel.isProviderEnabledInZone(vpc.getZoneId(), Provider.VPCVirtualRouter.getName())) { throw new ResourceUnavailableException("VPC provider is not enabled in zone " + vpc.getZoneId(), DataCenter.class, vpc.getZoneId()); } - List routers = _vpcMgr.getVpcRouters(ip.getVpcId()); + List routers = _vpcRouterMgr.getVpcRouters(ip.getVpcId()); if (routers == null || routers.size() != 1) { throw new ResourceUnavailableException("Cannot enable site-to-site VPN on the backend; virtual router doesn't exist in the vpc " + ip.getVpcId(), DataCenter.class, vpc.getZoneId()); diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java index 297ae9b1f13..76c8aa89173 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManager.java @@ -101,4 +101,10 @@ public interface VpcVirtualNetworkApplianceManager extends VirtualNetworkApplian * @throws ResourceUnavailableException */ boolean stopSite2SiteVpn(Site2SiteVpnConnection conn, VirtualRouter router) throws ResourceUnavailableException; + + /** + * @param vpcId + * @return + */ + List getVpcRouters(long vpcId); } diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 22d823fb364..bdfac060798 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -234,7 +234,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian long dcId = dest.getDataCenter().getId(); DeploymentPlan plan = new DataCenterDeployment(dcId); - List routers = _routerDao.listByVpcId(vpcId); + List routers = getVpcRouters(vpcId); return new Pair>(plan, routers); } @@ -1212,7 +1212,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian networks = super.createRouterNetworks(owner, isRedundant, plan, null, sourceNatIp); //2) allocate nic for private gateway if needed - VpcGateway privateGateway = _vpcMgr.getPrivateGatewayForVpc(vpcId); + PrivateGateway privateGateway = _vpcMgr.getVpcPrivateGateway(vpcId); if (privateGateway != null) { NicProfile privateNic = createPrivateNicProfileForGateway(privateGateway); Network privateNetwork = _networkModel.getNetwork(privateGateway.getNetworkId()); @@ -1233,7 +1233,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian for (IPAddressVO ip : ips) { PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId())); if ((ip.getState() == IpAddress.State.Allocated || ip.getState() == IpAddress.State.Allocating) - && _vpcMgr.ipUsedInVpc(ip)&& !publicVlans.contains(publicIp.getVlanTag())) { + && _vpcMgr.isIpAllocatedToVpc(ip)&& !publicVlans.contains(publicIp.getVlanTag())) { s_logger.debug("Allocating nic for router in vlan " + publicIp.getVlanTag()); NicProfile publicNic = new NicProfile(); publicNic.setDefaultNic(false); @@ -1314,7 +1314,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian long publicNtwkId = ip.getNetworkId(); //if ip is not associated to any network, and there are no firewall rules, release it on the backend - if (!_vpcMgr.ipUsedInVpc(ip)) { + if (!_vpcMgr.isIpAllocatedToVpc(ip)) { ip.setState(IpAddress.State.Releasing); } @@ -1334,7 +1334,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian long publicNtwkId = ip.getNetworkId(); //if ip is not associated to any network, and there are no firewall rules, release it on the backend - if (!_vpcMgr.ipUsedInVpc(ip)) { + if (!_vpcMgr.isIpAllocatedToVpc(ip)) { ip.setState(IpAddress.State.Releasing); } @@ -1376,4 +1376,9 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } } + @Override + public List getVpcRouters(long vpcId) { + return _routerDao.listByVpcId(vpcId); + } + } diff --git a/server/src/com/cloud/network/vpc/VpcManager.java b/server/src/com/cloud/network/vpc/VpcManager.java index 714330dd5aa..84ab8ef5dd7 100644 --- a/server/src/com/cloud/network/vpc/VpcManager.java +++ b/server/src/com/cloud/network/vpc/VpcManager.java @@ -17,8 +17,11 @@ package com.cloud.network.vpc; import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.cloudstack.acl.ControlledEntity.ACLType; + import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; @@ -27,33 +30,27 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress; import com.cloud.network.Network; +import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; import com.cloud.network.PhysicalNetwork; import com.cloud.network.addr.PublicIp; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; -import com.cloud.vm.DomainRouterVO; public interface VpcManager extends VpcService{ /** - * @param ntwkOffId - * @param cidr - * @param networkDomain - * @param networkOwner - * @param vpc TODO - * @param networkId TODO - * @param gateway TODO + * Returns all existing VPCs for a given account + * @param accountId * @return */ - void validateNtkwOffForVpc(long ntwkOffId, String cidr, String networkDomain, Account networkOwner, - Vpc vpc, Long networkId, String gateway); - - List getVpcsForAccount(long accountId); + /** + * Destroys the VPC + * * @param vpc * @param caller TODO * @param callerUserId TODO @@ -63,34 +60,19 @@ public interface VpcManager extends VpcService{ */ boolean destroyVpc(Vpc vpc, Account caller, Long callerUserId) throws ConcurrentOperationException, ResourceUnavailableException; - /** - * @param vpcId - * @return - */ - List getVpcRouters(long vpcId); - - /** - * @param zoneId - * @param provider - * @return - */ - boolean vpcProviderEnabledInZone(long zoneId, String provider); - - /** - * @param vpcId - * @return - */ - VpcGateway getPrivateGatewayForVpc(long vpcId); - /** + * Returns true if the IP is allocated to the VPC; false otherwise + * * @param ip * @return */ - boolean ipUsedInVpc(IpAddress ip); + boolean isIpAllocatedToVpc(IpAddress ip); /** + * Disassociates the public IP address from VPC + * * @param ipId * @param networkId */ @@ -98,6 +80,8 @@ public interface VpcManager extends VpcService{ /** + * Creates guest network in the VPC + * * @param ntwkOffId * @param name * @param displayText @@ -125,9 +109,11 @@ public interface VpcManager extends VpcService{ /** + * Assigns source nat public IP address to VPC + * * @param owner * @param vpc - * @return + * @return public IP address object * @throws InsufficientAddressCapacityException * @throws ConcurrentOperationException */ @@ -135,6 +121,8 @@ public interface VpcManager extends VpcService{ /** + * Validates network offering to find if it can be used for network creation in VPC + * * @param guestNtwkOff * @param supportedSvcs TODO */ @@ -142,8 +130,36 @@ public interface VpcManager extends VpcService{ /** - * @return + * @return list of hypervisors that are supported by VPC */ List getSupportedVpcHypervisors(); + + + /** + * Lists all the services and providers that the current VPC suppots + * @param vpcOffId + * @return map of Service to Provider(s) map + */ + Map> getVpcOffSvcProvidersMap(long vpcOffId); + + + /** + * Returns VPC that is ready to be used + * @param vpcId + * @return VPC object + */ + public Vpc getActiveVpc(long vpcId); + + /** + * Performs network offering validation to determine if it can be used for network upgrade inside the VPC + * @param networkId + * @param newNtwkOffId + * @param newCidr + * @param newNetworkDomain + * @param vpc + * @param gateway + * @param networkOwner TODO + */ + void validateNtwkOffForNtwkInVpc(Long networkId, long newNtwkOffId, String newCidr, String newNetworkDomain, Vpc vpc, String gateway, Account networkOwner); } diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index fee4ef310f7..3948f2ecf73 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -31,13 +31,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.network.element.StaticNatServiceProvider; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceType; @@ -77,6 +76,7 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.Site2SiteVpnGatewayDao; +import com.cloud.network.element.StaticNatServiceProvider; import com.cloud.network.element.VpcProvider; import com.cloud.network.vpc.VpcOffering.State; import com.cloud.network.vpc.dao.PrivateIpDao; @@ -103,8 +103,6 @@ import com.cloud.user.UserContext; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; - -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; @@ -124,8 +122,8 @@ import com.cloud.vm.dao.DomainRouterDao; @Component -@Local(value = { VpcManager.class, VpcService.class }) -public class VpcManagerImpl extends ManagerBase implements VpcManager{ +@Local(value = { VpcManager.class, VpcService.class, VpcProvisioningService.class }) +public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvisioningService{ private static final Logger s_logger = Logger.getLogger(VpcManagerImpl.class); @Inject VpcOfferingDao _vpcOffDao; @@ -584,19 +582,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ return createVpc(zoneId, vpcOffId, owner, vpcName, displayText, cidr, networkDomain); } - - @Override - public boolean vpcProviderEnabledInZone(long zoneId, String provider) - { - //the provider has to be enabled at least in one network in the zone - for (PhysicalNetwork pNtwk : _pNtwkDao.listByZone(zoneId)) { - if (_ntwkModel.isProviderEnabledInPhysicalNetwork(pNtwk.getId(), provider)) { - return true; - } - } - - return false; - } @DB @@ -656,7 +641,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } - if (!vpcProviderEnabledInZone(zoneId, provider)) { + if (!_ntwkModel.isProviderEnabledInZone(zoneId, provider)) { throw new InvalidParameterValueException("Provider " + provider + " should be enabled in at least one physical network of the zone specified"); } @@ -1015,20 +1000,20 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ return success; } - @Override @DB - public void validateNtkwOffForVpc(long ntwkOffId, String cidr, String networkDomain, - Account networkOwner, Vpc vpc, Long networkId, String gateway) { + @Override + public void validateNtwkOffForNtwkInVpc(Long networkId, long newNtwkOffId, String newCidr, + String newNetworkDomain, Vpc vpc, String gateway, Account networkOwner) { - NetworkOffering guestNtwkOff = _configMgr.getNetworkOffering(ntwkOffId); + NetworkOffering guestNtwkOff = _configMgr.getNetworkOffering(newNtwkOffId); if (guestNtwkOff == null) { throw new InvalidParameterValueException("Can't find network offering by id specified"); } - + if (networkId == null) { //1) Validate attributes that has to be passed in when create new guest network - validateNewVpcGuestNetwork(cidr, gateway, networkOwner, vpc, networkDomain); + validateNewVpcGuestNetwork(newCidr, gateway, networkOwner, vpc, newNetworkDomain); } //2) validate network offering attributes @@ -1213,7 +1198,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } //4) Delete private gateway - VpcGateway gateway = getPrivateGatewayForVpc(vpcId); + PrivateGateway gateway = getVpcPrivateGateway(vpcId); if (gateway != null) { s_logger.debug("Deleting private gateway " + gateway + " as a part of vpc " + vpcId + " resources cleanup"); if (!deleteVpcPrivateGateway(gateway.getId())) { @@ -1270,11 +1255,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } } - @Override - public List getVpcRouters(long vpcId) { - return _routerDao.listByVpcId(vpcId); - } - + @Override public PrivateGateway getVpcPrivateGateway(long id) { VpcGateway gateway = _vpcGatewayDao.findById(id); @@ -1835,11 +1816,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } } } - - @Override - public VpcGateway getPrivateGatewayForVpc(long vpcId) { - return _vpcGatewayDao.getPrivateGatewayForVpc(vpcId); - } @DB @@ -1895,7 +1871,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ @Override public void unassignIPFromVpcNetwork(long ipId, long networkId) { IPAddressVO ip = _ipAddressDao.findById(ipId); - if (ipUsedInVpc(ip)) { + if (isIpAllocatedToVpc(ip)) { return; } @@ -1927,7 +1903,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } @Override - public boolean ipUsedInVpc(IpAddress ip) { + public boolean isIpAllocatedToVpc(IpAddress ip) { return (ip != null && ip.getVpcId() != null && (ip.isOneToOneNat() || !_firewallDao.listByIp(ip.getId()).isEmpty())); } @@ -1957,7 +1933,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ } //1) Validate if network can be created for VPC - validateNtkwOffForVpc(ntwkOffId, cidr, networkDomain, owner, vpc, null, gateway); + validateNtwkOffForNtwkInVpc(null, ntwkOffId, cidr, networkDomain, vpc, gateway, owner); //2) Create network Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId, @@ -2020,24 +1996,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager{ return ipToReturn; } - - - @Override - public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount, - User callerUser, String domainSuffix, Long ntwkOffId, Boolean changeCidr, String guestVmCidr) { - NetworkVO network = _ntwkDao.findById(networkId); - if (network == null) { - throw new InvalidParameterValueException("Couldn't find network by id"); - } - //perform below validation if the network is vpc network - if (network.getVpcId() != null && ntwkOffId != null) { - Vpc vpc = getVpc(network.getVpcId()); - validateNtkwOffForVpc(ntwkOffId, null, null, null, vpc, networkId, null); - } - - return _ntwkSvc.updateGuestNetwork(networkId, name, displayText, callerAccount, callerUser, domainSuffix, - ntwkOffId, changeCidr, guestVmCidr); - } + @Override public List getSupportedVpcHypervisors() { diff --git a/server/src/com/cloud/network/vpc/VpcOfferingVO.java b/server/src/com/cloud/network/vpc/VpcOfferingVO.java index dce7a81e4d0..9d5becf2333 100644 --- a/server/src/com/cloud/network/vpc/VpcOfferingVO.java +++ b/server/src/com/cloud/network/vpc/VpcOfferingVO.java @@ -102,7 +102,6 @@ public class VpcOfferingVO implements VpcOffering { return name; } - @Override public String getUniqueName() { return uniqueName; } diff --git a/server/src/com/cloud/network/vpc/VpcVO.java b/server/src/com/cloud/network/vpc/VpcVO.java index 634df052850..7b784eb6458 100644 --- a/server/src/com/cloud/network/vpc/VpcVO.java +++ b/server/src/com/cloud/network/vpc/VpcVO.java @@ -26,9 +26,7 @@ import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; -import org.apache.cloudstack.api.Identity; import com.cloud.utils.db.GenericDao; -import org.apache.cloudstack.api.InternalIdentity; @Entity @Table(name="vpc") @@ -94,11 +92,6 @@ public class VpcVO implements Vpc { this.networkDomain = networkDomain; this.vpcOfferingId = vpcOffId; } - - @Override - public boolean readyToUse() { - return state == State.Enabled; - } @Override public long getId() { diff --git a/server/test/com/cloud/network/MockNetworkModelImpl.java b/server/test/com/cloud/network/MockNetworkModelImpl.java index b926519d45b..c5789659008 100644 --- a/server/test/com/cloud/network/MockNetworkModelImpl.java +++ b/server/test/com/cloud/network/MockNetworkModelImpl.java @@ -844,4 +844,10 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { // TODO Auto-generated method stub return null; } + + @Override + public boolean isProviderEnabledInZone(long zoneId, String provider) { + // TODO Auto-generated method stub + return false; + } } diff --git a/server/test/com/cloud/vpc/MockNetworkModelImpl.java b/server/test/com/cloud/vpc/MockNetworkModelImpl.java index b05e8eaba6c..e1534cbf62a 100644 --- a/server/test/com/cloud/vpc/MockNetworkModelImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkModelImpl.java @@ -857,4 +857,10 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel { return null; } + @Override + public boolean isProviderEnabledInZone(long zoneId, String provider) { + // TODO Auto-generated method stub + return false; + } + } diff --git a/server/test/com/cloud/vpc/MockVpcManagerImpl.java b/server/test/com/cloud/vpc/MockVpcManagerImpl.java index e6c65200ded..0f269284127 100644 --- a/server/test/com/cloud/vpc/MockVpcManagerImpl.java +++ b/server/test/com/cloud/vpc/MockVpcManagerImpl.java @@ -47,15 +47,11 @@ import com.cloud.network.vpc.StaticRoute; import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcGateway; import com.cloud.network.vpc.VpcManager; -import com.cloud.network.vpc.VpcOffering; import com.cloud.network.vpc.VpcService; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; -import com.cloud.user.User; import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; -import com.cloud.vm.DomainRouterVO; import com.cloud.vpc.dao.MockVpcDaoImpl; @Component @@ -63,19 +59,6 @@ import com.cloud.vpc.dao.MockVpcDaoImpl; public class MockVpcManagerImpl extends ManagerBase implements VpcManager { @Inject MockVpcDaoImpl _vpcDao; - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#getVpcOffering(long) - */ - @Override - public VpcOffering getVpcOffering(long vpcOfferingId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders) { - return null; - } /* (non-Javadoc) * @see com.cloud.network.vpc.VpcService#getVpc(long) @@ -104,42 +87,6 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#getVpcOffSvcProvidersMap(long) - */ - @Override - public Map> getVpcOffSvcProvidersMap(long vpcOffId) { - // TODO Auto-generated method stub - return null; - } - - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#listVpcOfferings(java.lang.Long, java.lang.String, java.lang.String, java.util.List, java.lang.Boolean, java.lang.String, java.lang.String, java.lang.Long, java.lang.Long) - */ - @Override - public List listVpcOfferings(Long id, String name, String displayText, List supportedServicesStr, Boolean isDefault, String keyword, String state, Long startIndex, Long pageSizeVal) { - // TODO Auto-generated method stub - return null; - } - - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#deleteVpcOffering(long) - */ - @Override - public boolean deleteVpcOffering(long offId) { - // TODO Auto-generated method stub - return false; - } - - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#updateVpcOffering(long, java.lang.String, java.lang.String, java.lang.String) - */ - @Override - public VpcOffering updateVpcOffering(long vpcOffId, String vpcOfferingName, String displayText, String state) { - // TODO Auto-generated method stub - return null; - } - /* (non-Javadoc) * @see com.cloud.network.vpc.VpcService#createVpc(long, long, long, java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ @@ -313,19 +260,6 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcService#updateVpcGuestNetwork(long, java.lang.String, java.lang.String, com.cloud.user.Account, com.cloud.user.User, java.lang.String, java.lang.Long, java.lang.Boolean) - */ - - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcManager#validateNtkwOffForVpc(long, java.lang.String, java.lang.String, com.cloud.user.Account, com.cloud.network.vpc.Vpc, java.lang.Long, java.lang.String) - */ - @Override - public void validateNtkwOffForVpc(long ntwkOffId, String cidr, String networkDomain, Account networkOwner, Vpc vpc, Long networkId, String gateway) { - // TODO Auto-generated method stub - - } - /* (non-Javadoc) * @see com.cloud.network.vpc.VpcManager#getVpcsForAccount(long) */ @@ -344,34 +278,13 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return false; } - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcManager#getVpcRouters(long) - */ - @Override - public List getVpcRouters(long vpcId) { - // TODO Auto-generated method stub - return null; - } - @Override - public boolean vpcProviderEnabledInZone(long zoneId, String provider) { - return false; - } - - /* (non-Javadoc) - * @see com.cloud.network.vpc.VpcManager#getPrivateGatewayForVpc(long) - */ - @Override - public VpcGateway getPrivateGatewayForVpc(long vpcId) { - // TODO Auto-generated method stub - return null; - } /* (non-Javadoc) * @see com.cloud.network.vpc.VpcManager#ipUsedInVpc(com.cloud.network.IpAddress) */ @Override - public boolean ipUsedInVpc(IpAddress ip) { + public boolean isIpAllocatedToVpc(IpAddress ip) { // TODO Auto-generated method stub return false; } @@ -458,11 +371,16 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager { return null; } - @Override - public Network updateVpcGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, - String domainSuffix, Long ntwkOffId, Boolean changeCidr, String guestVmCidr) { - // TODO Auto-generated method stub - return null; - } + @Override + public Map> getVpcOffSvcProvidersMap(long vpcOffId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void validateNtwkOffForNtwkInVpc(Long networkId, long newNtwkOffId, String newCidr, String newNetworkDomain, Vpc vpc, String gateway, Account networkOwner) { + // TODO Auto-generated method stub + + } } diff --git a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java index 0b47d1de697..ef5478bb1f8 100644 --- a/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java +++ b/server/test/com/cloud/vpc/MockVpcVirtualNetworkApplianceManager.java @@ -396,4 +396,10 @@ VpcVirtualNetworkApplianceService { return false; } + @Override + public List getVpcRouters(long vpcId) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/VpcApiUnitTest.java b/server/test/com/cloud/vpc/VpcApiUnitTest.java index 8e64ab18ebe..d4d5b29812d 100644 --- a/server/test/com/cloud/vpc/VpcApiUnitTest.java +++ b/server/test/com/cloud/vpc/VpcApiUnitTest.java @@ -30,38 +30,13 @@ import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.cloud.configuration.dao.ConfigurationDaoImpl; -import com.cloud.configuration.dao.ResourceCountDaoImpl; -import com.cloud.dc.dao.VlanDaoImpl; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network.Service; -import com.cloud.network.dao.FirewallRulesDaoImpl; -import com.cloud.network.dao.IPAddressDaoImpl; -import com.cloud.network.dao.PhysicalNetworkDaoImpl; -import com.cloud.network.dao.Site2SiteVpnGatewayDaoImpl; import com.cloud.network.vpc.Vpc; -import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcManagerImpl; -import com.cloud.network.vpc.dao.PrivateIpDaoImpl; -import com.cloud.network.vpc.dao.StaticRouteDaoImpl; -import com.cloud.network.vpc.dao.VpcGatewayDaoImpl; -import com.cloud.network.vpc.dao.VpcOfferingDaoImpl; -import com.cloud.server.ManagementService; -import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.user.AccountVO; -import com.cloud.user.MockAccountManagerImpl; -import com.cloud.user.dao.AccountDaoImpl; import com.cloud.utils.component.ComponentContext; -import com.cloud.vm.dao.DomainRouterDaoImpl; -import com.cloud.vpc.dao.MockNetworkDaoImpl; -import com.cloud.vpc.dao.MockNetworkOfferingDaoImpl; -import com.cloud.vpc.dao.MockNetworkOfferingServiceMapDaoImpl; -import com.cloud.vpc.dao.MockNetworkServiceMapDaoImpl; -import com.cloud.vpc.dao.MockVpcDaoImpl; -import com.cloud.vpc.dao.MockVpcOfferingDaoImpl; -import com.cloud.vpc.dao.MockVpcOfferingServiceMapDaoImpl; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:/VpcTestContext.xml") public class VpcApiUnitTest extends TestCase{ @@ -180,7 +155,7 @@ public class VpcApiUnitTest extends TestCase{ //1) correct network offering boolean result = false; try { - _vpcService.validateNtkwOffForVpc(1, "0.0.0.0", "111-", new AccountVO(), _vpcService.getVpc(1), 2L, "10.1.1.1"); + _vpcService.validateNtwkOffForNtwkInVpc(2L, 1, "0.0.0.0", "111-", _vpcService.getVpc(1), "10.1.1.1", new AccountVO()); result = true; s_logger.debug("Validate network offering: Test passed: the offering is valid for vpc creation"); } catch (Exception ex) { @@ -191,7 +166,7 @@ public class VpcApiUnitTest extends TestCase{ result = false; String msg = null; try { - _vpcService.validateNtkwOffForVpc(2, "0.0.0.0", "111-", new AccountVO(), _vpcService.getVpc(1), 2L, "10.1.1.1"); + _vpcService.validateNtwkOffForNtwkInVpc(2L, 2, "0.0.0.0", "111-", _vpcService.getVpc(1), "10.1.1.1", new AccountVO()); result = true; } catch (InvalidParameterValueException ex) { msg = ex.getMessage(); @@ -207,7 +182,7 @@ public class VpcApiUnitTest extends TestCase{ result = false; msg = null; try { - _vpcService.validateNtkwOffForVpc(3, "0.0.0.0", "111-", new AccountVO(), _vpcService.getVpc(1), 2L, "10.1.1.1"); + _vpcService.validateNtwkOffForNtwkInVpc(2L, 3, "0.0.0.0", "111-", _vpcService.getVpc(1), "10.1.1.1", new AccountVO()); result = true; } catch (InvalidParameterValueException ex) { msg = ex.getMessage(); @@ -222,7 +197,7 @@ public class VpcApiUnitTest extends TestCase{ //4) invalid offering - guest type shared result = false; try { - _vpcService.validateNtkwOffForVpc(4, "0.0.0.0", "111-", new AccountVO(), _vpcService.getVpc(1), 2L, "10.1.1.1"); + _vpcService.validateNtwkOffForNtwkInVpc(2L, 4, "0.0.0.0", "111-", _vpcService.getVpc(1), "10.1.1.1", new AccountVO()); result = true; } catch (InvalidParameterValueException ex) { msg = ex.getMessage(); @@ -237,7 +212,7 @@ public class VpcApiUnitTest extends TestCase{ //5) Invalid offering - no redundant router support result = false; try { - _vpcService.validateNtkwOffForVpc(5, "0.0.0.0", "111-", new AccountVO(), _vpcService.getVpc(1), 2L, "10.1.1.1"); + _vpcService.validateNtwkOffForNtwkInVpc(2L, 5, "0.0.0.0", "111-", _vpcService.getVpc(1), "10.1.1.1", new AccountVO()); result = true; } catch (InvalidParameterValueException ex) { msg = ex.getMessage(); @@ -252,7 +227,7 @@ public class VpcApiUnitTest extends TestCase{ //6) Only one network in the VPC can support LB service - negative scenario result = false; try { - _vpcService.validateNtkwOffForVpc(6, "0.0.0.0", "111-", new AccountVO(), _vpcService.getVpc(1), 2L, "10.1.1.1"); + _vpcService.validateNtwkOffForNtwkInVpc(2L, 6, "0.0.0.0", "111-", _vpcService.getVpc(1), "10.1.1.1", new AccountVO()); result = true; s_logger.debug("Validate network offering: Test passed: the offering is valid for vpc creation"); } catch (InvalidParameterValueException ex) { From 5a16e70de9d7bfd93f71bf476de8e23f84e52152 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Fri, 29 Mar 2013 18:31:26 -0600 Subject: [PATCH 004/120] CLOUDSTACK-1846, CLOUDSTACK-1845 - KVM Storage, sometimes KVMHA will remount deleted NFS pools, causing failures when defining new storage pools. Sometimes a storage pool has never been used on a host, and getStoragePool fails when copying templates or in storage migration. deleteStoragePool(pool) often fails silently, leaving no pool defined in libvirt, but a mountpoint left behind. This patch handles some of these exceptions and brings forward any issues via logging. Signed-off-by: Marcus Sorensen 1364603486 -0600 --- .../resource/LibvirtComputingResource.java | 34 ++++++++++++-- .../kvm/storage/LibvirtStorageAdaptor.java | 46 +++++++++++++------ 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index f786f886bf1..6852e2cf711 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -1218,10 +1218,23 @@ ServerResource { StorageFilerTO pool = cmd.getPool(); String secondaryStorageUrl = cmd.getSecondaryStorageURL(); KVMStoragePool secondaryStoragePool = null; + KVMStoragePool primaryPool = null; try { - KVMStoragePool primaryPool = _storagePoolMgr.getStoragePool( - pool.getType(), - pool.getUuid()); + try { + primaryPool = _storagePoolMgr.getStoragePool( + pool.getType(), + pool.getUuid()); + } catch (CloudRuntimeException e) { + if (e.getMessage().contains("not found")) { + primaryPool = _storagePoolMgr.createStoragePool(cmd.getPool().getUuid(), + cmd.getPool().getHost(), cmd.getPool().getPort(), + cmd.getPool().getPath(), cmd.getPool().getUserInfo(), + cmd.getPool().getType()); + } else { + return new CopyVolumeAnswer(cmd, false, e.getMessage(), null, null); + } + } + String volumeName = UUID.randomUUID().toString(); if (copyToSecondary) { @@ -2155,6 +2168,7 @@ ServerResource { String secondaryStorageURL = cmd.getSecondaryStorageUrl(); KVMStoragePool secondaryStorage = null; + KVMStoragePool primary = null; try { Connect conn = LibvirtConnection.getConnection(); String templateFolder = cmd.getAccountId() + File.separator @@ -2164,9 +2178,21 @@ ServerResource { secondaryStorage = _storagePoolMgr.getStoragePoolByURI( secondaryStorageURL); - KVMStoragePool primary = _storagePoolMgr.getStoragePool( + try { + primary = _storagePoolMgr.getStoragePool( cmd.getPool().getType(), cmd.getPrimaryStoragePoolNameLabel()); + } catch (CloudRuntimeException e) { + if (e.getMessage().contains("not found")) { + primary = _storagePoolMgr.createStoragePool(cmd.getPool().getUuid(), + cmd.getPool().getHost(), cmd.getPool().getPort(), + cmd.getPool().getPath(), cmd.getPool().getUserInfo(), + cmd.getPool().getType()); + } else { + return new CreatePrivateTemplateAnswer(cmd, false, e.getMessage()); + } + } + KVMPhysicalDisk disk = primary.getPhysicalDisk(cmd.getVolumePath()); String tmpltPath = secondaryStorage.getLocalPath() + File.separator + templateInstallFolder; diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index ca5da5cf683..5e83ef62f22 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -124,6 +124,23 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { return sp; } catch (LibvirtException e) { s_logger.error(e.toString()); + // if error is that pool is mounted, try to handle it + if (e.toString().contains("already mounted")) { + s_logger.error("Attempting to unmount old mount libvirt is unaware of at "+targetPath); + String result = Script.runSimpleBashScript("umount " + targetPath ); + if (result == null) { + s_logger.error("Succeeded in unmounting " + targetPath); + try { + sp = conn.storagePoolCreateXML(spd.toString(), 0); + s_logger.error("Succeeded in redefining storage"); + return sp; + } catch (LibvirtException l) { + s_logger.error("Target was already mounted, unmounted it but failed to redefine storage:" + l); + } + } else { + s_logger.error("Failed in unmounting and redefining storage"); + } + } if (sp != null) { try { if (sp.isPersistent() == 1) { @@ -134,8 +151,8 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { } sp.free(); } catch (LibvirtException l) { - s_logger.debug("Failed to define nfs storage pool with: " - + l.toString()); + s_logger.debug("Failed to undefine nfs storage pool with: " + + l.toString()); } } return null; @@ -541,6 +558,19 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { } return true; } catch (LibvirtException e) { + // handle ebusy error when pool is quickly destroyed + if (e.toString().contains("exit status 16")) { + String targetPath = _mountPoint + File.separator + uuid; + s_logger.error("deleteStoragePool removed pool from libvirt, but libvirt had trouble" + + "unmounting the pool. Trying umount location " + targetPath + + "again in a few seconds"); + String result = Script.runSimpleBashScript("sleep 5 && umount " + targetPath ); + if (result == null) { + s_logger.error("Succeeded in unmounting " + targetPath); + return true; + } + s_logger.error("failed in umount retry"); + } throw new CloudRuntimeException(e.toString()); } } @@ -766,17 +796,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { @Override public boolean deleteStoragePool(KVMStoragePool pool) { - LibvirtStoragePool libvirtPool = (LibvirtStoragePool) pool; - StoragePool virtPool = libvirtPool.getPool(); - try { - virtPool.destroy(); - virtPool.undefine(); - virtPool.free(); - } catch (LibvirtException e) { - return false; - } - - return true; + return deleteStoragePool(pool.getUuid()); } public boolean deleteVbdByPath(String diskPath) { From 29baacd12062a9d9dedb4b0b8828a6e273e71dca Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sat, 30 Mar 2013 16:32:08 +0100 Subject: [PATCH 005/120] debian: Include jasypt in the cloudstack-common package This is required for the cloud-install-sys-tmplt installer. Signed-off-by: Wido den Hollander --- debian/cloudstack-common.install | 1 + debian/rules | 3 +++ scripts/storage/secondary/cloud-install-sys-tmplt | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/debian/cloudstack-common.install b/debian/cloudstack-common.install index 9677f871cf0..021474e1b65 100644 --- a/debian/cloudstack-common.install +++ b/debian/cloudstack-common.install @@ -26,6 +26,7 @@ /usr/share/cloudstack-common/scripts/vm/hypervisor/kvm/* /usr/share/cloudstack-common/scripts/vm/hypervisor/versions.sh /usr/share/cloudstack-common/scripts/vm/hypervisor/xenserver/* +/usr/share/cloudstack-common/lib/* /usr/bin/cloud-set-guest-password /usr/bin/cloud-set-guest-sshkey /usr/lib/python2.?/*-packages/* diff --git a/debian/rules b/debian/rules index 3804d8d49e9..907cdcda46b 100755 --- a/debian/rules +++ b/debian/rules @@ -116,6 +116,7 @@ install: mkdir -p $(DESTDIR)/usr/share/$(PACKAGE)-common mkdir $(DESTDIR)/usr/share/$(PACKAGE)-common/scripts mkdir $(DESTDIR)/usr/share/$(PACKAGE)-common/setup + mkdir $(DESTDIR)/usr/share/$(PACKAGE)-common/lib cp -r scripts/installer $(DESTDIR)/usr/share/$(PACKAGE)-common/scripts cp -r scripts/network $(DESTDIR)/usr/share/$(PACKAGE)-common/scripts cp -r scripts/storage $(DESTDIR)/usr/share/$(PACKAGE)-common/scripts @@ -127,6 +128,8 @@ install: install -D client/target/utilities/bin/cloud-setup-databases $(DESTDIR)/usr/bin install -D client/target/utilities/bin/cloud-setup-management $(DESTDIR)/usr/bin install -D client/target/cloud-client-ui-$(VERSION)-SNAPSHOT/WEB-INF/classes/vms/systemvm.iso $(DESTDIR)/usr/share/$(PACKAGE)-common/vms/systemvm.iso + # We need jasypt for cloud-install-sys-tmplt, so this is a nasty hack to get it into the right place + install -D agent/target/dependencies/jasypt-1.9.0.jar $(DESTDIR)/usr/share/$(PACKAGE)-common/lib # cloudstack-python mkdir -p $(DESTDIR)/usr/lib/python2.7/dist-packages diff --git a/scripts/storage/secondary/cloud-install-sys-tmplt b/scripts/storage/secondary/cloud-install-sys-tmplt index 2172b287848..bcdc4c4f0ca 100755 --- a/scripts/storage/secondary/cloud-install-sys-tmplt +++ b/scripts/storage/secondary/cloud-install-sys-tmplt @@ -40,7 +40,7 @@ DISKSPACE=5120000 #free disk space required in kilobytes dbHost= dbUser= dbPassword= -jasypt='/usr/share/java/jasypt-1.9.0.jar' +jasypt='/usr/share/cloudstack-common/lib/jasypt-1.9.0.jar' while getopts 'm:h:f:u:Ft:e:s:o:r:d' OPTION do case $OPTION in From bc1ce57c9b75029399b8842c7bd4818c3465ee3e Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sat, 30 Mar 2013 20:09:56 +0100 Subject: [PATCH 006/120] debian: Update the init script for the management server Signed-off-by: Wido den Hollander --- packaging/debian/init/cloud-management | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packaging/debian/init/cloud-management b/packaging/debian/init/cloud-management index 69a0428db21..3ebaa738861 100755 --- a/packaging/debian/init/cloud-management +++ b/packaging/debian/init/cloud-management @@ -19,7 +19,7 @@ # specific language governing permissions and limitations # under the License. ### BEGIN INIT INFO -# Provides: tomcat-vmops +# Provides: cloudstack-management # Required-Start: $local_fs $remote_fs $network # Required-Stop: $local_fs $remote_fs $network # Should-Start: $named @@ -34,7 +34,7 @@ PATH=/bin:/usr/bin:/sbin:/usr/sbin NAME=cloudstack-management DESC="CloudStack-specific Tomcat servlet engine" DAEMON=/usr/bin/jsvc -CATALINA_HOME=/usr/share/cloudstack/management +CATALINA_HOME=/usr/share/cloudstack-management DEFAULT=/etc/cloudstack/management/tomcat6.conf JVM_TMP=/tmp/$NAME-temp @@ -65,7 +65,7 @@ TOMCAT6_USER=tomcat6 # The first existing directory is used for JAVA_HOME (if JAVA_HOME is not # defined in $DEFAULT) -JDK_DIRS="/usr/lib/jvm/java-1.6.0-openjdk-amd64/ /usr/lib/jvm/java-1.6.0-openjdk-i386/ /usr/lib/jvm/java-1.6.0-openjdk/ /usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-sun" +JDK_DIRS="/usr/lib/jvm/java-7-openjdk-amd64 /usr/lib/jvm/java-7-openjdk-i386 /usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun" # Look for the right JVM to use for jdir in $JDK_DIRS; do @@ -76,7 +76,7 @@ done export JAVA_HOME # Directory for per-instance configuration files and webapps -CATALINA_BASE=/usr/share/cloudstack/management +CATALINA_BASE=/usr/share/cloudstack-management # Use the Java security manager? (yes/no) TOMCAT6_SECURITY=no From 80da4d5baf9381985f61faa257f6684cc80b8c9f Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sun, 31 Mar 2013 12:46:23 +0200 Subject: [PATCH 007/120] CLOUDSTACK-1490: deb packaging tomcat fixes Signed-off-by: Wido den Hollander --- debian/cloudstack-management.install | 1 - debian/rules | 2 -- packaging/debian/replace.properties | 2 +- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/debian/cloudstack-management.install b/debian/cloudstack-management.install index e80701d0a78..b42343ad5a4 100644 --- a/debian/cloudstack-management.install +++ b/debian/cloudstack-management.install @@ -31,5 +31,4 @@ /usr/bin/cloud-setup-databases /usr/bin/cloud-migrate-databases /usr/share/cloudstack-management/* -/usr/share/java/* /usr/share/tomcat6/lib/* diff --git a/debian/rules b/debian/rules index 907cdcda46b..55496e4d6b3 100755 --- a/debian/rules +++ b/debian/rules @@ -100,10 +100,8 @@ install: ln -s tomcat6-nonssl.conf $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/management/tomcat6.conf mkdir -p $(DESTDIR)/$(SYSCONFDIR)/$(PACKAGE)/management/Catalina/localhost/client mkdir -p ${DESTDIR}/usr/share/tomcat6/lib - mkdir -p ${DESTDIR}/usr/share/java install -D packaging/debian/init/cloud-management $(DESTDIR)/$(SYSCONFDIR)/init.d/$(PACKAGE)-management install -D client/bindir/cloud-update-xenserver-licenses.in $(DESTDIR)/usr/bin/cloud-update-xenserver-licenses - install -D server/target/cloud-server-$(VERSION)-SNAPSHOT.jar $(DESTDIR)/usr/share/java/$(PACKAGE)-server.jar ln -s /usr/share/tomcat6/bin $(DESTDIR)/usr/share/$(PACKAGE)-management/bin ln -s ../../..$(SYSCONFDIR)/$(PACKAGE)/management $(DESTDIR)/usr/share/$(PACKAGE)-management/conf ln -s ../../../usr/share/tomcat6/lib $(DESTDIR)/usr/share/$(PACKAGE)-management/lib diff --git a/packaging/debian/replace.properties b/packaging/debian/replace.properties index 8705c78a8f7..8c852060c02 100644 --- a/packaging/debian/replace.properties +++ b/packaging/debian/replace.properties @@ -34,7 +34,7 @@ AWSAPILOG=/var/log/cloudstack/awsapi/awsapi.log BINDIR=/usr/bin COMMONLIBDIR=/usr/share/cloudstack-common CONFIGUREVARS= -DEPSCLASSPATH= +DEPSCLASSPATH=/usr/share/tomcat6/bin/bootstrap.jar:/usr/share/tomcat6/bin/tomcat-juli.jar DOCDIR= IPALOCATORLOG=/var/log/cloudstack/management/ipallocator.log JAVADIR=/usr/share/cloudstack-management/webapps/client/WEB-INF/lib From 35e5b8e3f818f23661450b175eb8c20ae2489938 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sun, 31 Mar 2013 14:02:00 +0200 Subject: [PATCH 008/120] tomcat: Change some /etc/cloud paths to /etc/cloudstack Signed-off-by: Wido den Hollander --- client/tomcatconf/server-ssl.xml.in | 4 ++-- client/tomcatconf/tomcat6-ssl.conf.in | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/tomcatconf/server-ssl.xml.in b/client/tomcatconf/server-ssl.xml.in index 5d68f1d3d8b..37bc53d25d4 100755 --- a/client/tomcatconf/server-ssl.xml.in +++ b/client/tomcatconf/server-ssl.xml.in @@ -94,7 +94,7 @@ maxThreads="150" scheme="https" secure="true" URIEncoding="UTF-8" clientAuth="false" sslProtocol="TLS" keystoreType="JKS" - keystoreFile="/etc/cloud/management/cloudmanagementserver.keystore" + keystoreFile="/etc/cloudstack/management/cloudmanagementserver.keystore" keystorePass="vmops.com"/> @@ -200,7 +200,7 @@ maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreType="JKS" - keystoreFile="/etc/cloud/management/cloudmanagementserver.keystore" + keystoreFile="/etc/cloudstack/management/cloudmanagementserver.keystore" keystorePass="vmops.com"/> diff --git a/client/tomcatconf/tomcat6-ssl.conf.in b/client/tomcatconf/tomcat6-ssl.conf.in index 84b6d6275bb..0d2650871b6 100644 --- a/client/tomcatconf/tomcat6-ssl.conf.in +++ b/client/tomcatconf/tomcat6-ssl.conf.in @@ -40,7 +40,7 @@ CATALINA_TMPDIR="@MSENVIRON@/temp" # Use JAVA_OPTS to set java.library.path for libtcnative.so #JAVA_OPTS="-Djava.library.path=/usr/lib64" -JAVA_OPTS="-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/etc/cloud/management/cloudmanagementserver.keystore -Djavax.net.ssl.trustStorePassword=vmops.com -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:MaxPermSize=800m -XX:PermSize=512M" +JAVA_OPTS="-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/etc/cloudstack/management/cloudmanagementserver.keystore -Djavax.net.ssl.trustStorePassword=vmops.com -Dcom.sun.management.jmxremote.port=45219 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xmx2g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=@MSLOGDIR@ -XX:MaxPermSize=800m -XX:PermSize=512M" # What user should run tomcat TOMCAT_USER="@MSUSER@" From 44a0facd38159d53365a6444f4e025684add29b9 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sun, 31 Mar 2013 14:14:52 +0200 Subject: [PATCH 009/120] debian: Copy management server configuration from old location Signed-off-by: Wido den Hollander --- debian/cloudstack-management.postinst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/debian/cloudstack-management.postinst b/debian/cloudstack-management.postinst index 4e9b046caff..293810a97e7 100644 --- a/debian/cloudstack-management.postinst +++ b/debian/cloudstack-management.postinst @@ -20,7 +20,7 @@ if [ "$1" = configure ]; then if ! getent passwd cloud >/dev/null; then adduser --quiet --system --group --no-create-home --home /var/lib/cloudstack/management cloud else - usermod -m -d /var/lib/cloudstack/management cloud + usermod -m -d /var/lib/cloudstack/management cloud || true fi for i in /var/cache/cloudstack/management \ @@ -36,6 +36,20 @@ if [ "$1" = configure ]; then chgrp cloud $i done + OLDCONFDIR="/etc/cloud/management" + NEWCONFDIR="/etc/cloudstack/management" + CONFFILES="db.properties db-enc.properties cloud.keystore key" + + # Copy old configuration so the admin doesn't have to do that + # Only do so when we are installing for the first time + if [ -z "$2" ]; then + for FILE in $CONFFILES; do + if [ -f "$OLDCONFDIR/${FILE}" ]; then + cp -a $OLDCONFDIR/$FILE $NEWCONFDIR/$FILE + fi + done + fi + chmod 0640 /etc/cloudstack/management/db.properties chgrp cloud /etc/cloudstack/management/db.properties fi From 45eb9fdf8bf0e721555921464c239e9f3af03c37 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Sun, 31 Mar 2013 17:02:08 +0200 Subject: [PATCH 010/120] git: Add debian packaging files to .gitignore --- .gitignore | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 15f7f91c864..f41862895ec 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,11 @@ docs/runbook/tmp docs/runbook/publish .project Gemfile.lock +debian/tmp +debian/files +debian/cloudstack-*/* +debian/*.substvars +debian/*.debhelper +replace.properties.tmp +build-indep-stamp +configure-stamp From 7a3a1c792a0c263ccde74e6156afaa57470b2847 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Fri, 29 Mar 2013 17:14:59 +0530 Subject: [PATCH 011/120] Cloudstack-1739 Signed-off-by: Abhinandan Prateek --- .../hypervisor/kvm/resource/LibvirtComputingResource.java | 4 ++-- .../src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 6852e2cf711..7b70b62f694 100755 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -3066,8 +3066,8 @@ ServerResource { if (vmTO.getMinRam() != vmTO.getMaxRam()){ grd.setMemBalloning(true); - grd.setCurrentMem((int)vmTO.getMinRam()/1024); - grd.setMemorySize((int)vmTO.getMaxRam()/1024); + grd.setCurrentMem((long)vmTO.getMinRam()/1024); + grd.setMemorySize((long)vmTO.getMaxRam()/1024); } else{ grd.setMemorySize(vmTO.getMaxRam() / 1024); diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index c93aeeb2dd6..3d896a74c64 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -113,7 +113,7 @@ public class LibvirtVMDef { public static class GuestResourceDef { private long _mem; - private int _currentMem = -1; + private long _currentMem = -1; private String _memBacking; private int _vcpu = -1; private boolean _memBalloning= false; @@ -122,7 +122,7 @@ public class LibvirtVMDef { _mem = mem; } - public void setCurrentMem(int currMem) { + public void setCurrentMem(long currMem) { _currentMem = currMem; } From 355589c1f0c583cbbdc601f74dba504064f81bac Mon Sep 17 00:00:00 2001 From: Bharat Kumar Date: Mon, 1 Apr 2013 10:43:16 +0530 Subject: [PATCH 012/120] CLOUDSTACK-1395 Upgrade script for cpu and ram overcommit. It sets the overcommit values of all the clusters to 1. --- .../cloud/upgrade/dao/Upgrade410to420.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java index d26da4dc916..8ce118f3cbc 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade410to420.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade410to420.java @@ -76,8 +76,45 @@ public class Upgrade410to420 implements DbUpgrade { } } } + updateCluster_details(conn); } + //update the cluster_details table with default overcommit ratios. + private void updateCluster_details(Connection conn) { + PreparedStatement pstmt = null; + PreparedStatement pstmt1 = null; + PreparedStatement pstmt2 =null; + ResultSet rs = null; + + try { + pstmt = conn.prepareStatement("select id from `cloud`.`cluster`"); + pstmt1=conn.prepareStatement("INSERT INTO `cloud`.`cluster_details` (cluster_id, name, value) VALUES(?, 'cpuOvercommitRatio', '1')"); + pstmt2=conn.prepareStatement("INSERT INTO `cloud`.`cluster_details` (cluster_id, name, value) VALUES(?, 'memoryOvercommitRatio', '1')"); + rs = pstmt.executeQuery(); + while (rs.next()) { + long id = rs.getLong(1); + //update cluster_details table with the default overcommit ratios. + pstmt1.setLong(1,id); + pstmt1.execute(); + pstmt2.setLong(1,id); + pstmt2.execute(); + } + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to update cluster_details with default overcommit ratios.", e); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (pstmt != null) { + pstmt.close(); + } + } catch (SQLException e) { + } + } + } + + @Override public File[] getCleanupScripts() { String script = Script.findScript("", "db/schema-410to420-cleanup.sql"); From 8dd0b7747b2da1aa71110e871b0bd4ffdbcdfcb4 Mon Sep 17 00:00:00 2001 From: Jayapal Reddy Date: Mon, 1 Apr 2013 16:22:12 +0530 Subject: [PATCH 013/120] Mulitiple ip address per nic support for advacned shared networks Description: Changes added for supporting multiple ip address per nic for shared networks Testing Done: Tested adding and removing the ip for nic using the APIs --- .../com/cloud/network/NetworkServiceImpl.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index d5034597f4f..4eb620c4243 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -490,6 +490,9 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { accountId = network.getAccountId(); domainId = network.getDomainId(); + // Validate network offering + NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(network.getNetworkOfferingId()); + // verify permissions _accountMgr.checkAccess(ipOwner, null, true, network); @@ -518,7 +521,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { } catch (InsufficientAddressCapacityException e) { throw new InvalidParameterValueException("Allocating guest ip for nic failed"); } - } else if (dc.getNetworkType() == NetworkType.Basic) { + } else if (dc.getNetworkType() == NetworkType.Basic || ntwkOff.getGuestType() == Network.GuestType.Shared) { Account caller = UserContext.current().getCaller(); long callerUserId = UserContext.current().getCallerUserId(); _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); @@ -546,14 +549,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { s_logger.error("Allocating ip to guest nic " + nicId + " failed"); return null; } - } else if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && zone.getNetworkType() == NetworkType.Advanced) { - // if shared network in the advanced zone, then check the caller against the network for 'AccessType.UseNetwork' - Account caller = UserContext.current().getCaller(); - long callerUserId = UserContext.current().getCallerUserId(); - _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId()); - } } else { s_logger.error("AddIpToVMNic is not supported in this network..."); return null; @@ -594,6 +589,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { Network network = _networksDao.findById(secIpVO.getNetworkId()); + if (network == null) { + throw new InvalidParameterValueException("Invalid network id is given"); + } + + // Validate network offering + NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(network.getNetworkOfferingId()); + // verify permissions _accountMgr.checkAccess(caller, null, true, network); @@ -627,7 +629,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { s_logger.debug("VM nic IP " + secondaryIp + " is associated with the static NAT rule public IP address id " + publicIpVO.getId()); throw new InvalidParameterValueException("Can' remove the ip " + secondaryIp + "is associate with static NAT rule public IP address id " + publicIpVO.getId()); } - } else if (dc.getNetworkType() == NetworkType.Basic) { + } else if (dc.getNetworkType() == NetworkType.Basic || ntwkOff.getGuestType() == Network.GuestType.Shared) { IPAddressVO ip = _ipAddressDao.findByIpAndNetworkId(secIpVO.getNetworkId(), secIpVO.getIp4Address()); if (ip != null) { Transaction txn = Transaction.currentTxn(); @@ -636,7 +638,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { _ipAddressDao.unassignIpAddress(ip.getId()); txn.commit(); } - } else if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && dc.getNetworkType() == NetworkType.Advanced) { + } else { throw new InvalidParameterValueException("Not supported for this network now"); } From 6eac4229434b46ee74b5952d3abd26b646166b39 Mon Sep 17 00:00:00 2001 From: Pradeep Soundararajan Date: Mon, 1 Apr 2013 15:31:08 +0100 Subject: [PATCH 014/120] CLOUDSTACK-1689: Adding ipset as part of agent install for debian Signed-off-by: Chip Childers --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 8f82fc3ab2f..27a3150158e 100644 --- a/debian/control +++ b/debian/control @@ -22,7 +22,7 @@ Description: CloudStack server library Package: cloudstack-agent Architecture: all -Depends: openjdk-6-jre | openjdk-7-jre, cloudstack-common (= ${source:Version}), lsb-base (>= 3.2), libcommons-daemon-java, libjna-java, openssh-client, libvirt0, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, uuid-runtime, rsync, grep, iproute, perl-base, perl-modules, ebtables, vlan, wget, jsvc +Depends: openjdk-6-jre | openjdk-7-jre, cloudstack-common (= ${source:Version}), lsb-base (>= 3.2), libcommons-daemon-java, libjna-java, openssh-client, libvirt0, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, uuid-runtime, rsync, grep, iproute, perl-base, perl-modules, ebtables, vlan, wget, jsvc, ipset Conflicts: cloud-agent, cloud-agent-libs, cloud-agent-deps, cloud-agent-scripts Description: CloudStack agent The CloudStack agent is in charge of managing shared computing resources in From aa79ccf985a172603a9ff15fbaa71dbfb3dad99d Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Mon, 1 Apr 2013 15:40:21 -0700 Subject: [PATCH 015/120] CLOUDSTACK-922: LXC Support in Cloudstack. Signed-off-by: Edison Su --- agent/conf/agent.properties | 9 + api/src/com/cloud/agent/api/Command.java | 2 + .../com/cloud/agent/api/RebootCommand.java | 1 + api/src/com/cloud/agent/api/StopCommand.java | 7 +- api/src/com/cloud/hypervisor/Hypervisor.java | 3 + api/src/com/cloud/storage/Storage.java | 3 +- client/tomcatconf/applicationContext.xml.in | 8 + client/tomcatconf/componentContext.xml.in | 1 + .../kvm/resource/DirectVifDriver.java | 65 +++ .../resource/LibvirtComputingResource.java | 160 ++++--- .../kvm/resource/LibvirtConnection.java | 52 ++- .../kvm/resource/LibvirtDomainXMLParser.java | 21 +- .../kvm/resource/LibvirtStorageVolumeDef.java | 6 +- .../hypervisor/kvm/resource/LibvirtVMDef.java | 71 +++- .../kvm/storage/KVMPhysicalDisk.java | 2 +- .../kvm/storage/KVMStoragePoolManager.java | 4 + .../kvm/storage/LibvirtStorageAdaptor.java | 37 +- .../kvm/resource/LibvirtVMDefTest.java | 14 + .../storage/secondary/cloud-install-sys-tmplt | 4 + .../consoleproxy/ConsoleProxyManagerImpl.java | 12 +- server/src/com/cloud/hypervisor/LXCGuru.java | 58 +++ .../kvm/discoverer/KvmServerDiscoverer.java | 371 +---------------- .../discoverer/LibvirtServerDiscoverer.java | 393 ++++++++++++++++++ .../kvm/discoverer/LxcServerDiscoverer.java | 33 ++ .../cloud/network/SshKeysDistriMonitor.java | 3 +- .../VirtualNetworkApplianceManagerImpl.java | 8 +- .../SecondaryStorageManagerImpl.java | 6 +- .../template/HypervisorTemplateAdapter.java | 3 + .../cloud/vm/VirtualMachineManagerImpl.java | 27 +- setup/db/db/schema-410to420.sql | 12 + ui/scripts/system.js | 62 ++- ui/scripts/templates.js | 4 + ui/scripts/zoneWizard.js | 10 + 33 files changed, 986 insertions(+), 486 deletions(-) create mode 100644 plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/DirectVifDriver.java create mode 100644 server/src/com/cloud/hypervisor/LXCGuru.java create mode 100644 server/src/com/cloud/hypervisor/kvm/discoverer/LibvirtServerDiscoverer.java create mode 100644 server/src/com/cloud/hypervisor/kvm/discoverer/LxcServerDiscoverer.java diff --git a/agent/conf/agent.properties b/agent/conf/agent.properties index f7eac674712..e49afbf2aaf 100644 --- a/agent/conf/agent.properties +++ b/agent/conf/agent.properties @@ -80,3 +80,12 @@ domr.scripts.dir=scripts/network/domr/kvm # native = com.cloud.hypervisor.kvm.resource.BridgeVifDriver # openvswitch = com.cloud.hypervisor.kvm.resource.OvsBridgeDriver #libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.BridgeVifDriver + +# set the hypervisor type, values are: kvm, lxc +# hypervisor.type=kvm + +# settings to enable direct networking in libvirt, should not be used +# on hosts that run system vms, values for mode are: private, bridge, vepa +# libvirt.vif.driver=com.cloud.hypervisor.kvm.resource.DirectVifDriver +# network.direct.source.mode=private +# network.direct.device=eth0 diff --git a/api/src/com/cloud/agent/api/Command.java b/api/src/com/cloud/agent/api/Command.java index 9cd67495e04..aadbeaf0def 100755 --- a/api/src/com/cloud/agent/api/Command.java +++ b/api/src/com/cloud/agent/api/Command.java @@ -27,6 +27,8 @@ import com.cloud.agent.api.LogLevel.Log4jLevel; */ public abstract class Command { + public static final String HYPERVISOR_TYPE = "hypervisorType"; + // allow command to carry over hypervisor or other environment related context info @LogLevel(Log4jLevel.Trace) protected Map contextMap = new HashMap(); diff --git a/api/src/com/cloud/agent/api/RebootCommand.java b/api/src/com/cloud/agent/api/RebootCommand.java index 299e61b76af..49712b6fce5 100755 --- a/api/src/com/cloud/agent/api/RebootCommand.java +++ b/api/src/com/cloud/agent/api/RebootCommand.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.agent.api; +import com.cloud.hypervisor.Hypervisor; import com.cloud.vm.VirtualMachine; public class RebootCommand extends Command { diff --git a/api/src/com/cloud/agent/api/StopCommand.java b/api/src/com/cloud/agent/api/StopCommand.java index 9ee7ce3c874..1c67f3816ca 100755 --- a/api/src/com/cloud/agent/api/StopCommand.java +++ b/api/src/com/cloud/agent/api/StopCommand.java @@ -38,10 +38,9 @@ public class StopCommand extends RebootCommand { super(vm); this.vnet = vnet; } - - public StopCommand(VirtualMachine vm, String vmName, String vnet) { - super(vmName); - this.vnet = vnet; + + public StopCommand(VirtualMachine vm) { + super(vm); } public StopCommand(String vmName) { diff --git a/api/src/com/cloud/hypervisor/Hypervisor.java b/api/src/com/cloud/hypervisor/Hypervisor.java index 2e0012dca6f..a4ee5b98fd9 100644 --- a/api/src/com/cloud/hypervisor/Hypervisor.java +++ b/api/src/com/cloud/hypervisor/Hypervisor.java @@ -29,6 +29,7 @@ public class Hypervisor { BareMetal, Simulator, Ovm, + LXC, Any; /*If you don't care about the hypervisor type*/ @@ -54,6 +55,8 @@ public class Hypervisor { return HypervisorType.Simulator; } else if (hypervisor.equalsIgnoreCase("Ovm")) { return HypervisorType.Ovm; + } else if (hypervisor.equalsIgnoreCase("LXC")) { + return HypervisorType.LXC; } else if (hypervisor.equalsIgnoreCase("Any")) { return HypervisorType.Any; } else { diff --git a/api/src/com/cloud/storage/Storage.java b/api/src/com/cloud/storage/Storage.java index fba12b62d3d..c130fe222bf 100755 --- a/api/src/com/cloud/storage/Storage.java +++ b/api/src/com/cloud/storage/Storage.java @@ -26,7 +26,8 @@ public class Storage { VHD(true, true, true), ISO(false, false, false), OVA(true, true, true, "ova"), - BAREMETAL(false, false, false); + BAREMETAL(false, false, false), + TAR(false, false, false); private final boolean thinProvisioned; private final boolean supportSparse; diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index ca6b4020364..636eac2b939 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -499,6 +499,10 @@ + + + + @@ -568,6 +572,10 @@ + + + + diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 9d95e150129..fea1d0f6157 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -106,6 +106,7 @@ + + org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java From 8d34b5809d459eac90eea1f01cc5b20dedb39f11 Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Tue, 2 Apr 2013 14:55:29 +0530 Subject: [PATCH 018/120] CLOUDSTACK-1887:removing the host option from the scope field for primary storage --- ui/scripts/zoneWizard.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js index 76fd5e9f358..8add9bb085e 100755 --- a/ui/scripts/zoneWizard.js +++ b/ui/scripts/zoneWizard.js @@ -1204,7 +1204,7 @@ if(selectedHypervisorObj.hypervisortype != "KVM"){ var scope=[]; scope.push({ id: 'cluster', description: _l('label.cluster') }); - scope.push({ id: 'host', description: _l('label.host') }); + //scope.push({ id: 'host', description: _l('label.host') }); args.response.success({data: scope}); } @@ -1212,7 +1212,7 @@ var scope=[]; scope.push({ id: 'zone', description: _l('label.zone.wide') }); scope.push({ id: 'cluster', description: _l('label.cluster') }); - scope.push({ id: 'host', description: _l('label.host') }); + // scope.push({ id: 'host', description: _l('label.host') }); args.response.success({data: scope}); } From dedec164e8cce17b861d517fe8e29bb99902e113 Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Tue, 2 Apr 2013 16:19:24 +0800 Subject: [PATCH 019/120] fix CLOUDSTACK-1698 --- .../com/cloud/storage/VolumeManagerImpl.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java index ff0235f018a..1e8edafe4e2 100644 --- a/server/src/com/cloud/storage/VolumeManagerImpl.java +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -169,6 +169,8 @@ import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.SecondaryStorageVmDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import com.cloud.vm.snapshot.VMSnapshotVO; +import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Component public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @@ -289,6 +291,8 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { @Inject protected ResourceTagDao _resourceTagDao; @Inject + protected VMSnapshotDao _vmSnapshotDao; + @Inject protected List _storagePoolAllocators; @Inject ConfigurationDao _configDao; @@ -1669,6 +1673,13 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { } } + // if target VM has associated VM snapshots + List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + if(vmSnapshots.size() > 0){ + throw new InvalidParameterValueException( + "Unable to attach volume, please specify a VM that does not have VM snapshots"); + } + // permission check _accountMgr.checkAccess(caller, null, true, volume, vm); @@ -1826,6 +1837,13 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager { "Please specify a VM that is either running or stopped."); } + // Check if the VM has VM snapshots + List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + if(vmSnapshots.size() > 0){ + throw new InvalidParameterValueException( + "Unable to detach volume, the specified volume is attached to a VM that has VM snapshots."); + } + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor .getCurrentExecutor(); if (asyncExecutor != null) { From 4edef1fd305891beb5393b722e96f4a140934f9f Mon Sep 17 00:00:00 2001 From: Mice Xia Date: Tue, 2 Apr 2013 17:24:49 +0800 Subject: [PATCH 020/120] fix CLOUDSTACK-1700 --- .../hypervisor/xen/resource/CitrixResourceBase.java | 12 +++++++++++- server/src/com/cloud/api/ApiResponseHelper.java | 1 + .../com/cloud/vm/snapshot/VMSnapshotManagerImpl.java | 8 ++++++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index d2f3f69f088..c50f13ce7e5 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -262,6 +262,7 @@ import com.xensource.xenapi.SR; import com.xensource.xenapi.Session; import com.xensource.xenapi.Task; import com.xensource.xenapi.Types; +import com.xensource.xenapi.Types.BadAsyncResult; import com.xensource.xenapi.Types.BadServerResponse; import com.xensource.xenapi.Types.ConsoleProtocol; import com.xensource.xenapi.Types.IpConfigurationMode; @@ -6452,7 +6453,16 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe success = true; return new CreateVMSnapshotAnswer(cmd, cmd.getTarget(), cmd.getVolumeTOs()); } catch (Exception e) { - String msg = e.getMessage(); + String msg = ""; + if(e instanceof BadAsyncResult){ + String licenseKeyWord = "LICENCE_RESTRICTION"; + BadAsyncResult errorResult = (BadAsyncResult)e; + if(errorResult.shortDescription != null && errorResult.shortDescription.contains(licenseKeyWord)){ + msg = licenseKeyWord; + } + }else{ + msg = e.getMessage(); + } s_logger.error("Creating VM Snapshot " + cmd.getTarget().getSnapshotName() + " failed due to: " + msg); return new CreateVMSnapshotAnswer(cmd, false, msg); } finally { diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index d350de2dfdd..64be7f8758a 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -446,6 +446,7 @@ public class ApiResponseHelper implements ResponseGenerator { vmSnapshotResponse.setParentName(ApiDBUtils.getVMSnapshotById(vmSnapshot.getParent()).getDisplayName()); vmSnapshotResponse.setCurrent(vmSnapshot.getCurrent()); vmSnapshotResponse.setType(vmSnapshot.getType().toString()); + vmSnapshotResponse.setObjectName("vmsnapshot"); return vmSnapshotResponse; } diff --git a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java index 12a059727be..638be6c0c9b 100644 --- a/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java +++ b/server/src/com/cloud/vm/snapshot/VMSnapshotManagerImpl.java @@ -367,9 +367,13 @@ public class VMSnapshotManagerImpl extends ManagerBase implements VMSnapshotMana processAnswer(vmSnapshot, userVm, answer, hostId); s_logger.debug("Create vm snapshot " + vmSnapshot.getName() + " succeeded for vm: " + userVm.getInstanceName()); }else{ - String errMsg = answer.getDetails(); - s_logger.error("Agent reports creating vm snapshot " + vmSnapshot.getName() + " failed for vm: " + userVm.getInstanceName() + " due to " + errMsg); + + String errMsg = "Creating VM snapshot: " + vmSnapshot.getName() + " failed"; + if(answer != null && answer.getDetails() != null) + errMsg = errMsg + " due to " + answer.getDetails(); + s_logger.error(errMsg); vmSnapshotStateTransitTo(vmSnapshot, VMSnapshot.Event.OperationFailed); + throw new CloudRuntimeException(errMsg); } return vmSnapshot; } catch (Exception e) { From 3d8afb0cfbcf20f4644fb58171f6c587c60f50ba Mon Sep 17 00:00:00 2001 From: Pranav Saxena Date: Tue, 2 Apr 2013 16:21:25 +0530 Subject: [PATCH 021/120] CLOUDSTACK-1887:removing the host option from the scope field for primary storage --- ui/scripts/system.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 98570d249ea..2fdf5f925be 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -9316,8 +9316,8 @@ select: function(args) { var scope = [ { id: 'zone', description: _l('label.zone.wide') }, - { id: 'cluster', description: _l('label.cluster') }, - { id: 'host', description: _l('label.host') } + { id: 'cluster', description: _l('label.cluster') } + // { id: 'host', description: _l('label.host') } ]; args.response.success({ From 009749fb796bc935f610921f1bdc71e8d993198d Mon Sep 17 00:00:00 2001 From: Sateesh Chodapuneedi Date: Wed, 20 Mar 2013 04:44:59 +0530 Subject: [PATCH 022/120] CLOUDSTACK-301 Nexus 1000v DVS integration is not functional Moved validateVSMCluster method from CiscoNexusVSMDeviceManagerImpl to CiscoNexusVSMElement. Signed-off-by: Sateesh Chodapuneedi --- .../vmware/VmwareServerDiscoverer.java | 17 ++- .../CiscoNexusVSMDeviceManagerImpl.java | 96 ----------------- .../network/element/CiscoNexusVSMElement.java | 100 +++++++++++++++++- .../element/CiscoNexusVSMElementService.java | 7 ++ 4 files changed, 122 insertions(+), 98 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java index 2b3eba690e3..2f82b534af2 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java @@ -45,6 +45,7 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.DiscoveredWithErrorException; import com.cloud.exception.DiscoveryException; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceInUseException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; @@ -62,6 +63,8 @@ import com.cloud.network.Networks.TrafficType; import com.cloud.network.PhysicalNetwork; import com.cloud.network.VmwareTrafficLabel; import com.cloud.network.dao.CiscoNexusVSMDeviceDao; +import com.cloud.network.element.CiscoNexusVSMElement; +import com.cloud.network.element.CiscoNexusVSMElementService; import com.cloud.resource.Discoverer; import com.cloud.resource.DiscovererBase; import com.cloud.resource.ResourceManager; @@ -104,6 +107,8 @@ public class VmwareServerDiscoverer extends DiscovererBase implements @Inject CiscoNexusVSMDeviceDao _nexusDao; @Inject + CiscoNexusVSMElementService _nexusElement; + @Inject NetworkModel _netmgr; @Inject HypervisorCapabilitiesDao _hvCapabilitiesDao; @@ -255,7 +260,17 @@ public class VmwareServerDiscoverer extends DiscovererBase implements guestTrafficLabel = _netmgr.getDefaultGuestTrafficLabel(dcId, HypervisorType.VMware); if (guestTrafficLabel != null) { s_logger.info("Detected guest network label : " + guestTrafficLabel); - } + } + String vsmIp = _urlParams.get("vsmipaddress"); + String vsmUser = _urlParams.get("vsmusername"); + String vsmPassword = _urlParams.get("vsmpassword"); + String clusterName = cluster.getName(); + try { + _nexusElement.validateVsmCluster(vsmIp, vsmUser, vsmPassword, clusterId, clusterName); + } catch(ResourceInUseException ex) { + DiscoveryException discEx = new DiscoveryException(ex.getLocalizedMessage() + ". The resource is " + ex.getResourceName()); + throw discEx; + } vsmCredentials = _vmwareMgr.getNexusVSMCredentialsByClusterId(clusterId); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java index e17d99d3184..9ec64ffce9d 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java @@ -23,8 +23,6 @@ import javax.inject.Inject; import org.apache.log4j.Logger; import com.cloud.agent.api.StartupCommand; -import com.cloud.configuration.Config; -import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVSMMapVO; @@ -64,8 +62,6 @@ public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase { HostDetailsDao _hostDetailDao; @Inject PortProfileDao _ppDao; - @Inject - ConfigurationDao _configDao; private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalLoadBalancerDeviceManagerImpl.class); @@ -315,96 +311,4 @@ public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase { // TODO Auto-generated method stub return null; } - - @DB - public boolean vliadateVsmCluster(String vsmIp, String vsmUser, String vsmPassword, long clusterId, String clusterName) throws ResourceInUseException { - // Check if we're associating a Cisco Nexus VSM with a vmware cluster. - if (Boolean.parseBoolean(_configDao.getValue(Config.VmwareUseNexusVSwitch.toString()))) { - - if(vsmIp != null && vsmUser != null && vsmPassword != null) { - NetconfHelper netconfClient; - try { - netconfClient = new NetconfHelper(vsmIp, vsmUser, vsmPassword); - netconfClient.disconnect(); - } catch (CloudRuntimeException e) { - String msg = "Invalid credentials supplied for user " + vsmUser + " for Cisco Nexus 1000v VSM at " + vsmIp; - s_logger.error(msg); - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(msg); - } - - Transaction txn; - - // If VSM already exists and is mapped to a cluster, fail this operation. - CiscoNexusVSMDeviceVO vsm = _ciscoNexusVSMDeviceDao.getVSMbyIpaddress(vsmIp); - if(vsm != null) { - List clusterList = _clusterVSMDao.listByVSMId(vsm.getId()); - if (clusterList != null && !clusterList.isEmpty()) { - s_logger.error("Failed to add cluster: specified Nexus VSM is already associated with another cluster"); - _clusterDao.remove(clusterId); - ResourceInUseException ex = new ResourceInUseException("Failed to add cluster: specified Nexus VSM is already associated with another cluster with specified Id"); - // get clusterUuid to report error - ClusterVO cluster = _clusterDao.findById(clusterList.get(0).getClusterId()); - ex.addProxyObject(cluster.getUuid()); - throw ex; - } - } - // persist credentials to database if the VSM entry is not already in the db. - if (_ciscoNexusVSMDeviceDao.getVSMbyIpaddress(vsmIp) == null) { - vsm = new CiscoNexusVSMDeviceVO(vsmIp, vsmUser, vsmPassword); - txn = Transaction.currentTxn(); - try { - txn.start(); - vsm = _ciscoNexusVSMDeviceDao.persist(vsm); - txn.commit(); - } catch (Exception e) { - txn.rollback(); - s_logger.error("Failed to persist Cisco Nexus 1000v VSM details to database. Exception: " + e.getMessage()); - // Removing the cluster record which was added already because the persistence of Nexus VSM credentials has failed. - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(e.getMessage()); - } - } - // Create a mapping between the cluster and the vsm. - vsm = _ciscoNexusVSMDeviceDao.getVSMbyIpaddress(vsmIp); - if (vsm != null) { - ClusterVSMMapVO connectorObj = new ClusterVSMMapVO(clusterId, vsm.getId()); - txn = Transaction.currentTxn(); - try { - txn.start(); - _clusterVSMDao.persist(connectorObj); - txn.commit(); - } catch (Exception e) { - txn.rollback(); - s_logger.error("Failed to associate Cisco Nexus 1000v VSM with cluster: " + clusterName + ". Exception: " + e.getMessage()); - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(e.getMessage()); - } - } - } else { - String msg; - msg = "The global parameter " + Config.VmwareUseNexusVSwitch.toString() + - " is set to \"true\". Following mandatory parameters are not specified. "; - if(vsmIp == null) { - msg += "vsmipaddress: Management IP address of Cisco Nexus 1000v dvSwitch. "; - } - if(vsmUser == null) { - msg += "vsmusername: Name of a user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; - } - if(vsmPassword == null) { - if(vsmUser != null) { - msg += "vsmpassword: Password of user account " + vsmUser + ". "; - } else { - msg += "vsmpassword: Password of user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; - } - } - s_logger.error(msg); - // Cleaning up the cluster record as addCluster operation failed because Nexus dvSwitch credentials are supplied. - _clusterDao.remove(clusterId); - throw new CloudRuntimeException(msg); - } - return true; - } - return false; - } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java index daf7dd6bd40..4629b6c2d3e 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java +++ b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElement.java @@ -34,6 +34,11 @@ import com.cloud.api.commands.EnableCiscoNexusVSMCmd; import com.cloud.api.commands.DisableCiscoNexusVSMCmd; import com.cloud.api.commands.ListCiscoNexusVSMsCmd; import com.cloud.api.response.CiscoNexusVSMResponse; +import com.cloud.configuration.Config; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.ClusterVSMMapVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.ClusterVSMMapDao; import com.cloud.deploy.DeployDestination; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; @@ -55,7 +60,10 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; import com.cloud.offering.NetworkOffering; import com.cloud.org.Cluster; +import com.cloud.utils.cisco.n1kv.vsm.NetconfHelper; import com.cloud.utils.component.Manager; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; import com.cloud.exception.ResourceInUseException; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.server.ManagementService; @@ -66,7 +74,11 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme private static final Logger s_logger = Logger.getLogger(CiscoNexusVSMElement.class); @Inject - CiscoNexusVSMDeviceDao _vsmDao; + CiscoNexusVSMDeviceDao _vsmDao; + @Inject + ClusterDao _clusterDao; + @Inject + ClusterVSMMapDao _clusterVSMDao; @Override public Map> getCapabilities() { @@ -247,4 +259,90 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme cmdList.add(DeleteCiscoNexusVSMCmd.class); return cmdList; } + + @DB + public boolean validateVsmCluster(String vsmIp, String vsmUser, String vsmPassword, long clusterId, String clusterName) throws ResourceInUseException { + if(vsmIp != null && vsmUser != null && vsmPassword != null) { + NetconfHelper netconfClient; + try { + netconfClient = new NetconfHelper(vsmIp, vsmUser, vsmPassword); + netconfClient.disconnect(); + } catch (CloudRuntimeException e) { + String msg = "Invalid credentials supplied for user " + vsmUser + " for Cisco Nexus 1000v VSM at " + vsmIp; + s_logger.error(msg); + _clusterDao.remove(clusterId); + throw new CloudRuntimeException(msg); + } + + Transaction txn; + + // If VSM already exists and is mapped to a cluster, fail this operation. + CiscoNexusVSMDeviceVO vsm = _vsmDao.getVSMbyIpaddress(vsmIp); + if(vsm != null) { + List clusterList = _clusterVSMDao.listByVSMId(vsm.getId()); + if (clusterList != null && !clusterList.isEmpty()) { + s_logger.error("Failed to add cluster: specified Nexus VSM is already associated with another cluster"); + ResourceInUseException ex = new ResourceInUseException("Failed to add cluster: specified Nexus VSM is already associated with another cluster with specified Id"); + // get clusterUuid to report error + ClusterVO cluster = _clusterDao.findById(clusterList.get(0).getClusterId()); + ex.addProxyObject(cluster.getUuid()); + _clusterDao.remove(clusterId); + throw ex; + } + } + // persist credentials to database if the VSM entry is not already in the db. + if (_vsmDao.getVSMbyIpaddress(vsmIp) == null) { + vsm = new CiscoNexusVSMDeviceVO(vsmIp, vsmUser, vsmPassword); + txn = Transaction.currentTxn(); + try { + txn.start(); + vsm = _vsmDao.persist(vsm); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.error("Failed to persist Cisco Nexus 1000v VSM details to database. Exception: " + e.getMessage()); + throw new CloudRuntimeException(e.getMessage()); + } + } + // Create a mapping between the cluster and the vsm. + vsm = _vsmDao.getVSMbyIpaddress(vsmIp); + if (vsm != null) { + ClusterVSMMapVO connectorObj = new ClusterVSMMapVO(clusterId, vsm.getId()); + txn = Transaction.currentTxn(); + try { + txn.start(); + _clusterVSMDao.persist(connectorObj); + txn.commit(); + } catch (Exception e) { + txn.rollback(); + s_logger.error("Failed to associate Cisco Nexus 1000v VSM with cluster: " + clusterName + ". Exception: " + e.getMessage()); + _vsmDao.remove(vsm.getId()); // Removing VSM from virtual_supervisor_module table because association with cluster failed. + // Cluster would be deleted from cluster table by callee. + throw new CloudRuntimeException(e.getMessage()); + } + } + } else { + String msg; + msg = "The global parameter " + Config.VmwareUseNexusVSwitch.toString() + + " is set to \"true\". Following mandatory parameters are not specified. "; + if(vsmIp == null) { + msg += "vsmipaddress: Management IP address of Cisco Nexus 1000v dvSwitch. "; + } + if(vsmUser == null) { + msg += "vsmusername: Name of a user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; + } + if(vsmPassword == null) { + if(vsmUser != null) { + msg += "vsmpassword: Password of user account " + vsmUser + ". "; + } else { + msg += "vsmpassword: Password of user account with admin privileges over Cisco Nexus 1000v dvSwitch. "; + } + } + s_logger.error(msg); + // Cleaning up the cluster record as addCluster operation failed because of invalid credentials of Nexus dvSwitch. + _clusterDao.remove(clusterId); + throw new CloudRuntimeException(msg); + } + return true; + } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java index 1cc9fafb052..e90581ae56c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java +++ b/plugins/hypervisors/vmware/src/com/cloud/network/element/CiscoNexusVSMElementService.java @@ -24,6 +24,7 @@ import com.cloud.api.commands.EnableCiscoNexusVSMCmd; import com.cloud.api.commands.DisableCiscoNexusVSMCmd; import com.cloud.api.commands.ListCiscoNexusVSMsCmd; import com.cloud.api.response.CiscoNexusVSMResponse; +import com.cloud.exception.ResourceInUseException; import com.cloud.network.CiscoNexusVSMDeviceVO; import com.cloud.network.CiscoNexusVSMDevice; import com.cloud.utils.component.PluggableService; @@ -68,4 +69,10 @@ public interface CiscoNexusVSMElementService extends PluggableService { * @return CiscoNexusVSMResponse */ public CiscoNexusVSMResponse createCiscoNexusVSMDetailedResponse(CiscoNexusVSMDevice vsmDeviceVO); + + /** + * Validate Cisco Nexus VSM before associating with cluster + * + */ + public boolean validateVsmCluster(String vsmIp, String vsmUser, String vsmPassword, long clusterId, String clusterName) throws ResourceInUseException; } From 8e917b1ad3c0d3076b0c6425ea3318a6d6dd5c25 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 5 Mar 2013 11:48:16 +0530 Subject: [PATCH 023/120] removing unused commented dependencies removing the spring related dependencies that were commented out. Signed-off-by: Prasanna Santhanam --- plugins/pom.xml | 3 +- pom.xml | 354 +++++++++++++++++++++++++++++------------------- 2 files changed, 215 insertions(+), 142 deletions(-) diff --git a/plugins/pom.xml b/plugins/pom.xml index d7e8debbf02..348ffa26308 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -16,7 +16,8 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ---> +--> + 4.0.0 cloudstack-plugins Apache CloudStack Plugin POM diff --git a/pom.xml b/pom.xml index dab3db2c7c1..0393d0cc1a3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,15 +1,23 @@ - + + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 @@ -26,8 +34,8 @@ Apache CloudStack is an IaaS (“Infrastracture as a Service”) cloud orchestration platform. http://www.cloudstack.org - scm:git:https://git-wip-us.apache.org/repos/asf/cloudstack.git - scm:git:https://git-wip-us.apache.org/repos/asf/cloudstack.git + scm:git:https://git-wip-us.apache.org/repos/asf/incubator-cloudstack.git + scm:git:https://git-wip-us.apache.org/repos/asf/incubator-cloudstack.git jira @@ -35,7 +43,7 @@ - + 1.6 UTF-8 @@ -84,7 +92,6 @@ 0.10 build/replace.properties 0.4.9 - target @@ -99,49 +106,40 @@ Apache CloudStack User List - users-subscribe@cloudstack.apache.org - users-unsubscribe@cloudstack.apache.org - users@cloudstack.apache.org - http://mail-archives.apache.org/mod_mbox/cloudstack-users - - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-users - + cloudstack-users-subscribe@incubator.apache.org + cloudstack-users-unsubscribe@incubator.apache.org + cloudstack-users@incubator.apache.org + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-users Apache CloudStack Developer List - dev-subscribe@cloudstack.apache.org - dev-unsubscribe@cloudstack.apache.org - dev@cloudstack.apache.org - http://mail-archives.apache.org/mod_mbox/cloudstack-dev - - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-dev - + cloudstack-dev-subscribe@incubator.apache.org + cloudstack-dev-unsubscribe@incubator.apache.org + cloudstack-dev@incubator.apache.org + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-dev Apache CloudStack Commits List - commits-subscribe@cloudstack.apache.org - commits-unsubscribe@cloudstack.apache.org - commits@cloudstack.apache.org - http://mail-archives.apache.org/mod_mbox/cloudstack-commits - - http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-commits - + cloudstack-commits-subscribe@incubator.apache.org + cloudstack-commits-unsubscribe@incubator.apache.org + cloudstack-commits@incubator.apache.org + http://mail-archives.apache.org/mod_mbox/incubator-cloudstack-commits The Apache CloudStack Team - dev@cloudstack.apache.org - http://cloudstack.apache.org/ + cloudstack-dev@incubator.apache.org + http://incubator.apache.org/projects/cloudstack.html Apache Software Foundation http://apache.org/ - Jenkins - http://builds.apache.org/ + Jenkin + http://jenkins.cloudstack.org/ @@ -176,11 +174,11 @@ - - mysql - mysql-connector-java - ${cs.mysql.version} - + + mysql + mysql-connector-java + ${cs.mysql.version} + @@ -190,12 +188,12 @@ junit ${cs.junit.version} test - - - org.springframework - spring-core - ${org.springframework.version} - + + + org.springframework + spring-core + ${org.springframework.version} + org.springframework spring-context @@ -206,36 +204,18 @@ spring-web ${org.springframework.version} - - org.mockito - mockito-all - 1.9.5 - test - - - org.springframework - spring-test - ${org.springframework.version} - test + org.mockito + mockito-all + 1.9.5 + test + + org.springframework + spring-test + ${org.springframework.version} + test + org.aspectj aspectjrt @@ -247,19 +227,17 @@ 1.7.1 - javax.inject - javax.inject - 1 + javax.inject + javax.inject + 1 install - ${basedir}/${cs.target.dir}/classes - ${basedir}/${cs.target.dir}/test-classes - org.eclipse.m2e @@ -282,7 +260,7 @@ - + @@ -340,9 +318,11 @@ dist/console-proxy/js/jquery.js scripts/vm/systemvm/id_rsa.cloud tools/devcloud/basebuild/puppet-devcloudinitial/files/network.conf - tools/appliance/definitions/devcloud/* - tools/appliance/definitions/systemvmtemplate/* - tools/appliance/definitions/systemvmtemplate64/* + tools/appliance/definitions/systemvmtemplate/base.sh + tools/appliance/definitions/systemvmtemplate/cleanup.sh + tools/appliance/definitions/systemvmtemplate/definition.rb + tools/appliance/definitions/systemvmtemplate/preseed.cfg + tools/appliance/definitions/systemvmtemplate/zerodisk.sh tools/cli/cloudmonkey.egg-info/* tools/devcloud/src/deps/boxes/basebox-build/definition.rb tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg @@ -410,41 +390,41 @@ ${cs.jdk.version} ${cs.jdk.version} - true - 128m - 512m - -XDignore.symbol.file=true + true + 128m + 512m + -XDignore.symbol.file=true - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - true - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.7 - - - remove-old-installers - - remove-project-artifact - - - true - - - - + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + remove-old-installers + + remove-project-artifact + + + true + + + + org.apache.maven.plugins maven-dependency-plugin @@ -472,31 +452,15 @@ - eclipse - - target-eclipse - - - developer - - tools/devcloud/devcloud.cfg - + + tools/devcloud/devcloud.cfg + developer tools - - impatient - - tools/devcloud/devcloud.cfg - - - developer - - - vmware @@ -508,5 +472,113 @@ vmware-base + + simulator + + + deploydb-simulator + + + + + + org.codehaus.mojo + properties-maven-plugin + 1.0-alpha-2 + + + initialize + + read-project-properties + + + + ${project.basedir}/utils/conf/db.properties + ${project.basedir}/utils/conf/db.properties.override + + true + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + + mysql + mysql-connector-java + ${cs.mysql.version} + + + commons-dbcp + commons-dbcp + ${cs.dbcp.version} + + + commons-pool + commons-pool + ${cs.pool.version} + + + org.jasypt + jasypt + ${cs.jasypt.version} + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + org.apache.cloudstack + cloud-server + ${project.version} + + + + + process-resources + create-schema + + java + + + + + false + true + + org.apache.cloudstack + cloud-server + + com.cloud.upgrade.DatabaseCreator + + + ${project.basedir}/utils/conf/db.properties + ${project.basedir}/utils/conf/db.properties.override + + ${basedir}/target/db/create-schema-simulator.sql + ${basedir}/target/db/templates.simulator.sql + + com.cloud.upgrade.DatabaseUpgradeChecker + --database=simulator + --rootpassword=${db.root.password} + + + + + catalina.home + ${project.basedir}/utils + + + + + + + From 7ee602beaf85643c643d878e52f77e8c9bbcabb1 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Sun, 10 Mar 2013 21:07:29 +0530 Subject: [PATCH 024/120] simulator: removing cyclic dependency from simulator The database creator caused a cyclic dependecny in the simulator which is removed with this commit. Additionally the simulator profile is now merged with developer profile and a test for server health is included --- client/pom.xml | 25 +- client/tomcatconf/componentContext.xml.in | 418 +++++++++++++--------- pom.xml | 230 ++++-------- 3 files changed, 322 insertions(+), 351 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 61cda76aa2e..75650295849 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -65,16 +65,6 @@ cloud-plugin-network-nvp ${project.version} - - org.apache.cloudstack - cloud-plugin-syslog-alerts - ${project.version} - - - org.apache.cloudstack - cloud-plugin-snmp-alerts - ${project.version} - org.apache.cloudstack cloud-plugin-network-ovs @@ -100,6 +90,11 @@ cloud-plugin-hypervisor-baremetal ${project.version} + + org.apache.cloudstack + cloud-plugin-hypervisor-ucs + ${project.version} + org.apache.cloudstack cloud-plugin-hypervisor-ovm @@ -224,16 +219,6 @@ cloud-plugin-hypervisor-simulator ${project.version} - - org.apache.cloudstack - cloud-plugin-hypervisor-ucs - ${project.version} - - - org.apache.cloudstack - cloud-plugin-storage-volume-default - ${project.version} - install diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index fea1d0f6157..d5714ea9f01 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -30,192 +30,286 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - + + - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - + + + + + + + + + + + + + + - - diff --git a/pom.xml b/pom.xml index 0393d0cc1a3..5e5f6245f4e 100644 --- a/pom.xml +++ b/pom.xml @@ -174,11 +174,11 @@ - - mysql - mysql-connector-java - ${cs.mysql.version} - + + mysql + mysql-connector-java + ${cs.mysql.version} + @@ -188,12 +188,12 @@ junit ${cs.junit.version} test - - - org.springframework - spring-core - ${org.springframework.version} - + + + org.springframework + spring-core + ${org.springframework.version} + org.springframework spring-context @@ -205,17 +205,17 @@ ${org.springframework.version} - org.mockito - mockito-all - 1.9.5 - test + org.mockito + mockito-all + 1.9.5 + test + + + org.springframework + spring-test + ${org.springframework.version} + test - - org.springframework - spring-test - ${org.springframework.version} - test - org.aspectj aspectjrt @@ -227,9 +227,9 @@ 1.7.1 - javax.inject - javax.inject - 1 + javax.inject + javax.inject + 1 @@ -260,7 +260,7 @@ - + @@ -390,41 +390,41 @@ ${cs.jdk.version} ${cs.jdk.version} - true - 128m - 512m - -XDignore.symbol.file=true + true + 128m + 512m + -XDignore.symbol.file=true - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - - true - true - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.7 - - - remove-old-installers - - remove-project-artifact - - - true - - - - + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + + true + true + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.7 + + + remove-old-installers + + remove-project-artifact + + + true + + + + org.apache.maven.plugins maven-dependency-plugin @@ -453,9 +453,9 @@ developer - - tools/devcloud/devcloud.cfg - + + tools/devcloud/devcloud.cfg + developer tools @@ -472,113 +472,5 @@ vmware-base - - simulator - - - deploydb-simulator - - - - - - org.codehaus.mojo - properties-maven-plugin - 1.0-alpha-2 - - - initialize - - read-project-properties - - - - ${project.basedir}/utils/conf/db.properties - ${project.basedir}/utils/conf/db.properties.override - - true - - - - - - - org.codehaus.mojo - exec-maven-plugin - 1.2.1 - - - - mysql - mysql-connector-java - ${cs.mysql.version} - - - commons-dbcp - commons-dbcp - ${cs.dbcp.version} - - - commons-pool - commons-pool - ${cs.pool.version} - - - org.jasypt - jasypt - ${cs.jasypt.version} - - - org.apache.cloudstack - cloud-utils - ${project.version} - - - org.apache.cloudstack - cloud-server - ${project.version} - - - - - process-resources - create-schema - - java - - - - - false - true - - org.apache.cloudstack - cloud-server - - com.cloud.upgrade.DatabaseCreator - - - ${project.basedir}/utils/conf/db.properties - ${project.basedir}/utils/conf/db.properties.override - - ${basedir}/target/db/create-schema-simulator.sql - ${basedir}/target/db/templates.simulator.sql - - com.cloud.upgrade.DatabaseUpgradeChecker - --database=simulator - --rootpassword=${db.root.password} - - - - - catalina.home - ${project.basedir}/utils - - - - - - - From 3075d0cf569d8adeacb74dd77b7d9f3bd6707101 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Wed, 13 Mar 2013 11:49:08 +0530 Subject: [PATCH 025/120] marvin: argparse enhancement and unit-test-xml-reporting dependency removed 1. deployAndRun will use the more modern argparse module 2. improving logging within the remoteSSHClient, moving to debug and default logging to INFO 3. removing dependance on the xmlrunner. use nose --with-xunit instead Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/TestCaseExecuteEngine.py | 13 ++---- tools/marvin/marvin/deployAndRun.py | 40 ++++++++----------- tools/marvin/marvin/remoteSSHClient.py | 9 ++--- .../sandbox/demo/simulator/simulator_setup.py | 2 +- tools/marvin/marvin/testSetupSuccess.py | 2 +- tools/marvin/pom.xml | 39 +++++++++++++++++- tools/marvin/setup.py | 5 +-- 7 files changed, 64 insertions(+), 46 deletions(-) diff --git a/tools/marvin/marvin/TestCaseExecuteEngine.py b/tools/marvin/marvin/TestCaseExecuteEngine.py index 3c34c7efdfc..57438688486 100644 --- a/tools/marvin/marvin/TestCaseExecuteEngine.py +++ b/tools/marvin/marvin/TestCaseExecuteEngine.py @@ -16,7 +16,6 @@ # under the License. import unittest -import xmlrunner import os import sys import logging @@ -27,7 +26,7 @@ def testCaseLogger(message, logger=None): logger.debug(message) class TestCaseExecuteEngine(object): - def __init__(self, testclient, config, testcaseLogFile=None, testResultLogFile=None, format="text", xmlDir="xml-reports"): + def __init__(self, testclient, config, testcaseLogFile=None, testResultLogFile=None): """ Initialize the testcase execution engine, just the basics here @var testcaseLogFile: client log file @@ -38,7 +37,6 @@ class TestCaseExecuteEngine(object): self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s") self.loader = unittest.loader.TestLoader() self.suite = None - self.format = format if testcaseLogFile is not None: self.logfile = testcaseLogFile @@ -56,9 +54,7 @@ class TestCaseExecuteEngine(object): self.testResultLogFile = fp else: self.testResultLogFile = sys.stdout - if self.format == "xml" and (xmlDir is not None): - self.xmlDir = xmlDir - + def loadTestsFromDir(self, testDirectory): """ Load the test suites from a package with multiple test files """ self.suite = self.loader.discover(testDirectory) @@ -92,7 +88,4 @@ class TestCaseExecuteEngine(object): def run(self): if self.suite: - if self.format == "text": - unittest.TextTestRunner(stream=self.testResultLogFile, verbosity=2).run(self.suite) - elif self.format == "xml": - xmlrunner.XMLTestRunner(output=self.xmlDir).run(self.suite) + unittest.TextTestRunner(stream=self.testResultLogFile, verbosity=2).run(self.suite) diff --git a/tools/marvin/marvin/deployAndRun.py b/tools/marvin/marvin/deployAndRun.py index e7b005caf68..c83065aaca9 100644 --- a/tools/marvin/marvin/deployAndRun.py +++ b/tools/marvin/marvin/deployAndRun.py @@ -17,22 +17,22 @@ import deployDataCenter import TestCaseExecuteEngine -from optparse import OptionParser -import os - +from argparse import ArgumentParser if __name__ == "__main__": - parser = OptionParser() #TODO: deprecate and use the argparse module - - parser.add_option("-c", "--config", action="store", default="./datacenterCfg", dest="config", help="the path where the json config file generated, by default is ./datacenterCfg") - parser.add_option("-d", "--directory", dest="testCaseFolder", help="the test case directory") - parser.add_option("-r", "--result", dest="result", help="test result log file") - parser.add_option("-t", "--client", dest="testcaselog", help="test case log file") - parser.add_option("-l", "--load", dest="load", action="store_true", help="only load config, do not deploy, it will only run testcase") - parser.add_option("-f", "--file", dest="module", help="run tests in the given file") - parser.add_option("-x", "--xml", dest="xmlrunner", help="use the xml runner to generate xml reports and path to store xml files") - (options, args) = parser.parse_args() - + parser = ArgumentParser() + + parser.add_argument("-d", "--directory", dest="testCaseFolder", help="the test case directory") + parser.add_argument("-f", "--file", dest="module", help="run tests in the given file") + parser.add_argument("-r", "--result", dest="result", help="test result log file", default='/tmp/t.log') + parser.add_argument("-t", "--client", dest="testcaselog", help="test case log file", default='/tmp/r.log') + parser.add_argument("-c", "--config", action="store", default="./datacenterCfg", dest="config", + help="the path where the json config file generated, by default is ./datacenterCfg") + parser.add_argument("-l", "--load", dest="load", action="store_true", + help="only load config, do not deploy, it will only run testcase") + + options = parser.parse_args() + testResultLogFile = None if options.result is not None: testResultLogFile = options.result @@ -46,12 +46,6 @@ if __name__ == "__main__": else: deploy.deploy() - fmt = "text" - xmlDir = None - if options.xmlrunner is not None: - xmlDir = options.xmlrunner - fmt = "xml" - if options.testCaseFolder is None: if options.module is None: parser.print_usage() @@ -61,15 +55,13 @@ if __name__ == "__main__": TestCaseExecuteEngine.TestCaseExecuteEngine(deploy.testClient, deploy.getCfg(), testCaseLogFile, - testResultLogFile, fmt, - xmlDir) + testResultLogFile) engine.loadTestsFromFile(options.module) engine.run() else: engine = TestCaseExecuteEngine.TestCaseExecuteEngine(deploy.testClient, deploy.getCfg(), testCaseLogFile, - testResultLogFile, - fmt, xmlDir) + testResultLogFile) engine.loadTestsFromDir(options.testCaseFolder) engine.run() diff --git a/tools/marvin/marvin/remoteSSHClient.py b/tools/marvin/marvin/remoteSSHClient.py index 95a9adab53f..4fb2f0de8f0 100644 --- a/tools/marvin/marvin/remoteSSHClient.py +++ b/tools/marvin/marvin/remoteSSHClient.py @@ -23,7 +23,7 @@ import logging from contextlib import closing class remoteSSHClient(object): - def __init__(self, host, port, user, passwd, retries = 10): + def __init__(self, host, port, user, passwd, retries = 10, log_lvl=logging.INFO): self.host = host self.port = port self.user = user @@ -32,14 +32,14 @@ class remoteSSHClient(object): self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.logger = logging.getLogger('sshClient') ch = logging.StreamHandler() - ch.setLevel(logging.DEBUG) + ch.setLevel(log_lvl) self.logger.addHandler(ch) retry_count = retries while True: try: self.ssh.connect(str(host),int(port), user, passwd) - self.logger.debug("connecting to server %s with user %s passwd %s"%(str(host), user, passwd)) + self.logger.debug("SSH connect: %s@%s with passwd %s"%(user, str(host), passwd)) except paramiko.SSHException, sshex: if retry_count == 0: raise cloudstackException.InvalidParameterException(repr(sshex)) @@ -52,7 +52,6 @@ class remoteSSHClient(object): def execute(self, command): stdin, stdout, stderr = self.ssh.exec_command(command) - self.logger.debug("sending command %s to host %s"%(command, str(self.host))) output = stdout.readlines() errors = stderr.readlines() results = [] @@ -64,7 +63,7 @@ class remoteSSHClient(object): else: for strOut in output: results.append(strOut.rstrip()) - self.logger.debug("command %s returned %s"%(command, results)) + self.logger.debug("{Cmd: %s via Host: %s} {returns: %s}"%(command, str(self.host), results)) return results def scp(self, srcFile, destPath): diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py index 0d341408aea..e4ec9b7b1b1 100644 --- a/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py +++ b/tools/marvin/marvin/sandbox/demo/simulator/simulator_setup.py @@ -41,7 +41,6 @@ def describeResources(config): z.name = 'Sandbox-%s'%(config.get('environment', 'hypervisor')) z.networktype = 'Advanced' z.guestcidraddress = '10.1.1.0/24' - z.vlan = config.get('cloudstack', 'zone.vlan') vpcprovider = provider() vpcprovider.name = 'VpcVirtualRouter' @@ -50,6 +49,7 @@ def describeResources(config): pn.name = "Sandbox-pnet" pn.traffictypes = [traffictype("Guest"), traffictype("Management"), traffictype("Public")] pn.providers.append(vpcprovider) + pn.vlan = config.get('cloudstack', 'zone.vlan') z.physical_networks.append(pn) diff --git a/tools/marvin/marvin/testSetupSuccess.py b/tools/marvin/marvin/testSetupSuccess.py index 8a0034cfa9b..319fd21c582 100644 --- a/tools/marvin/marvin/testSetupSuccess.py +++ b/tools/marvin/marvin/testSetupSuccess.py @@ -75,7 +75,7 @@ class TestSetupSuccess(cloudstackTestCase): retry = retry - 1 delay(60) #wait a minute for retry self.assertNotEqual(retry, 0, "builtIn templates not ready in zone %s"%z.name) - + @classmethod def tearDownClass(cls): pass diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index a3bd5460fd5..194d7841030 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -65,8 +65,8 @@ - package - package + install + install exec @@ -117,7 +117,42 @@ exec + + ${basedir}/marvin + /usr/local/bin/nosetests + + --with-marvin + --marvin-config + ${user.dir}/${marvin.config} + --load + -a + tags=simulator + ${basedir}/../../test/integration/smoke/test_vm_life_cycle.py + + + diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py index fea53d07f8a..f8198d7999b 100644 --- a/tools/marvin/setup.py +++ b/tools/marvin/setup.py @@ -37,7 +37,6 @@ setup(name="Marvin", install_requires=[ "mysql-connector-python", "paramiko", - "nose", - "unittest-xml-reporting>1.2" - ], + "nose" + ], ) From fe48bbebda0ff05653fc2341649e410db6bfb159 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Thu, 21 Mar 2013 15:34:26 +0530 Subject: [PATCH 026/120] moving out the vmpasswd into its own suite vm passwords are extended features that don't need to be part of the smoke suite. Signed-off-by: Prasanna Santhanam --- .../component/test_vm_passwdenabled.py | 242 ++++++++++++++++++ test/integration/smoke/test_vm_life_cycle.py | 170 ------------ tools/marvin/marvin/testSetupSuccess.py | 2 +- 3 files changed, 243 insertions(+), 171 deletions(-) create mode 100644 test/integration/component/test_vm_passwdenabled.py diff --git a/test/integration/component/test_vm_passwdenabled.py b/test/integration/component/test_vm_passwdenabled.py new file mode 100644 index 00000000000..fb881708e2f --- /dev/null +++ b/test/integration/component/test_vm_passwdenabled.py @@ -0,0 +1,242 @@ +# 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. +import marvin +from marvin.cloudstackTestCase import * +from marvin.cloudstackAPI import * +from marvin.remoteSSHClient import remoteSSHClient +from marvin.integration.lib.utils import * +from marvin.integration.lib.base import * +from marvin.integration.lib.common import * +from nose.plugins.attrib import attr + + +_multiprocess_shared_ = True +class Services: + """Test VM Life Cycle Services + """ + + def __init__(self): + self.services = { + "disk_offering":{ + "displaytext": "Small", + "name": "Small", + "disksize": 1 + }, + "account": { + "email": "test@test.com", + "firstname": "Test", + "lastname": "User", + "username": "test", + # Random characters are appended in create account to + # ensure unique username generated each time + "password": "password", + }, + "service_offerings": + { + "small": + { + # Small service offering ID to for change VM + # service offering from medium to small + "name": "Small Instance", + "displaytext": "Small Instance", + "cpunumber": 1, + "cpuspeed": 100, + "memory": 256, + }, + }, + "template": { + "displaytext": "Cent OS Template", + "name": "Cent OS Template", + "passwordenabled": True, + }, + "sleep": 60, + "timeout": 10, + "ostype": 'CentOS 5.3 (64-bit)', + # CentOS 5.3 (64-bit) + } + +@unittest.skip("Additional test") +class TestVMPasswordEnabled(cloudstackTestCase): + + @classmethod + def setUpClass(cls): + cls.api_client = super( + TestVMPasswordEnabled, + cls + ).getClsTestClient().getApiClient() + cls.services = Services().services + + # Get Zone, Domain and templates + domain = get_domain(cls.api_client, cls.services) + zone = get_zone(cls.api_client, cls.services) + template = get_template( + cls.api_client, + zone.id, + cls.services["ostype"] + ) + # Set Zones and disk offerings + cls.services["small"]["zoneid"] = zone.id + cls.services["small"]["template"] = template.id + + # Create VMs, NAT Rules etc + cls.account = Account.create( + cls.api_client, + cls.services["account"], + domainid=domain.id + ) + + cls.small_offering = ServiceOffering.create( + cls.api_client, + cls.services["service_offerings"]["small"] + ) + + cls.virtual_machine = VirtualMachine.create( + cls.api_client, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.small_offering.id, + mode=cls.services["mode"] + ) + #Stop virtual machine + cls.virtual_machine.stop(cls.api_client) + + # Poll listVM to ensure VM is stopped properly + timeout = cls.services["timeout"] + while True: + time.sleep(cls.services["sleep"]) + + # Ensure that VM is in stopped state + list_vm_response = list_virtual_machines( + cls.api_client, + id=cls.virtual_machine.id + ) + + if isinstance(list_vm_response, list): + + vm = list_vm_response[0] + if vm.state == 'Stopped': + break + + if timeout == 0: + raise Exception( + "Failed to stop VM (ID: %s) in change service offering" % + vm.id) + + timeout = timeout - 1 + + list_volume = list_volumes( + cls.api_client, + virtualmachineid=cls.virtual_machine.id, + type='ROOT', + listall=True + ) + if isinstance(list_volume, list): + cls.volume = list_volume[0] + else: + raise Exception( + "Exception: Unable to find root volume foe VM: %s" % + cls.virtual_machine.id) + + cls.services["template"]["ostype"] = cls.services["ostype"] + #Create templates for Edit, Delete & update permissions testcases + cls.pw_enabled_template = Template.create( + cls.api_client, + cls.services["template"], + cls.volume.id, + account=cls.account.account.name, + domainid=cls.account.account.domainid + ) + # Delete the VM - No longer needed + cls.virtual_machine.delete(cls.api_client) + cls.services["small"]["template"] = cls.pw_enabled_template.id + + cls.vm = VirtualMachine.create( + cls.api_client, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.small_offering.id, + mode=cls.services["mode"] + ) + cls._cleanup = [ + cls.small_offering, + cls.pw_enabled_template, + cls.account + ] + + @classmethod + def tearDownClass(cls): + # Cleanup VMs, templates etc. + cleanup_resources(cls.api_client, cls._cleanup) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() + self.cleanup = [] + + def tearDown(self): + #Clean up, terminate the created instances + cleanup_resources(self.apiclient, self.cleanup) + return + + @attr(tags = ["advanced", "advancedns", "smoke", "basic", "sg"]) + def test_11_get_vm_password(self): + """Test get VM password for password enabled template""" + + # Validate the following + # 1. Create an account + # 2. Deploy VM with default service offering and "password enabled" + # template. Vm should be in running state. + # 3. Stop VM deployed in step 2 + # 4. Reset VM password. SSH with new password should be successful + + self.debug("Stopping VM: %s" % self.vm.name) + self.vm.stop(self.apiclient) + + # Sleep to ensure VM is stopped properly + time.sleep(self.services["sleep"]) + + self.debug("Resetting VM password for VM: %s" % self.vm.name) + password = self.vm.resetPassword(self.apiclient) + self.debug("Password reset to: %s" % password) + + self.debug("Starting VM to verify new password..") + self.vm.start(self.apiclient) + self.debug("VM - %s stated!" % self.vm.name) + + vms = VirtualMachine.list(self.apiclient, id=self.vm.id, listall=True) + self.assertEqual( + isinstance(vms, list), + True, + "List VMs should retun valid response for VM: %s" % self.vm.name + ) + virtual_machine = vms[0] + + self.assertEqual( + virtual_machine.state, + "Running", + "VM state should be running" + ) + try: + self.debug("SSHing into VM: %s" % self.vm.ssh_ip) + self.vm.password = password + ssh = self.vm.get_ssh_client() + except Exception as e: + self.fail("SSH into VM: %s failed" % self.vm.ssh_ip) + return diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 0a5fbad8376..719984d4fd9 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -998,174 +998,4 @@ class TestVMLifeCycle(cloudstackTestCase): ) return -@unittest.skip("Additional test") -class TestVMPasswordEnabled(cloudstackTestCase): - @classmethod - def setUpClass(cls): - cls.api_client = super( - TestVMPasswordEnabled, - cls - ).getClsTestClient().getApiClient() - cls.services = Services().services - - # Get Zone, Domain and templates - domain = get_domain(cls.api_client, cls.services) - zone = get_zone(cls.api_client, cls.services) - template = get_template( - cls.api_client, - zone.id, - cls.services["ostype"] - ) - # Set Zones and disk offerings - cls.services["small"]["zoneid"] = zone.id - cls.services["small"]["template"] = template.id - - # Create VMs, NAT Rules etc - cls.account = Account.create( - cls.api_client, - cls.services["account"], - domainid=domain.id - ) - - cls.small_offering = ServiceOffering.create( - cls.api_client, - cls.services["service_offerings"]["small"] - ) - - cls.virtual_machine = VirtualMachine.create( - cls.api_client, - cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, - serviceofferingid=cls.small_offering.id, - mode=cls.services["mode"] - ) - #Stop virtual machine - cls.virtual_machine.stop(cls.api_client) - - # Poll listVM to ensure VM is stopped properly - timeout = cls.services["timeout"] - while True: - time.sleep(cls.services["sleep"]) - - # Ensure that VM is in stopped state - list_vm_response = list_virtual_machines( - cls.api_client, - id=cls.virtual_machine.id - ) - - if isinstance(list_vm_response, list): - - vm = list_vm_response[0] - if vm.state == 'Stopped': - break - - if timeout == 0: - raise Exception( - "Failed to stop VM (ID: %s) in change service offering" % - vm.id) - - timeout = timeout - 1 - - list_volume = list_volumes( - cls.api_client, - virtualmachineid=cls.virtual_machine.id, - type='ROOT', - listall=True - ) - if isinstance(list_volume, list): - cls.volume = list_volume[0] - else: - raise Exception( - "Exception: Unable to find root volume foe VM: %s" % - cls.virtual_machine.id) - - cls.services["template"]["ostype"] = cls.services["ostype"] - #Create templates for Edit, Delete & update permissions testcases - cls.pw_enabled_template = Template.create( - cls.api_client, - cls.services["template"], - cls.volume.id, - account=cls.account.account.name, - domainid=cls.account.account.domainid - ) - # Delete the VM - No longer needed - cls.virtual_machine.delete(cls.api_client) - cls.services["small"]["template"] = cls.pw_enabled_template.id - - cls.vm = VirtualMachine.create( - cls.api_client, - cls.services["small"], - accountid=cls.account.account.name, - domainid=cls.account.account.domainid, - serviceofferingid=cls.small_offering.id, - mode=cls.services["mode"] - ) - cls._cleanup = [ - cls.small_offering, - cls.pw_enabled_template, - cls.account - ] - - @classmethod - def tearDownClass(cls): - # Cleanup VMs, templates etc. - cleanup_resources(cls.api_client, cls._cleanup) - return - - def setUp(self): - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - self.cleanup = [] - - def tearDown(self): - #Clean up, terminate the created instances - cleanup_resources(self.apiclient, self.cleanup) - return - - @attr(tags = ["advanced", "advancedns", "smoke", "basic", "sg"]) - def test_11_get_vm_password(self): - """Test get VM password for password enabled template""" - - # Validate the following - # 1. Create an account - # 2. Deploy VM with default service offering and "password enabled" - # template. Vm should be in running state. - # 3. Stop VM deployed in step 2 - # 4. Reset VM password. SSH with new password should be successful - - self.debug("Stopping VM: %s" % self.vm.name) - self.vm.stop(self.apiclient) - - # Sleep to ensure VM is stopped properly - time.sleep(self.services["sleep"]) - - self.debug("Resetting VM password for VM: %s" % self.vm.name) - password = self.vm.resetPassword(self.apiclient) - self.debug("Password reset to: %s" % password) - - self.debug("Starting VM to verify new password..") - self.vm.start(self.apiclient) - self.debug("VM - %s stated!" % self.vm.name) - - vms = VirtualMachine.list(self.apiclient, id=self.vm.id, listall=True) - self.assertEqual( - isinstance(vms, list), - True, - "List VMs should retun valid response for VM: %s" % self.vm.name - ) - virtual_machine = vms[0] - - self.assertEqual( - virtual_machine.state, - "Running", - "VM state should be running" - ) - try: - self.debug("SSHing into VM: %s" % self.vm.ssh_ip) - self.vm.password = password - ssh = self.vm.get_ssh_client() - except Exception as e: - self.fail("SSH into VM: %s failed" % self.vm.ssh_ip) - return diff --git a/tools/marvin/marvin/testSetupSuccess.py b/tools/marvin/marvin/testSetupSuccess.py index 319fd21c582..b1721c40d3b 100644 --- a/tools/marvin/marvin/testSetupSuccess.py +++ b/tools/marvin/marvin/testSetupSuccess.py @@ -33,7 +33,7 @@ class TestSetupSuccess(cloudstackTestCase): zones = listZones.listZonesCmd() cls.zones_list = cls.apiClient.listZones(zones) - cls.retry = 50 + cls.retry = 2 def test_systemVmReady(self): """ From 2e2046fe389b79b2b105ef40b792263cee831929 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Thu, 21 Mar 2013 20:02:23 +0530 Subject: [PATCH 027/120] marvin changes to do an pre-integration and integration test Introducing the simulator spring context - simulatorComponentContext.xml.in. This separates the simulator beans so that production deployments don't have the simulator in them. Context is enabled with -Dsimulator as part of the developer profile. Also adding config files - Simulator Config for advanced zone and basic zone deployments under setup/dev. Signed-off-by: Prasanna Santhanam --- client/pom.xml | 67 +++-- client/tomcatconf/componentContext.xml.in | 9 - .../simulatorComponentContext.xml.in | 270 ++++++++++++++++++ setup/db/templates.simulator.sql | 2 +- .../simulator.cfg => setup/dev/advanced.cfg | 167 ++++++----- setup/dev/basic.cfg | 178 ++++++++++++ test/integration/smoke/test_vm_life_cycle.py | 14 +- tools/marvin/marvin/testSetupSuccess.py | 5 + tools/marvin/pom.xml | 49 ++-- 9 files changed, 626 insertions(+), 135 deletions(-) create mode 100644 client/tomcatconf/simulatorComponentContext.xml.in rename tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg => setup/dev/advanced.cfg (54%) create mode 100644 setup/dev/basic.cfg diff --git a/client/pom.xml b/client/pom.xml index 75650295849..91dfece3952 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -218,6 +218,10 @@ org.apache.cloudstack cloud-plugin-hypervisor-simulator ${project.version} + + org.apache.cloudstack + cloud-plugin-storage-volume-default + ${project.version} @@ -376,22 +380,38 @@ - - process-nonoss - process-resources - - run - - - - test - - - - + + process-nonoss + process-resources + + run + + + + test + + + + + + process-simulator-context + process-resources + + run + + + + test + + + + process-nonoss-spring-context process-resources @@ -480,6 +500,21 @@ + + developer + + + simulator + + + + + org.apache.cloudstack + cloud-plugin-hypervisor-simulator + ${project.version} + + + netapp diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index d5714ea9f01..584be9787e8 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -203,11 +203,6 @@ - - - - - @@ -304,10 +299,6 @@ - - - - diff --git a/client/tomcatconf/simulatorComponentContext.xml.in b/client/tomcatconf/simulatorComponentContext.xml.in new file mode 100644 index 00000000000..d501ca1d10e --- /dev/null +++ b/client/tomcatconf/simulatorComponentContext.xml.in @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup/db/templates.simulator.sql b/setup/db/templates.simulator.sql index 13246233c16..a8044504487 100755 --- a/setup/db/templates.simulator.sql +++ b/setup/db/templates.simulator.sql @@ -19,4 +19,4 @@ INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, image_data_store_id) VALUES (10, UUID(), 'simulator-domR', 'SystemVM Template (simulator)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/routing/debian/latest/systemvm.vhd.bz2', '', 0, 'SystemVM Template (simulator)', 'VHD', 15, 0, 1, 'Simulator', 1); INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, image_data_store_id) - VALUES (11, UUID(), 'simulator-Centos', 'CentOS 5.3(64-bit) no GUI (Simulator)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/centos53-x86_64/latest/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', '', 0, 'CentOS 5.3(64-bit) no GUI (Simulator)', 'VHD', 11, 1, 1, 'Simulator', 1); + VALUES (11, UUID(), 'simulator-Centos', 'CentOS 5.3(64-bit) no GUI (Simulator)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://nfs1.lab.vmops.com/templates/centos53-x86_64/latest/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', '', 0, 'CentOS 5.3(64-bit) no GUI (Simulator)', 'VHD', 12, 1, 1, 'Simulator', 1); diff --git a/tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg b/setup/dev/advanced.cfg similarity index 54% rename from tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg rename to setup/dev/advanced.cfg index ca794605540..c031c2a4f84 100644 --- a/tools/marvin/marvin/sandbox/demo/simulator/simulator.cfg +++ b/setup/dev/advanced.cfg @@ -5,9 +5,9 @@ # 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 @@ -15,181 +15,180 @@ # specific language governing permissions and limitations # under the License. - { "zones": [ { - "name": "Sandbox-simulator", - "guestcidraddress": "10.1.1.0/24", - "dns1": "10.147.28.6", - "vlan": "100-200", + "name": "Sandbox-simulator", + "guestcidraddress": "10.1.1.0/24", + "dns1": "10.147.28.6", "physical_networks": [ { - "broadcastdomainrange": "Zone", - "name": "Sandbox-pnet", + "broadcastdomainrange": "Zone", + "vlan": "100-200", + "name": "Sandbox-pnet", "traffictypes": [ { "typ": "Guest" - }, + }, { "typ": "Management" - }, + }, { "typ": "Public" } - ], + ], "providers": [ { - "broadcastdomainrange": "ZONE", + "broadcastdomainrange": "ZONE", "name": "VirtualRouter" - }, + }, { - "broadcastdomainrange": "ZONE", + "broadcastdomainrange": "ZONE", "name": "VpcVirtualRouter" } ] } - ], + ], "ipranges": [ { - "startip": "192.168.2.2", - "endip": "192.168.2.200", - "netmask": "255.255.255.0", - "vlan": "50", + "startip": "192.168.2.2", + "endip": "192.168.2.200", + "netmask": "255.255.255.0", + "vlan": "50", "gateway": "192.168.2.1" } - ], - "networktype": "Advanced", + ], + "networktype": "Advanced", "pods": [ { - "endip": "172.16.15.200", - "name": "POD0", - "startip": "172.16.15.2", - "netmask": "255.255.255.0", + "endip": "172.16.15.200", + "name": "POD0", + "startip": "172.16.15.2", + "netmask": "255.255.255.0", "clusters": [ { - "clustername": "C0", - "hypervisor": "simulator", + "clustername": "C0", + "hypervisor": "simulator", "hosts": [ { - "username": "root", - "url": "http://sim/c0/h0", + "username": "root", + "url": "http://sim/c0/h0", "password": "password" - }, + }, { - "username": "root", - "url": "http://sim/c0/h1", + "username": "root", + "url": "http://sim/c0/h1", "password": "password" } - ], - "clustertype": "CloudManaged", + ], + "clustertype": "CloudManaged", "primaryStorages": [ { - "url": "nfs://10.147.28.6:/export/home/sandbox/primary", + "url": "nfs://10.147.28.6:/export/home/sandbox/primary", "name": "PS0" } ] } - ], + ], "gateway": "172.16.15.1" } - ], - "internaldns1": "10.147.28.6", + ], + "internaldns1": "10.147.28.6", "secondaryStorages": [ { "url": "nfs://10.147.28.6:/export/home/sandbox/secondary" } ] } - ], + ], "dbSvr": { - "dbSvr": "localhost", - "passwd": "cloud", - "db": "cloud", - "port": 3306, + "dbSvr": "localhost", + "passwd": "cloud", + "db": "cloud", + "port": 3306, "user": "cloud" - }, + }, "logger": [ { - "name": "TestClient", + "name": "TestClient", "file": "/tmp/testclient.log" - }, + }, { - "name": "TestCase", + "name": "TestCase", "file": "/tmp/testcase.log" } - ], + ], "globalConfig": [ { - "name": "network.gc.wait", + "name": "network.gc.wait", "value": "60" - }, + }, { - "name": "storage.cleanup.interval", + "name": "storage.cleanup.interval", "value": "300" - }, + }, { - "name": "vm.op.wait.interval", + "name": "vm.op.wait.interval", "value": "5" - }, + }, { - "name": "default.page.size", + "name": "default.page.size", "value": "10000" - }, + }, { - "name": "network.gc.interval", + "name": "network.gc.interval", "value": "60" - }, + }, { - "name": "instance.name", + "name": "instance.name", "value": "QA" - }, + }, { - "name": "workers", + "name": "workers", "value": "10" - }, + }, { - "name": "account.cleanup.interval", + "name": "account.cleanup.interval", "value": "600" - }, + }, { - "name": "guest.domain.suffix", + "name": "guest.domain.suffix", "value": "sandbox.simulator" - }, + }, { - "name": "expunge.delay", + "name": "expunge.delay", "value": "60" - }, + }, { - "name": "vm.allocation.algorithm", + "name": "vm.allocation.algorithm", "value": "random" - }, + }, { - "name": "expunge.interval", + "name": "expunge.interval", "value": "60" - }, + }, { - "name": "expunge.workers", + "name": "expunge.workers", "value": "3" - }, + }, { - "name": "check.pod.cidrs", + "name": "check.pod.cidrs", "value": "true" - }, + }, { - "name": "secstorage.allowed.internal.sites", + "name": "secstorage.allowed.internal.sites", "value": "10.147.28.0/24" - }, + }, { - "name": "direct.agent.load.size", + "name": "direct.agent.load.size", "value": "1000" } - ], + ], "mgtSvr": [ { - "mgtSvrIp": "localhost", - "passwd": "password", - "user": "root", + "mgtSvrIp": "localhost", + "passwd": "password", + "user": "root", "port": 8096 } ] diff --git a/setup/dev/basic.cfg b/setup/dev/basic.cfg new file mode 100644 index 00000000000..fb99b8b5498 --- /dev/null +++ b/setup/dev/basic.cfg @@ -0,0 +1,178 @@ +# 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. + + +{ + "zones": [ + { + "name": "Sandbox-simulator", + "dns1": "8.8.8.8", + "physical_networks": [ + { + "broadcastdomainrange": "Zone", + "name": "Sandbox-pnet", + "traffictypes": [ + { + "typ": "Guest" + }, + { + "typ": "Management" + } + ], + "providers": [ + { + "broadcastdomainrange": "ZONE", + "name": "VirtualRouter" + }, + { + "broadcastdomainrange": "Pod", + "name": "SecurityGroupProvider" + } + ] + } + ], + "securitygroupenabled": "true", + "networktype": "Basic", + "pods": [ + { + "endip": "172.16.15.254", + "name": "POD0", + "startip": "172.16.15.2", + "guestIpRanges": [ + { + "startip": "60.147.41.2", + "endip": "60.147.41.254", + "netmask": "255.255.255.0", + "gateway": "60.147.40.1" + } + ], + "netmask": "255.255.255.0", + "clusters": [ + { + "clustername": "C0", + "hypervisor": "simulator", + "hosts": [ + { + "username": "root", + "url": "http://sim/c0/h0", + "password": "password" + } + ], + "clustertype": "CloudManaged", + "primaryStorages": [ + { + "url": "nfs://nfsstor:/export/home/sandbox/primary", + "name": "PS0" + } + ] + } + ], + "gateway": "172.16.15.1" + } + ], + "internaldns1": "8.8.8.8", + "secondaryStorages": [ + { + "url": "nfs://nfsstor:/export/home/sandbox/secondary" + } + ] + } + ], + "dbSvr": { + "dbSvr": "localhost", + "passwd": "cloud", + "db": "cloud", + "port": 3306, + "user": "cloud" + }, + "logger": [ + { + "name": "TestClient", + "file": "/var/log/testclient.log" + }, + { + "name": "TestCase", + "file": "/var/log/testcase.log" + } + ], + "globalConfig": [ + { + "name": "storage.cleanup.interval", + "value": "300" + }, + { + "name": "direct.agent.load.size", + "value": "1000" + }, + { + "name": "default.page.size", + "value": "10000" + }, + { + "name": "instance.name", + "value": "QA" + }, + { + "name": "workers", + "value": "10" + }, + { + "name": "vm.op.wait.interval", + "value": "5" + }, + { + "name": "account.cleanup.interval", + "value": "600" + }, + { + "name": "guest.domain.suffix", + "value": "sandbox.simulator" + }, + { + "name": "expunge.delay", + "value": "60" + }, + { + "name": "vm.allocation.algorithm", + "value": "random" + }, + { + "name": "expunge.interval", + "value": "60" + }, + { + "name": "expunge.workers", + "value": "3" + }, + { + "name": "secstorage.allowed.internal.sites", + "value": "172.16.15.0/24" + }, + { + "name": "check.pod.cidrs", + "value": "true" + } + ], + "mgtSvr": [ + { + "mgtSvrIp": "localhost", + "passwd": "password", + "user": "root", + "port": 8096 + } + ] +} diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 719984d4fd9..143fea71975 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -20,7 +20,6 @@ import marvin from marvin.cloudstackTestCase import * from marvin.cloudstackAPI import * -from marvin.remoteSSHClient import remoteSSHClient from marvin.integration.lib.utils import * from marvin.integration.lib.base import * from marvin.integration.lib.common import * @@ -177,7 +176,7 @@ class TestDeployVM(cloudstackTestCase): self.account ] - @attr(tags = ["devcloud", "advanced", "advancedns", "smoke", "basic", "sg"]) + @attr(tags = ["simulator", "devcloud", "advanced", "advancedns", "smoke", "basic", "sg"]) def test_deploy_vm(self): """Test Deploy Virtual Machine """ @@ -231,6 +230,13 @@ class TestDeployVM(cloudstackTestCase): self.virtual_machine.name, "Check virtual machine name in listVirtualMachines" ) + + self.assertEqual( + vm_response.state, + 'Running', + msg="VM is not in Running state" + ) + return def tearDown(self): @@ -996,6 +1002,4 @@ class TestVMLifeCycle(cloudstackTestCase): False, "Check if ISO is detached from virtual machine" ) - return - - + return \ No newline at end of file diff --git a/tools/marvin/marvin/testSetupSuccess.py b/tools/marvin/marvin/testSetupSuccess.py index b1721c40d3b..dcd15e674eb 100644 --- a/tools/marvin/marvin/testSetupSuccess.py +++ b/tools/marvin/marvin/testSetupSuccess.py @@ -76,6 +76,11 @@ class TestSetupSuccess(cloudstackTestCase): delay(60) #wait a minute for retry self.assertNotEqual(retry, 0, "builtIn templates not ready in zone %s"%z.name) + def test_deployVmWithBuiltIn(self): + """ + Deploys a VM with the built-in CentOS template + """ + @classmethod def tearDownClass(cls): pass diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index 194d7841030..ff5176fbcb6 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -48,8 +48,8 @@ 1.2.1 - compile - compile + generate-sources + generate-sources exec @@ -80,7 +80,6 @@ - @@ -88,7 +87,9 @@ marvin - marvin.config + + marvin.config + @@ -96,24 +97,32 @@ org.codehaus.mojo exec-maven-plugin 1.2.1 - - ${basedir}/marvin - python - - deployAndRun.py - -c - ${user.dir}/${marvin.config} - -t - /tmp/t.log - -r - /tmp/r.log - -f - ${basedir}/marvin/testSetupSuccess.py - - - test + pre-integration-test + pre-integration-test + + exec + + + ${basedir}/marvin + python + + deployAndRun.py + -c + ${user.dir}/${marvin.config} + -t + /tmp/t.log + -r + /tmp/r.log + -f + ${basedir}/marvin/testSetupSuccess.py + + + + + integration-test + integration-test exec From 9c755e11e5067bfbc14581a3a3fac9b5b7fd21a1 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Sat, 23 Mar 2013 20:25:21 +0530 Subject: [PATCH 028/120] marvin-nose: include the plugin as part of marvin install No need to register the plugin seperately now. The installer will register with nose's entry_point automatically. Signed-off-by: Prasanna Santhanam --- tools/marvin/marvin/setup.py | 52 -------------------------------- tools/marvin/setup.py | 58 ++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 74 deletions(-) delete mode 100644 tools/marvin/marvin/setup.py diff --git a/tools/marvin/marvin/setup.py b/tools/marvin/marvin/setup.py deleted file mode 100644 index 07ff5b5a577..00000000000 --- a/tools/marvin/marvin/setup.py +++ /dev/null @@ -1,52 +0,0 @@ -# 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. - -import os -try: - from setuptools import setup, find_packages -except ImportError: - from distribute_setup import use_setuptools - use_setuptools() - from setuptools import setup, find_packages - - -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read().strip() - -VERSION = '0.1.0' - -setup( - name = "marvin-nose", - version = VERSION, - author = "Prasanna Santhanam", - author_email = "Prasanna.Santhanam@citrix.com", - description = "Run tests written using CloudStack's Marvin testclient", - license = 'ASL 2.0', - classifiers = [ - "Intended Audience :: Developers", - "Topic :: Software Development :: Testing", - "Programming Language :: Python", - ], - - py_modules = ['marvinPlugin'], - zip_safe = False, - - entry_points = { - 'nose.plugins': ['marvinPlugin = marvinPlugin:MarvinPlugin'] - }, - install_requires = ['nose', 'marvin'], -) diff --git a/tools/marvin/setup.py b/tools/marvin/setup.py index f8198d7999b..ab5eb6f7c24 100644 --- a/tools/marvin/setup.py +++ b/tools/marvin/setup.py @@ -16,27 +16,41 @@ # specific language governing permissions and limitations # under the License. -from setuptools import setup -from sys import version -import sys +try: + from setuptools import setup, find_packages +except ImportError: + from distribute_setup import use_setuptools + use_setuptools() + from setuptools import setup, find_packages + +VERSION = '0.1.0' + +import os +def read(fname): + return open(os.path.join(os.path.dirname(__file__), fname)).read().strip() setup(name="Marvin", - version="0.1.0", - description="Marvin - Python client for testing cloudstack", - author="Edison Su", - author_email="Edison.Su@citrix.com", - maintainer="Prasanna Santhanam", - maintainer_email="Prasanna.Santhanam@citrix.com", - long_description="Marvin is the cloudstack testclient written around the python unittest framework", - platforms=("Any",), - url="http://jenkins.cloudstack.org:8080/job/marvin", - packages=["marvin", "marvin.cloudstackAPI", "marvin.integration", - "marvin.integration.lib", "marvin.sandbox", - "marvin.sandbox.advanced", "marvin.sandbox.basic"], - license="LICENSE.txt", - install_requires=[ - "mysql-connector-python", - "paramiko", - "nose" - ], - ) + version=VERSION, + description="Marvin - Python client for Apache CloudStack", + author="Edison Su", + author_email="Edison.Su@citrix.com", + maintainer="Prasanna Santhanam", + maintainer_email="Prasanna.Santhanam@citrix.com", + long_description="Marvin is the Apache CloudStack python client written around the unittest framework", + platforms=("Any",), + url="https://builds.apache.org/view/CloudStack/job/cloudstack-marvin/", + packages=["marvin", "marvin.cloudstackAPI", "marvin.integration", + "marvin.integration.lib", "marvin.sandbox", + "marvin.sandbox.advanced", "marvin.sandbox.basic"], + license="LICENSE.txt", + install_requires=[ + "mysql-connector-python", + "paramiko", + "nose" + ], + py_modules=['marvin.marvinPlugin'], + zip_safe=False, + entry_points={ + 'nose.plugins': ['marvinPlugin = marvin.marvinPlugin:MarvinPlugin'] + }, +) From d4dc2649173f17d230b1d4332b3e0d9466fb3f20 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Mon, 25 Mar 2013 18:36:37 +0530 Subject: [PATCH 029/120] simulator+marvin: include a router test Added a test that will ensure the advanced router comes up in the account belonging to the deployed VM. It should come up with the publicip, guestip and linklocalip. Signed-off-by: Prasanna Santhanam --- test/integration/smoke/test_vm_life_cycle.py | 137 +++++++++++-------- tools/marvin/pom.xml | 22 --- 2 files changed, 79 insertions(+), 80 deletions(-) diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index 143fea71975..d9571f66833 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -129,72 +129,79 @@ class Services: class TestDeployVM(cloudstackTestCase): - def setUp(self): - - self.apiclient = self.testClient.getApiClient() - self.dbclient = self.testClient.getDbConnection() - self.services = Services().services + @classmethod + def setUpClass(cls): + cls.services = Services().services + cls.apiclient = super(TestDeployVM, cls).getClsTestClient().getApiClient() # Get Zone, Domain and templates - domain = get_domain(self.apiclient, self.services) - zone = get_zone(self.apiclient, self.services) - self.services['mode'] = zone.networktype + domain = get_domain(cls.apiclient, cls.services) + zone = get_zone(cls.apiclient, cls.services) + cls.services['mode'] = zone.networktype - #if local storage is enabled, alter the offerings to use localstorage + #If local storage is enabled, alter the offerings to use localstorage #this step is needed for devcloud if zone.localstorageenabled == True: - self.services["service_offerings"]["tiny"]["storagetype"] = 'local' - self.services["service_offerings"]["small"]["storagetype"] = 'local' - self.services["service_offerings"]["medium"]["storagetype"] = 'local' + cls.services["service_offerings"]["tiny"]["storagetype"] = 'local' + cls.services["service_offerings"]["small"]["storagetype"] = 'local' + cls.services["service_offerings"]["medium"]["storagetype"] = 'local' template = get_template( - self.apiclient, - zone.id, - self.services["ostype"] - ) + cls.apiclient, + zone.id, + cls.services["ostype"] + ) # Set Zones and disk offerings - self.services["small"]["zoneid"] = zone.id - self.services["small"]["template"] = template.id + cls.services["small"]["zoneid"] = zone.id + cls.services["small"]["template"] = template.id - self.services["medium"]["zoneid"] = zone.id - self.services["medium"]["template"] = template.id - self.services["iso"]["zoneid"] = zone.id + cls.services["medium"]["zoneid"] = zone.id + cls.services["medium"]["template"] = template.id + cls.services["iso"]["zoneid"] = zone.id - # Create Account, VMs, NAT Rules etc - self.account = Account.create( - self.apiclient, - self.services["account"], - domainid=domain.id - ) + cls.account = Account.create( + cls.apiclient, + cls.services["account"], + domainid=domain.id + ) + + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.services["service_offerings"]["tiny"] + ) + + cls.virtual_machine = VirtualMachine.create( + cls.apiclient, + cls.services["small"], + accountid=cls.account.account.name, + domainid=cls.account.account.domainid, + serviceofferingid=cls.service_offering.id, + mode=cls.services['mode'] + ) + + cls.cleanup = [ + cls.service_offering, + cls.account + ] + + @classmethod + def tearDownClass(cls): + try: + cleanup_resources(cls.apiclient, cls.cleanup) + except Exception as e: + cls.debug("Warning! Exception in tearDown: %s" % e) + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.dbclient = self.testClient.getDbConnection() - self.service_offering = ServiceOffering.create( - self.apiclient, - self.services["service_offerings"]["tiny"] - ) - # Cleanup - self.cleanup = [ - self.service_offering, - self.account - ] @attr(tags = ["simulator", "devcloud", "advanced", "advancedns", "smoke", "basic", "sg"]) def test_deploy_vm(self): """Test Deploy Virtual Machine """ - # Validate the following: # 1. Virtual Machine is accessible via SSH # 2. listVirtualMachines returns accurate information - # 3. The Cloud Database contains the valid information - - self.virtual_machine = VirtualMachine.create( - self.apiclient, - self.services["small"], - accountid=self.account.account.name, - domainid=self.account.account.domainid, - serviceofferingid=self.service_offering.id, - mode=self.services['mode'] - ) - list_vm_response = list_virtual_machines( self.apiclient, id=self.virtual_machine.id @@ -204,46 +211,60 @@ class TestDeployVM(cloudstackTestCase): "Verify listVirtualMachines response for virtual machine: %s" \ % self.virtual_machine.id ) - self.assertEqual( isinstance(list_vm_response, list), True, "Check list response returns a valid list" ) - self.assertNotEqual( len(list_vm_response), 0, "Check VM available in List Virtual Machines" ) vm_response = list_vm_response[0] - self.assertEqual( vm_response.id, self.virtual_machine.id, "Check virtual machine id in listVirtualMachines" ) - self.assertEqual( vm_response.name, self.virtual_machine.name, "Check virtual machine name in listVirtualMachines" ) - self.assertEqual( vm_response.state, 'Running', msg="VM is not in Running state" ) - return + + @attr(tags = ["simulator", "advanced"]) + def test_advZoneVirtualRouter(self): + """ + Test advanced zone virtual router + 1. Is Running + 2. is in the account the VM was deployed in + 3. Has a linklocalip, publicip and a guestip + @return: + """ + routers = list_routers(self.apiclient, account=self.account.account.name) + self.assertTrue(len(routers) > 0, msg = "No virtual router found") + router = routers[0] + + self.assertEqual(router.state, 'Running', msg="Router is not in running state") + self.assertEqual(router.account, self.account.account.name, msg="Router does not belong to the account") + + #Has linklocal, public and guest ips + self.assertIsNotNone(router.linklocalip, msg="Router has no linklocal ip") + self.assertIsNotNone(router.publicip, msg="Router has no public ip") + self.assertIsNotNone(router.guestipaddress, msg="Router has no guest ip") + def tearDown(self): - try: - cleanup_resources(self.apiclient, self.cleanup) - except Exception as e: - self.debug("Warning! Exception in tearDown: %s" % e) + pass + class TestVMLifeCycle(cloudstackTestCase): diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index ff5176fbcb6..4f012eedf08 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -140,28 +140,6 @@ - From 5d67c98e5b7b763fde5ea87850e9cd7bafd2a4e1 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 26 Mar 2013 18:29:23 +0530 Subject: [PATCH 030/120] marvin+apidiscovery: Extend API discovery plugin API discovery plugin will return embedded entities for marvin to discovery and generate it's API classes. Signed-off-by: Prasanna Santhanam --- client/pom.xml | 5 - .../api/response/ApiDiscoveryResponse.java | 4 + .../api/response/ApiResponseResponse.java | 15 +- .../discovery/ApiDiscoveryServiceImpl.java | 167 ++++++++++-------- .../api/response/ApiResponseSerializer.java | 32 ++-- .../response/EmptyFieldExclusionStrategy.java | 40 +++++ test/integration/smoke/test_vm_life_cycle.py | 17 +- tools/marvin/marvin/cloudstackTestClient.py | 15 +- tools/marvin/marvin/codegenerator.py | 96 +++++++++- tools/marvin/marvin/marvinPlugin.py | 14 ++ 10 files changed, 295 insertions(+), 110 deletions(-) create mode 100644 server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java diff --git a/client/pom.xml b/client/pom.xml index 91dfece3952..35588aa2c93 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -90,11 +90,6 @@ cloud-plugin-hypervisor-baremetal ${project.version} - - org.apache.cloudstack - cloud-plugin-hypervisor-ucs - ${project.version} - org.apache.cloudstack cloud-plugin-hypervisor-ovm diff --git a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java index 77484f0f7e7..ce7eb498be9 100644 --- a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiDiscoveryResponse.java @@ -47,6 +47,9 @@ public class ApiDiscoveryResponse extends BaseResponse { @SerializedName(ApiConstants.RESPONSE) @Param(description="api response fields", responseObject = ApiResponseResponse.class) private Set apiResponse; + @SerializedName(ApiConstants.TYPE) @Param(description="response field type") + private String type; + public ApiDiscoveryResponse(){ params = new HashSet(); apiResponse = new HashSet(); @@ -81,6 +84,7 @@ public class ApiDiscoveryResponse extends BaseResponse { this.isAsync = isAsync; } + public boolean getAsync() { return isAsync; } diff --git a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java index b96295e1290..1433879a6ce 100644 --- a/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/api/response/ApiResponseResponse.java @@ -16,11 +16,14 @@ // under the License. package org.apache.cloudstack.api.response; -import org.apache.cloudstack.api.ApiConstants; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; +import java.util.HashSet; +import java.util.Set; + public class ApiResponseResponse extends BaseResponse { @SerializedName(ApiConstants.NAME) @Param(description="the name of the api response field") private String name; @@ -31,6 +34,9 @@ public class ApiResponseResponse extends BaseResponse { @SerializedName(ApiConstants.TYPE) @Param(description="response field type") private String type; + @SerializedName(ApiConstants.RESPONSE) @Param(description="api response fields") + private Set apiResponse; + public void setName(String name) { this.name = name; } @@ -42,4 +48,11 @@ public class ApiResponseResponse extends BaseResponse { public void setType(String type) { this.type = type; } + + public void addApiResponse(ApiResponseResponse childApiResponse) { + if(this.apiResponse == null) { + this.apiResponse = new HashSet(); + } + this.apiResponse.add(childApiResponse); + } } diff --git a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java index b3714883964..2d7dbd18671 100755 --- a/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java +++ b/plugins/api/discovery/src/org/apache/cloudstack/discovery/ApiDiscoveryServiceImpl.java @@ -16,25 +16,14 @@ // under the License. package org.apache.cloudstack.discovery; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.annotation.PostConstruct; -import javax.ejb.Local; -import javax.inject.Inject; - +import com.cloud.serializer.Param; +import com.cloud.user.User; +import com.cloud.utils.ReflectUtil; +import com.cloud.utils.StringUtils; +import com.cloud.utils.component.PluggableService; +import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.acl.APIChecker; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.BaseAsyncCmd; -import org.apache.cloudstack.api.BaseAsyncCreateCmd; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.BaseResponse; -import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.*; import org.apache.cloudstack.api.command.user.discovery.ListApisCmd; import org.apache.cloudstack.api.response.ApiDiscoveryResponse; import org.apache.cloudstack.api.response.ApiParameterResponse; @@ -43,12 +32,11 @@ import org.apache.cloudstack.api.response.ListResponse; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.serializer.Param; -import com.cloud.user.User; -import com.cloud.utils.ReflectUtil; -import com.cloud.utils.StringUtils; -import com.cloud.utils.component.PluggableService; -import com.google.gson.annotations.SerializedName; +import javax.annotation.PostConstruct; +import javax.ejb.Local; +import javax.inject.Inject; +import java.lang.reflect.Field; +import java.util.*; @Component @Local(value = ApiDiscoveryService.class) @@ -69,9 +57,9 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { long startTime = System.nanoTime(); s_apiNameDiscoveryResponseMap = new HashMap(); Set> cmdClasses = new HashSet>(); - for(PluggableService service: _services) { + for(PluggableService service: _services) { s_logger.debug(String.format("getting api commands of service: %s", service.getClass().getName())); - cmdClasses.addAll(service.getCommands()); + cmdClasses.addAll(service.getCommands()); } cmdClasses.addAll(this.getCommands()); cacheResponseMap(cmdClasses); @@ -80,72 +68,39 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { } } - protected void cacheResponseMap(Set> cmdClasses) { + protected Map> cacheResponseMap(Set> cmdClasses) { Map> responseApiNameListMap = new HashMap>(); for(Class cmdClass: cmdClasses) { APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class); - if (apiCmdAnnotation == null) + if (apiCmdAnnotation == null) { apiCmdAnnotation = cmdClass.getSuperclass().getAnnotation(APICommand.class); + } if (apiCmdAnnotation == null || !apiCmdAnnotation.includeInApiDoc() - || apiCmdAnnotation.name().isEmpty()) + || apiCmdAnnotation.name().isEmpty()) { continue; + } String apiName = apiCmdAnnotation.name(); + ApiDiscoveryResponse response = getCmdRequestMap(cmdClass, apiCmdAnnotation); + String responseName = apiCmdAnnotation.responseObject().getName(); if (!responseName.contains("SuccessResponse")) { - if (!responseApiNameListMap.containsKey(responseName)) + if (!responseApiNameListMap.containsKey(responseName)) { responseApiNameListMap.put(responseName, new ArrayList()); + } responseApiNameListMap.get(responseName).add(apiName); } - ApiDiscoveryResponse response = new ApiDiscoveryResponse(); - response.setName(apiName); - response.setDescription(apiCmdAnnotation.description()); - if (!apiCmdAnnotation.since().isEmpty()) - response.setSince(apiCmdAnnotation.since()); response.setRelated(responseName); + Field[] responseFields = apiCmdAnnotation.responseObject().getDeclaredFields(); for(Field responseField: responseFields) { - SerializedName serializedName = responseField.getAnnotation(SerializedName.class); - if(serializedName != null) { - ApiResponseResponse responseResponse = new ApiResponseResponse(); - responseResponse.setName(serializedName.value()); - Param param = responseField.getAnnotation(Param.class); - if (param != null) - responseResponse.setDescription(param.description()); - responseResponse.setType(responseField.getType().getSimpleName().toLowerCase()); - response.addApiResponse(responseResponse); - } + ApiResponseResponse responseResponse = getFieldResponseMap(responseField); + response.addApiResponse(responseResponse); } - Set fields = ReflectUtil.getAllFieldsForClass(cmdClass, - new Class[]{BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); - - boolean isAsync = ReflectUtil.isCmdClassAsync(cmdClass, - new Class[] {BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); - - response.setAsync(isAsync); - - for(Field field: fields) { - Parameter parameterAnnotation = field.getAnnotation(Parameter.class); - if (parameterAnnotation != null - && parameterAnnotation.expose() - && parameterAnnotation.includeInApiDoc()) { - - ApiParameterResponse paramResponse = new ApiParameterResponse(); - paramResponse.setName(parameterAnnotation.name()); - paramResponse.setDescription(parameterAnnotation.description()); - paramResponse.setType(parameterAnnotation.type().toString().toLowerCase()); - paramResponse.setLength(parameterAnnotation.length()); - paramResponse.setRequired(parameterAnnotation.required()); - if (!parameterAnnotation.since().isEmpty()) - paramResponse.setSince(parameterAnnotation.since()); - paramResponse.setRelated(parameterAnnotation.entityType()[0].getName()); - response.addParam(paramResponse); - } - } response.setObjectName("api"); s_apiNameDiscoveryResponseMap.put(apiName, response); } @@ -173,6 +128,76 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { } s_apiNameDiscoveryResponseMap.put(apiName, response); } + return responseApiNameListMap; + } + + private ApiResponseResponse getFieldResponseMap(Field responseField) { + ApiResponseResponse responseResponse = new ApiResponseResponse(); + SerializedName serializedName = responseField.getAnnotation(SerializedName.class); + Param param = responseField.getAnnotation(Param.class); + if (serializedName != null && param != null) { + responseResponse.setName(serializedName.value()); + responseResponse.setDescription(param.description()); + responseResponse.setType(responseField.getType().getSimpleName().toLowerCase()); + //If response is not of primitive type - we have a nested entity + Class fieldClass = param.responseObject(); + if (fieldClass != null) { + Class superClass = fieldClass.getSuperclass(); + if (superClass != null) { + String superName = superClass.getName(); + if (superName.equals(BaseResponse.class.getName())) { + Field[] fields = fieldClass.getDeclaredFields(); + for (Field field : fields) { + ApiResponseResponse innerResponse = getFieldResponseMap(field); + if (innerResponse != null) { + responseResponse.addApiResponse(innerResponse); + } + } + } + } + } + } + return responseResponse; + } + + private ApiDiscoveryResponse getCmdRequestMap(Class cmdClass, APICommand apiCmdAnnotation) { + String apiName = apiCmdAnnotation.name(); + ApiDiscoveryResponse response = new ApiDiscoveryResponse(); + response.setName(apiName); + response.setDescription(apiCmdAnnotation.description()); + if (!apiCmdAnnotation.since().isEmpty()) { + response.setSince(apiCmdAnnotation.since()); + } + + + Set fields = ReflectUtil.getAllFieldsForClass(cmdClass, + new Class[]{BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); + + boolean isAsync = ReflectUtil.isCmdClassAsync(cmdClass, + new Class[]{BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); + + response.setAsync(isAsync); + + for(Field field: fields) { + Parameter parameterAnnotation = field.getAnnotation(Parameter.class); + if (parameterAnnotation != null + && parameterAnnotation.expose() + && parameterAnnotation.includeInApiDoc()) { + + ApiParameterResponse paramResponse = new ApiParameterResponse(); + paramResponse.setName(parameterAnnotation.name()); + paramResponse.setDescription(parameterAnnotation.description()); + paramResponse.setType(parameterAnnotation.type().toString().toLowerCase()); + paramResponse.setLength(parameterAnnotation.length()); + paramResponse.setRequired(parameterAnnotation.required()); + if (!parameterAnnotation.since().isEmpty()) { + paramResponse.setSince(parameterAnnotation.since()); + } + paramResponse.setRelated(parameterAnnotation.entityType()[0].getName()); + response.addParam(paramResponse); + } + } + return response; } @Override diff --git a/server/src/com/cloud/api/response/ApiResponseSerializer.java b/server/src/com/cloud/api/response/ApiResponseSerializer.java index 3b1d9a6368b..965660a52cc 100644 --- a/server/src/com/cloud/api/response/ApiResponseSerializer.java +++ b/server/src/com/cloud/api/response/ApiResponseSerializer.java @@ -16,33 +16,25 @@ // under the License. package com.cloud.api.response; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.*; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.api.ApiConstants; import com.cloud.api.ApiDBUtils; import com.cloud.api.ApiResponseGsonHelper; import com.cloud.api.ApiServer; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.ResponseObject; import com.cloud.utils.encoding.URLEncoder; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.uuididentity.dao.IdentityDao; -import com.cloud.uuididentity.dao.IdentityDaoImpl; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.response.*; +import org.apache.log4j.Logger; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ApiResponseSerializer { private static final Logger s_logger = Logger.getLogger(ApiResponseSerializer.class.getName()); diff --git a/server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java b/server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java new file mode 100644 index 00000000000..3099d83d75c --- /dev/null +++ b/server/src/com/cloud/api/response/EmptyFieldExclusionStrategy.java @@ -0,0 +1,40 @@ +/* + * 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.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; + +public class EmptyFieldExclusionStrategy implements ExclusionStrategy { + + @Override + public boolean shouldSkipField(FieldAttributes fieldAttributes) { + if (fieldAttributes.getAnnotation(Param.class) != null) { + return true; + } + return false; + } + + @Override + public boolean shouldSkipClass(Class aClass) { + return false; + } +} diff --git a/test/integration/smoke/test_vm_life_cycle.py b/test/integration/smoke/test_vm_life_cycle.py index d9571f66833..564f6e854a5 100644 --- a/test/integration/smoke/test_vm_life_cycle.py +++ b/test/integration/smoke/test_vm_life_cycle.py @@ -262,11 +262,26 @@ class TestDeployVM(cloudstackTestCase): self.assertIsNotNone(router.publicip, msg="Router has no public ip") self.assertIsNotNone(router.guestipaddress, msg="Router has no guest ip") + @attr(hypervisor = ["simulator"]) + @attr(mode = ["basic"]) + def test_basicZoneVirtualRouter(self): + """ + Tests for basic zone virtual router + 1. Is Running + 2. is in the account the VM was deployed in + @return: + """ + routers = list_routers(self.apiclient, account=self.account.account.name) + self.assertTrue(len(routers) > 0, msg = "No virtual router found") + router = routers[0] + + self.assertEqual(router.state, 'Running', msg="Router is not in running state") + self.assertEqual(router.account, self.account.account.name, msg="Router does not belong to the account") + def tearDown(self): pass - class TestVMLifeCycle(cloudstackTestCase): @classmethod diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index cb63179f40f..4bfb90be4a8 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -24,7 +24,8 @@ import string import hashlib class cloudstackTestClient(object): - def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, defaultWorkerThreads=10, logging=None): + def __init__(self, mgtSvr=None, port=8096, apiKey = None, securityKey = None, asyncTimeout=3600, + defaultWorkerThreads=10, logging=None): self.connection = cloudstackConnection.cloudConnection(mgtSvr, port, apiKey, securityKey, asyncTimeout, logging) self.apiClient = cloudstackAPIClient.CloudStackAPIClient(self.connection) self.dbConnection = None @@ -32,7 +33,6 @@ class cloudstackTestClient(object): self.ssh = None self.defaultWorkerThreads = defaultWorkerThreads - def dbConfigure(self, host="localhost", port=3306, user='cloud', passwd='cloud', db='cloud'): self.dbConnection = dbConnection.dbConnection(host, port, user, passwd, db) @@ -147,7 +147,16 @@ class cloudstackTestClient(object): if hasattr(self, "userApiClient"): return self.userApiClient return None - + + def synchronize(self): + """ + synchronize the api from an endpoint + """ + apiclient = self.getApiClient() + cmd = listApis.listApisCmd() + response = apiclient.listApis(cmd) + + '''FixME, httplib has issue if more than one thread submitted''' def submitCmdsAndWait(self, cmds, workers=1): if self.asyncJobMgr is None: diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index ed9248c49a3..5d9a2dfc5de 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -16,10 +16,12 @@ # under the License. import xml.dom.minidom +import json from optparse import OptionParser from textwrap import dedent import os import sys + class cmdParameterProperty(object): def __init__(self): self.name = None @@ -97,6 +99,7 @@ class codeGenerator: subclass += self.space + self.space + 'self.%s = None\n'%pro.name self.subclass.append(subclass) + def generate(self, cmd): self.cmd = cmd @@ -159,8 +162,7 @@ class codeGenerator: fp.close() self.code = "" self.subclass = [] - - + def finalize(self): '''generate an api call''' @@ -215,8 +217,7 @@ class codeGenerator: fp.write(basecmd) fp.close() - - def constructResponse(self, response): + def constructResponseFromXML(self, response): paramProperty = cmdParameterProperty() paramProperty.name = getText(response.getElementsByTagName('name')) paramProperty.desc = getText(response.getElementsByTagName('description')) @@ -224,7 +225,23 @@ class codeGenerator: '''This is a list''' paramProperty.name = paramProperty.name.split('(*)')[0] for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'): - subProperty = self.constructResponse(subresponse) + subProperty = self.constructResponseFromXML(subresponse) + paramProperty.subProperties.append(subProperty) + return paramProperty + + def constructResponseFromJSON(self, response): + paramProperty = cmdParameterProperty() + if response.has_key('name'): + paramProperty.name = response['name'] + assert paramProperty.name + + if response.has_key('description'): + paramProperty.desc = response['description'] + if response.has_key('type') and response['type'] == 'list': + #Here list becomes a subproperty + paramProperty.name = paramProperty.name.split('(*)')[0] + for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'): + subProperty = self.constructResponseFromXML(subresponse) paramProperty.subProperties.append(subProperty) return paramProperty @@ -269,18 +286,79 @@ class codeGenerator: if response.parentNode != responseEle: continue - paramProperty = self.constructResponse(response) + paramProperty = self.constructResponseFromXML(response) csCmd.response.append(paramProperty) cmds.append(csCmd) return cmds - - def generateCode(self): + + def loadCmdFromJSON(self, apiStream): + if apiStream is None: + raise Exception("No APIs found through discovery") + + apiDict = json.loads(apiStream) + if not apiDict.has_key('listapisresponse'): + raise Exception("API discovery plugin response failed") + if not apiDict['listapisresponse'].has_key('count'): + raise Exception("Malformed api response") + + apilist = apiDict['listapisresponse']['api'] + cmds = [] + for cmd in apilist: + csCmd = cloudStackCmd() + if cmd.has_key('name'): + csCmd.name = cmd['name'] + assert csCmd.name + + if cmd.has_key('description'): + csCmd.desc = cmd['description'] + + if cmd.has_key('async'): + csCmd.async = cmd['isasync'] + + for param in cmd['params']: + paramProperty = cmdParameterProperty() + + if param.has_key('name'): + paramProperty.name = param['name'] + assert paramProperty.name + + if param.has_key('required'): + paramProperty.required = param.getElementsByTagName('required') + + if param.has_key('description'): + paramProperty.desc = param['description'] + + if param.has_key('type'): + paramProperty.type = param['type'] + + csCmd.request.append(paramProperty) + + for response in cmd['response']: + paramProperty = self.constructResponseFromJSON(response) + csCmd.response.append(paramProperty) + + cmds.append(csCmd) + return cmds + + + def generateCodeFromXML(self): cmds = self.loadCmdFromXML() for cmd in cmds: self.generate(cmd) self.finalize() + def generateCodeFromJSON(self, apiJson): + """ + Api Discovery plugin returns the supported APIs of a CloudStack endpoint. + @return: The classes in cloudstackAPI/ formed from api discovery json + """ + with open(apiJson, 'r') as apiStream: + cmds = self.loadCmdFromJSON(apiStream) + for cmd in cmds: + self.generate(cmd) + self.finalize() + def getText(elements): return elements[0].childNodes[0].nodeValue.strip() @@ -315,5 +393,5 @@ if __name__ == "__main__": exit(2) cg = codeGenerator(folder, apiSpecFile) - cg.generateCode() + cg.generateCodeFromXML() diff --git a/tools/marvin/marvin/marvinPlugin.py b/tools/marvin/marvin/marvinPlugin.py index c52596e6d43..518f27fe70b 100644 --- a/tools/marvin/marvin/marvinPlugin.py +++ b/tools/marvin/marvin/marvinPlugin.py @@ -21,6 +21,7 @@ import logging import nose.core from marvin.cloudstackTestCase import cloudstackTestCase from marvin import deployDataCenter +from marvin import apiSynchronizer from nose.plugins.base import Plugin from functools import partial @@ -39,6 +40,10 @@ class MarvinPlugin(Plugin): self.enableOpt = "--with-marvin" self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s") + if options.sync: + self.do_sync(options.config) + return + if options.debug_log: self.logger = logging.getLogger("NoseTestExecuteEngine") self.debug_stream = logging.FileHandler(options.debug_log) @@ -65,6 +70,13 @@ class MarvinPlugin(Plugin): cfg.debugLog = self.debug_stream self.testrunner = nose.core.TextTestRunner(stream=self.result_stream, descriptions=True, verbosity=2, config=config) + + def do_sync(self, config): + """ + Use the ApiDiscovery plugin exposed by the CloudStack mgmt server to rebuild the cloudStack API + """ + apiSynchronizer.sync(config) + def options(self, parser, env): """ @@ -84,6 +96,8 @@ class MarvinPlugin(Plugin): help="The path to the testcase debug logs [DEBUG_LOG]") parser.add_option("--load", action="store_true", default=False, dest="load", help="Only load the deployment configuration given") + parser.add_option("--sync", action="store_true", default=False, dest="sync", + help="Sync the APIs from the CloudStack endpoint in marvin-config") Plugin.options(self, parser, env) From 82fd9382b7497f1ee753e1298a9db1aed325fbc6 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Thu, 28 Mar 2013 18:19:15 +0530 Subject: [PATCH 031/120] marvin+sync: apidiscovery sync and regenerate for marvin Use codegenerator to sync marvin cloudstackAPIs from a given cloudstack endpoint. Sometimes you want to synchronize marvin with the new APIs that you have introduced locally or any alterations you may have made the API. In such cases you can sync marvin's libraries as follows. $sudo mvn -Pdeveloper,marvin.sync -Dendpoint=localhost -pl :cloud-marvin This needs sudo privileges since it will call on pip to upgrade the existing marvin installation on your machine. The endpoint is where your management server is running and is exposing the API discovery plugin. A listApis call is made and the resulting json deserialized back into marvin's library entities. Signed-off-by: Prasanna Santhanam --- .../api/response/ServiceResponse.java | 9 +- tools/marvin/marvin/cloudstackTestClient.py | 8 - tools/marvin/marvin/codegenerator.py | 215 ++++++++++-------- tools/marvin/marvin/integration/lib/base.py | 2 + tools/marvin/marvin/marvinPlugin.py | 16 +- tools/marvin/pom.xml | 71 +++++- 6 files changed, 192 insertions(+), 129 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/response/ServiceResponse.java b/api/src/org/apache/cloudstack/api/response/ServiceResponse.java index 445afcfcf5b..c93c55ee16a 100644 --- a/api/src/org/apache/cloudstack/api/response/ServiceResponse.java +++ b/api/src/org/apache/cloudstack/api/response/ServiceResponse.java @@ -16,13 +16,12 @@ // under the License. package org.apache.cloudstack.api.response; -import java.util.List; - +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; -import com.cloud.serializer.Param; -import com.google.gson.annotations.SerializedName; +import java.util.List; @SuppressWarnings("unused") public class ServiceResponse extends BaseResponse { @@ -30,7 +29,7 @@ public class ServiceResponse extends BaseResponse { @SerializedName(ApiConstants.NAME) @Param(description="the service name") private String name; - @SerializedName(ApiConstants.PROVIDER) @Param(description="the service provider name") + @SerializedName(ApiConstants.PROVIDER) @Param(description="the service provider name", responseObject = ProviderResponse.class) private List providers; @SerializedName("capability") @Param(description="the list of capabilities", responseObject = CapabilityResponse.class) diff --git a/tools/marvin/marvin/cloudstackTestClient.py b/tools/marvin/marvin/cloudstackTestClient.py index 4bfb90be4a8..e4735e453db 100644 --- a/tools/marvin/marvin/cloudstackTestClient.py +++ b/tools/marvin/marvin/cloudstackTestClient.py @@ -148,14 +148,6 @@ class cloudstackTestClient(object): return self.userApiClient return None - def synchronize(self): - """ - synchronize the api from an endpoint - """ - apiclient = self.getApiClient() - cmd = listApis.listApisCmd() - response = apiclient.listApis(cmd) - '''FixME, httplib has issue if more than one thread submitted''' def submitCmdsAndWait(self, cmds, workers=1): diff --git a/tools/marvin/marvin/codegenerator.py b/tools/marvin/marvin/codegenerator.py index 5d9a2dfc5de..0622e5dbc9e 100644 --- a/tools/marvin/marvin/codegenerator.py +++ b/tools/marvin/marvin/codegenerator.py @@ -21,6 +21,7 @@ from optparse import OptionParser from textwrap import dedent import os import sys +import urllib2 class cmdParameterProperty(object): def __init__(self): @@ -38,18 +39,21 @@ class cloudStackCmd: self.request = [] self.response = [] -class codeGenerator: - space = " " +class codeGenerator: + """ + Apache CloudStack- marvin python classes can be generated from the json returned by API discovery or from the + xml spec of commands generated by the ApiDocWriter. This class provides helper methods for these uses. + """ + space = " " cmdsName = [] - - def __init__(self, outputFolder, apiSpecFile): + + def __init__(self, outputFolder): self.cmd = None self.code = "" self.required = [] self.subclass = [] self.outputFolder = outputFolder - self.apiSpecFile = apiSpecFile lic = """\ # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -58,19 +62,19 @@ class codeGenerator: # 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. + # under the License. """ self.license = dedent(lic) - + def addAttribute(self, attr, pro): value = pro.value if pro.required: @@ -80,11 +84,11 @@ class codeGenerator: self.code += self.space self.code += "''' " + pro.desc + " '''" self.code += "\n" - + self.code += self.space self.code += attr + " = " + str(value) self.code += "\n" - + def generateSubClass(self, name, properties): '''generate code for sub list''' subclass = 'class %s:\n'%name @@ -97,44 +101,44 @@ class codeGenerator: self.generateSubClass(pro.name, pro.subProperties) else: subclass += self.space + self.space + 'self.%s = None\n'%pro.name - + self.subclass.append(subclass) def generate(self, cmd): - + self.cmd = cmd self.cmdsName.append(self.cmd.name) self.code = self.license self.code += "\n" - self.code += '"""%s"""\n'%self.cmd.desc + self.code += '"""%s"""\n'%self.cmd.desc self.code += 'from baseCmd import *\n' self.code += 'from baseResponse import *\n' self.code += "class %sCmd (baseCmd):\n"%self.cmd.name self.code += self.space + "def __init__(self):\n" - - self.code += self.space + self.space + 'self.isAsync = "%s"\n' %self.cmd.async - + + self.code += self.space + self.space + 'self.isAsync = "%s"\n' %str(self.cmd.async).lower() + for req in self.cmd.request: if req.desc is not None: self.code += self.space + self.space + '"""%s"""\n'%req.desc if req.required == "true": self.code += self.space + self.space + '"""Required"""\n' - + value = "None" if req.type == "list" or req.type == "map": value = "[]" - + self.code += self.space + self.space + 'self.%s = %s\n'%(req.name,value) if req.required == "true": self.required.append(req.name) - + self.code += self.space + self.space + "self.required = [" for require in self.required: self.code += '"' + require + '",' self.code += "]\n" self.required = [] - - + + """generate response code""" subItems = {} self.code += "\n" @@ -146,17 +150,17 @@ class codeGenerator: for res in self.cmd.response: if res.desc is not None: self.code += self.space + self.space + '"""%s"""\n'%res.desc - + if len(res.subProperties) > 0: self.code += self.space + self.space + 'self.%s = []\n'%res.name self.generateSubClass(res.name, res.subProperties) else: self.code += self.space + self.space + 'self.%s = None\n'%res.name self.code += '\n' - + for subclass in self.subclass: self.code += subclass + "\n" - + fp = open(self.outputFolder + "/cloudstackAPI/%s.py"%self.cmd.name, "w") fp.write(self.code) fp.close() @@ -165,7 +169,7 @@ class codeGenerator: def finalize(self): '''generate an api call''' - + header = '"""Test Client for CloudStack API"""\n' imports = "import copy\n" initCmdsList = '__all__ = [' @@ -174,33 +178,33 @@ class codeGenerator: body += self.space + 'def __init__(self, connection):\n' body += self.space + self.space + 'self.connection = connection\n' body += "\n" - + body += self.space + 'def __copy__(self):\n' body += self.space + self.space + 'return CloudStackAPIClient(copy.copy(self.connection))\n' body += "\n" - + for cmdName in self.cmdsName: body += self.space + 'def %s(self,command):\n'%cmdName body += self.space + self.space + 'response = %sResponse()\n'%cmdName body += self.space + self.space + 'response = self.connection.make_request(command, response)\n' body += self.space + self.space + 'return response\n' body += '\n' - + imports += 'from %s import %sResponse\n'%(cmdName, cmdName) initCmdsList += '"%s",'%cmdName - + fp = open(self.outputFolder + '/cloudstackAPI/cloudstackAPIClient.py', 'w') fp.write(self.license) for item in [header, imports, body]: fp.write(item) fp.close() - + '''generate __init__.py''' initCmdsList = self.license + initCmdsList + '"cloudstackAPIClient"]' fp = open(self.outputFolder + '/cloudstackAPI/__init__.py', 'w') fp.write(initCmdsList) fp.close() - + fp = open(self.outputFolder + '/cloudstackAPI/baseCmd.py', 'w') basecmd = self.license basecmd += '"""Base Command"""\n' @@ -208,7 +212,7 @@ class codeGenerator: basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() - + fp = open(self.outputFolder + '/cloudstackAPI/baseResponse.py', 'w') basecmd = self.license basecmd += '"""Base class for response"""\n' @@ -216,7 +220,7 @@ class codeGenerator: basecmd += self.space + 'pass\n' fp.write(basecmd) fp.close() - + def constructResponseFromXML(self, response): paramProperty = cmdParameterProperty() paramProperty.name = getText(response.getElementsByTagName('name')) @@ -229,74 +233,84 @@ class codeGenerator: paramProperty.subProperties.append(subProperty) return paramProperty - def constructResponseFromJSON(self, response): - paramProperty = cmdParameterProperty() - if response.has_key('name'): - paramProperty.name = response['name'] - assert paramProperty.name - - if response.has_key('description'): - paramProperty.desc = response['description'] - if response.has_key('type') and response['type'] == 'list': - #Here list becomes a subproperty - paramProperty.name = paramProperty.name.split('(*)')[0] - for subresponse in response.getElementsByTagName('arguments')[0].getElementsByTagName('arg'): - subProperty = self.constructResponseFromXML(subresponse) - paramProperty.subProperties.append(subProperty) - return paramProperty - - def loadCmdFromXML(self): - dom = xml.dom.minidom.parse(self.apiSpecFile) + def loadCmdFromXML(self, dom): cmds = [] for cmd in dom.getElementsByTagName("command"): csCmd = cloudStackCmd() csCmd.name = getText(cmd.getElementsByTagName('name')) assert csCmd.name - + desc = getText(cmd.getElementsByTagName('description')) - if desc: + if desc: csCmd.desc = desc - + async = getText(cmd.getElementsByTagName('isAsync')) if async: csCmd.async = async - + for param in cmd.getElementsByTagName("request")[0].getElementsByTagName("arg"): paramProperty = cmdParameterProperty() - + paramProperty.name = getText(param.getElementsByTagName('name')) assert paramProperty.name - + required = param.getElementsByTagName('required') if required: paramProperty.required = getText(required) - + requestDescription = param.getElementsByTagName('description') - if requestDescription: + if requestDescription: paramProperty.desc = getText(requestDescription) - + type = param.getElementsByTagName("type") if type: paramProperty.type = getText(type) - + csCmd.request.append(paramProperty) - + responseEle = cmd.getElementsByTagName("response")[0] for response in responseEle.getElementsByTagName("arg"): if response.parentNode != responseEle: continue - + paramProperty = self.constructResponseFromXML(response) csCmd.response.append(paramProperty) - + cmds.append(csCmd) return cmds + def generateCodeFromXML(self, apiSpecFile): + dom = xml.dom.minidom.parse(apiSpecFile) + cmds = self.loadCmdFromXML(dom) + for cmd in cmds: + self.generate(cmd) + self.finalize() + + def constructResponseFromJSON(self, response): + paramProperty = cmdParameterProperty() + if response.has_key('name'): + paramProperty.name = response['name'] + assert paramProperty.name, "%s has no property name"%response + + if response.has_key('description'): + paramProperty.desc = response['description'] + if response.has_key('type'): + if response['type'] in ['list', 'map', 'set']: + #Here list becomes a subproperty + if response.has_key('response'): + for innerResponse in response['response']: + subProperty = self.constructResponseFromJSON(innerResponse) + paramProperty.subProperties.append(subProperty) + paramProperty.type = response['type'] + return paramProperty + def loadCmdFromJSON(self, apiStream): if apiStream is None: raise Exception("No APIs found through discovery") - apiDict = json.loads(apiStream) + jsonOut = apiStream.readlines() + assert len(jsonOut) > 0 + apiDict = json.loads(jsonOut[0]) if not apiDict.has_key('listapisresponse'): raise Exception("API discovery plugin response failed") if not apiDict['listapisresponse'].has_key('count'): @@ -313,7 +327,7 @@ class codeGenerator: if cmd.has_key('description'): csCmd.desc = cmd['description'] - if cmd.has_key('async'): + if cmd.has_key('isasync'): csCmd.async = cmd['isasync'] for param in cmd['params']: @@ -324,7 +338,7 @@ class codeGenerator: assert paramProperty.name if param.has_key('required'): - paramProperty.required = param.getElementsByTagName('required') + paramProperty.required = param['required'] if param.has_key('description'): paramProperty.desc = param['description'] @@ -335,29 +349,25 @@ class codeGenerator: csCmd.request.append(paramProperty) for response in cmd['response']: - paramProperty = self.constructResponseFromJSON(response) - csCmd.response.append(paramProperty) + #FIXME: ExtractImage related APIs return empty dicts in response + if len(response) > 0: + paramProperty = self.constructResponseFromJSON(response) + csCmd.response.append(paramProperty) cmds.append(csCmd) return cmds - - def generateCodeFromXML(self): - cmds = self.loadCmdFromXML() - for cmd in cmds: - self.generate(cmd) - self.finalize() - - def generateCodeFromJSON(self, apiJson): + def generateCodeFromJSON(self, endpointUrl): """ Api Discovery plugin returns the supported APIs of a CloudStack endpoint. @return: The classes in cloudstackAPI/ formed from api discovery json """ - with open(apiJson, 'r') as apiStream: - cmds = self.loadCmdFromJSON(apiStream) - for cmd in cmds: - self.generate(cmd) - self.finalize() + if endpointUrl.find('response=json') >= 0: + apiStream = urllib2.urlopen(endpointUrl) + cmds = self.loadCmdFromJSON(apiStream) + for cmd in cmds: + self.generate(cmd) + self.finalize() def getText(elements): return elements[0].childNodes[0].nodeValue.strip() @@ -365,20 +375,14 @@ def getText(elements): if __name__ == "__main__": parser = OptionParser() - parser.add_option("-o", "--output", dest="output", help="the root path where code genereted, default is .") - parser.add_option("-s", "--specfile", dest="spec", help="the path and name of the api spec xml file, default is /etc/cloud/cli/commands.xml") - + parser.add_option("-o", "--output", dest="output", + help="The path to the generated code entities, default is .") + parser.add_option("-s", "--specfile", dest="spec", + help="The path and name of the api spec xml file, default is /etc/cloud/cli/commands.xml") + parser.add_option("-e", "--endpoint", dest="endpoint", + help="The endpoint mgmt server (with open 8096) where apis are discovered, default is localhost") + (options, args) = parser.parse_args() - - apiSpecFile = "/etc/cloud/cli/commands.xml" - if options.spec is not None: - apiSpecFile = options.spec - - if not os.path.exists(apiSpecFile): - print "the spec file %s does not exists"%apiSpecFile - print parser.print_help() - exit(1) - folder = "." if options.output is not None: @@ -391,7 +395,18 @@ if __name__ == "__main__": print "Failed to create folder %s, due to %s"%(apiModule,sys.exc_info()) print parser.print_help() exit(2) - - cg = codeGenerator(folder, apiSpecFile) - cg.generateCodeFromXML() - + + apiSpecFile = "/etc/cloud/cli/commands.xml" + if options.spec is not None: + apiSpecFile = options.spec + if not os.path.exists(apiSpecFile): + print "the spec file %s does not exists"%apiSpecFile + print parser.print_help() + exit(1) + + cg = codeGenerator(folder) + if options.spec is not None: + cg.generateCodeFromXML(apiSpecFile) + elif options.endpoint is not None: + endpointUrl='http://%s:8096/client/api?command=listApis&response=json'%options.endpoint + cg.generateCodeFromJSON(endpointUrl) diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 3751d987785..f3370eb3190 100644 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -883,6 +883,8 @@ class PublicIPAddress: if accountid: cmd.account = accountid + elif "account" in services: + cmd.account = services["account"] if zoneid: cmd.zoneid = zoneid diff --git a/tools/marvin/marvin/marvinPlugin.py b/tools/marvin/marvin/marvinPlugin.py index 518f27fe70b..46a8a4f3445 100644 --- a/tools/marvin/marvin/marvinPlugin.py +++ b/tools/marvin/marvin/marvinPlugin.py @@ -21,7 +21,6 @@ import logging import nose.core from marvin.cloudstackTestCase import cloudstackTestCase from marvin import deployDataCenter -from marvin import apiSynchronizer from nose.plugins.base import Plugin from functools import partial @@ -40,10 +39,6 @@ class MarvinPlugin(Plugin): self.enableOpt = "--with-marvin" self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(message)s") - if options.sync: - self.do_sync(options.config) - return - if options.debug_log: self.logger = logging.getLogger("NoseTestExecuteEngine") self.debug_stream = logging.FileHandler(options.debug_log) @@ -71,13 +66,6 @@ class MarvinPlugin(Plugin): self.testrunner = nose.core.TextTestRunner(stream=self.result_stream, descriptions=True, verbosity=2, config=config) - def do_sync(self, config): - """ - Use the ApiDiscovery plugin exposed by the CloudStack mgmt server to rebuild the cloudStack API - """ - apiSynchronizer.sync(config) - - def options(self, parser, env): """ Register command line options @@ -96,9 +84,7 @@ class MarvinPlugin(Plugin): help="The path to the testcase debug logs [DEBUG_LOG]") parser.add_option("--load", action="store_true", default=False, dest="load", help="Only load the deployment configuration given") - parser.add_option("--sync", action="store_true", default=False, dest="sync", - help="Sync the APIs from the CloudStack endpoint in marvin-config") - + Plugin.options(self, parser, env) def __init__(self): diff --git a/tools/marvin/pom.xml b/tools/marvin/pom.xml index 4f012eedf08..a5cbd31e24b 100644 --- a/tools/marvin/pom.xml +++ b/tools/marvin/pom.xml @@ -83,7 +83,76 @@ + + + sync + + + endpoint + localhost + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + + generate-sources + generate-sources + + exec + + + ${basedir}/marvin + python + + codegenerator.py + -e + ${endpoint} + Generating ${project.artifactId} API classes} + + + + + package + package + + exec + + + ${exec.workingdir} + python + + setup.py + sdist + + + + + install + install + + exec + + + ${basedir}/dist + pip + + install + --upgrade + Marvin-0.1.0.tar.gz + + + + + + + + marvin @@ -128,7 +197,7 @@ ${basedir}/marvin - /usr/local/bin/nosetests + nosetests --with-marvin --marvin-config From b798c451141c32d46322aae83063eeaa9634b337 Mon Sep 17 00:00:00 2001 From: Prasanna Santhanam Date: Tue, 2 Apr 2013 13:09:36 +0530 Subject: [PATCH 032/120] maven+marvin+simulator: Changes to the lifecycle steps integration test is now run as follows: Build $ mvn -Pdeveloper -Dsimulator clean install DB: $ mvn -Pdeveloper -pl developer -Ddeploydb $ mvn -Pdeveloper -pl developer -Ddeploydb-simulator Setup: $ mvn -Pdeveloper,marvin.setup -Dmarvin.config=setup/dev/advanced.cfg -pl :cloud-marvin integration-test Test: $ mvn -Pdeveloper,marvin.test -Dmarvin.config=setup/dev/advanced.cfg -pl :cloud-marvin integration-test Signed-off-by: Prasanna Santhanam --- client/pom.xml | 11 + client/tomcatconf/componentContext.xml.in | 400 +++++++----------- .../simulatorComponentContext.xml.in | 383 ++++++++--------- .../agent/manager/MockStorageManagerImpl.java | 36 +- .../dao/HypervisorCapabilitiesDaoImpl.java | 15 +- setup/db/templates.simulator.sql | 4 +- tools/marvin/pom.xml | 40 +- 7 files changed, 403 insertions(+), 486 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 35588aa2c93..05934f4db17 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -214,10 +214,21 @@ cloud-plugin-hypervisor-simulator ${project.version} + org.apache.cloudstack cloud-plugin-storage-volume-default ${project.version} + + org.apache.cloudstack + cloud-plugin-syslog-alerts + ${project.version} + + + org.apache.cloudstack + cloud-plugin-snmp-alerts + ${project.version} + install diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 584be9787e8..0ddb428d92e 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -1,3 +1,4 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + + + + + + + + + - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - + + + + - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + - - - - - - - + diff --git a/client/tomcatconf/simulatorComponentContext.xml.in b/client/tomcatconf/simulatorComponentContext.xml.in index d501ca1d10e..1cb9f6f2b63 100644 --- a/client/tomcatconf/simulatorComponentContext.xml.in +++ b/client/tomcatconf/simulatorComponentContext.xml.in @@ -1,3 +1,4 @@ + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - + diff --git a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java index 859acc85958..a50dff6382c 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java +++ b/plugins/hypervisors/simulator/src/com/cloud/agent/manager/MockStorageManagerImpl.java @@ -16,23 +16,6 @@ // under the License. package com.cloud.agent.manager; -import java.io.File; -import java.math.BigInteger; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.ejb.Local; -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - import com.cloud.agent.api.Answer; import com.cloud.agent.api.AttachIsoCommand; import com.cloud.agent.api.AttachVolumeAnswer; @@ -97,8 +80,23 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine.State; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.io.File; +import java.math.BigInteger; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + @Component @Local(value = { MockStorageManager.class }) public class MockStorageManagerImpl extends ManagerBase implements MockStorageManager { @@ -954,7 +952,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa long defaultTemplateSize = 2 * 1024 * 1024 * 1024L; MockVolumeVO template = new MockVolumeVO(); template.setName("simulator-domR"); - template.setPath(storage.getMountPoint() + "template/tmpl/1/10/" + UUID.randomUUID().toString()); + template.setPath(storage.getMountPoint() + "template/tmpl/1/100/" + UUID.randomUUID().toString()); template.setPoolId(storage.getId()); template.setSize(defaultTemplateSize); template.setType(MockVolumeType.TEMPLATE); @@ -975,7 +973,7 @@ public class MockStorageManagerImpl extends ManagerBase implements MockStorageMa template = new MockVolumeVO(); template.setName("simulator-Centos"); - template.setPath(storage.getMountPoint() + "template/tmpl/1/11/" + UUID.randomUUID().toString()); + template.setPath(storage.getMountPoint() + "template/tmpl/1/111/" + UUID.randomUUID().toString()); template.setPoolId(storage.getId()); template.setSize(defaultTemplateSize); template.setType(MockVolumeType.TEMPLATE); diff --git a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java index 5421a897b78..759803e67ac 100644 --- a/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java +++ b/server/src/com/cloud/hypervisor/dao/HypervisorCapabilitiesDaoImpl.java @@ -16,19 +16,16 @@ // under the License. package com.cloud.hypervisor.dao; -import java.util.List; - -import javax.ejb.Local; - -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorCapabilitiesVO; import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.ejb.Local; +import java.util.List; @Component @Local(value=HypervisorCapabilitiesDao.class) @@ -79,6 +76,8 @@ public class HypervisorCapabilitiesDaoImpl extends GenericDaoBase - sync + marvin.sync endpoint @@ -154,7 +154,10 @@ - marvin + marvin.setup + + ${user.dir}/setup/dev/advanced.cfg + marvin.config @@ -179,7 +182,7 @@ deployAndRun.py -c - ${user.dir}/${marvin.config} + ${marvin.config} -t /tmp/t.log -r @@ -189,6 +192,30 @@ + + + + + + + marvin.test + + ${user.dir}/setup/dev/advanced.cfg + simulator + test/integration/smoke + + + + marvin.config + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + integration-test integration-test @@ -201,11 +228,12 @@ --with-marvin --marvin-config - ${user.dir}/${marvin.config} + ${marvin.config} --load -a - tags=simulator - ${basedir}/../../test/integration/smoke/test_vm_life_cycle.py + tags=${tag} + ${user.dir}/${test} + -v From 6110e00c549630e8b08fc6ca4818a60ef6a0c919 Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Tue, 2 Apr 2013 19:11:08 +0530 Subject: [PATCH 033/120] CLOUDSTACK-1830: ZWPS: NPE while create volume from snapshot --- .../storage/allocator/ZoneWideStoragePoolAllocator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java index c45f8a822a9..a4aa3d5cf84 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java +++ b/engine/storage/src/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java @@ -56,7 +56,7 @@ public class ZoneWideStoragePoolAllocator extends AbstractStoragePoolAllocator { VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { List suitablePools = new ArrayList(); - HypervisorType hypervisor = vmProfile.getHypervisorType(); + HypervisorType hypervisor = dskCh.getHypersorType(); if (hypervisor != null) { if (hypervisor != HypervisorType.KVM) { s_logger.debug("Only kvm supports zone wide storage"); From 231367685789ff6e521879d25365d6ec65a1f076 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Tue, 2 Apr 2013 11:03:25 -0700 Subject: [PATCH 034/120] 41-42 db upgrade - added `cloud` db reference to the upgrade statements for remote access vpn --- setup/db/db/schema-410to420-cleanup.sql | 8 ++++---- setup/db/db/schema-410to420.sql | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/setup/db/db/schema-410to420-cleanup.sql b/setup/db/db/schema-410to420-cleanup.sql index 187076ff984..b65717f3593 100644 --- a/setup/db/db/schema-410to420-cleanup.sql +++ b/setup/db/db/schema-410to420-cleanup.sql @@ -20,9 +20,9 @@ --; #have to drop the foreign key in order to delete primary key; will re-insert the foreign key later -ALTER TABLE remote_access_vpn DROP foreign key `fk_remote_access_vpn__vpn_server_addr_id`; -ALTER TABLE remote_access_vpn DROP primary key; -ALTER TABLE remote_access_vpn ADD primary key (`id`); -ALTER TABLE remote_access_vpn ADD CONSTRAINT `fk_remote_access_vpn__vpn_server_addr_id` FOREIGN KEY (`vpn_server_addr_id`) REFERENCES `user_ip_address` (`id`); +ALTER TABLE `cloud`.`remote_access_vpn` DROP foreign key `fk_remote_access_vpn__vpn_server_addr_id`; +ALTER TABLE `cloud`.`remote_access_vpn` DROP primary key; +ALTER TABLE `cloud`.`remote_access_vpn` ADD primary key (`id`); +ALTER TABLE `cloud`.`remote_access_vpn` ADD CONSTRAINT `fk_remote_access_vpn__vpn_server_addr_id` FOREIGN KEY (`vpn_server_addr_id`) REFERENCES `user_ip_address` (`id`); diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql index 3dee7aec79b..ab9df05103b 100644 --- a/setup/db/db/schema-410to420.sql +++ b/setup/db/db/schema-410to420.sql @@ -391,8 +391,8 @@ CREATE VIEW `cloud`.`account_view` AS and async_job.instance_type = 'Account' and async_job.job_status = 0; -ALTER TABLE remote_access_vpn ADD COLUMN `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id'; -ALTER TABLE remote_access_vpn ADD COLUMN `uuid` varchar(40) UNIQUE; +ALTER TABLE `cloud`.`remote_access_vpn` ADD COLUMN `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT COMMENT 'id'; +ALTER TABLE `cloud`.`remote_access_vpn` ADD COLUMN `uuid` varchar(40) UNIQUE; -- START: support for LXC From f2ad38aa0f5623551fdd0a295219fb948030bd28 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Mon, 1 Apr 2013 18:25:06 -0700 Subject: [PATCH 035/120] CLOUDSTACK-1865: Change StatsCollector to be a manager so that it can initialize itself at proper run level --- server/src/com/cloud/server/StatsCollector.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index b1f4a570f48..05be0e2e3af 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -66,6 +66,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ComponentMethodInterceptable; +import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.SearchCriteria; import com.cloud.vm.UserVmManager; @@ -78,7 +79,7 @@ import com.cloud.vm.dao.UserVmDao; * */ @Component -public class StatsCollector implements ComponentMethodInterceptable { +public class StatsCollector extends ManagerBase implements ComponentMethodInterceptable { public static final Logger s_logger = Logger.getLogger(StatsCollector.class.getName()); private static StatsCollector s_instance = null; @@ -122,10 +123,11 @@ public class StatsCollector implements ComponentMethodInterceptable { s_instance = this; } - @PostConstruct - private void init(){ + @Override + public boolean start() { init(_configDao.getConfiguration()); - } + return true; + } private void init(Map configs) { _executor = Executors.newScheduledThreadPool(3, new NamedThreadFactory("StatsCollector")); From f52820f2fdbede9ad8f4675223a2306b9d89ac51 Mon Sep 17 00:00:00 2001 From: Min Chen Date: Tue, 2 Apr 2013 11:42:36 -0700 Subject: [PATCH 036/120] CLOUDSTACK-1890: listProjects is not listing state in the response. --- server/src/com/cloud/api/query/vo/ProjectJoinVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/com/cloud/api/query/vo/ProjectJoinVO.java b/server/src/com/cloud/api/query/vo/ProjectJoinVO.java index 73ec9313289..4bfddef01fe 100644 --- a/server/src/com/cloud/api/query/vo/ProjectJoinVO.java +++ b/server/src/com/cloud/api/query/vo/ProjectJoinVO.java @@ -25,9 +25,9 @@ import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.Table; +import com.cloud.projects.Project.State; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.utils.db.GenericDao; -import com.cloud.vm.VirtualMachine.State; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; From 7e54f40a028a909e19756e07ebe05782f31cfd05 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 3 Apr 2013 01:29:45 +0530 Subject: [PATCH 037/120] CLOUDSTACK-1897: Ignore appliance definitions for license checking Regression caused due to 8e917b1ad3c0d3076b0c6425ea3318a6d6dd5c25 Signed-off-by: Rohit Yadav --- pom.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 5e5f6245f4e..62081241445 100644 --- a/pom.xml +++ b/pom.xml @@ -318,11 +318,9 @@ dist/console-proxy/js/jquery.js scripts/vm/systemvm/id_rsa.cloud tools/devcloud/basebuild/puppet-devcloudinitial/files/network.conf - tools/appliance/definitions/systemvmtemplate/base.sh - tools/appliance/definitions/systemvmtemplate/cleanup.sh - tools/appliance/definitions/systemvmtemplate/definition.rb - tools/appliance/definitions/systemvmtemplate/preseed.cfg - tools/appliance/definitions/systemvmtemplate/zerodisk.sh + tools/appliance/definitions/devcloud/* + tools/appliance/definitions/systemvmtemplate/* + tools/appliance/definitions/systemvmtemplate64/* tools/cli/cloudmonkey.egg-info/* tools/devcloud/src/deps/boxes/basebox-build/definition.rb tools/devcloud/src/deps/boxes/basebox-build/preseed.cfg From 58c962ef15d507226a8cc0eb18abca23142cff1f Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Tue, 2 Apr 2013 15:53:09 -0700 Subject: [PATCH 038/120] Retire unused files to avoid confusions --- .../DefaultInterceptorLibrary.java | 33 ----- .../src/com/cloud/event/ActionEventUtils.java | 114 ------------------ .../component/AnnotationInterceptor.java | 36 ------ .../component/ComponentMethodProxyCache.java | 90 -------------- .../utils/component/InterceptorLibrary.java | 25 ---- .../component/MatchAnyMethodPointcut.java | 27 ----- .../com/cloud/utils/db/DatabaseCallback.java | 84 ------------- .../utils/db/DatabaseCallbackFilter.java | 58 --------- 8 files changed, 467 deletions(-) delete mode 100644 server/src/com/cloud/configuration/DefaultInterceptorLibrary.java delete mode 100644 utils/src/com/cloud/utils/component/AnnotationInterceptor.java delete mode 100644 utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java delete mode 100644 utils/src/com/cloud/utils/component/InterceptorLibrary.java delete mode 100644 utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.java delete mode 100644 utils/src/com/cloud/utils/db/DatabaseCallback.java delete mode 100755 utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java diff --git a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java b/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java deleted file mode 100644 index 13a22dbe827..00000000000 --- a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java +++ /dev/null @@ -1,33 +0,0 @@ -// 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.configuration; - -import com.cloud.event.ActionEventUtils; -import com.cloud.utils.component.AnnotationInterceptor; -import com.cloud.utils.component.InterceptorLibrary; -import com.cloud.utils.db.DatabaseCallback; - -import java.util.List; - -public class DefaultInterceptorLibrary implements InterceptorLibrary { - - @Override - public void addInterceptors(List> interceptors) { - interceptors.add(new DatabaseCallback()); - interceptors.add(new ActionEventUtils.ActionEventCallback()); - } -} diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java index 3f3ca685f73..a2d490662eb 100755 --- a/server/src/com/cloud/event/ActionEventUtils.java +++ b/server/src/com/cloud/event/ActionEventUtils.java @@ -22,14 +22,9 @@ import com.cloud.server.ManagementServer; import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.User; -import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; -import com.cloud.utils.component.AnnotationInterceptor; import com.cloud.utils.component.ComponentContext; -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; import org.apache.cloudstack.framework.events.EventBus; import org.apache.cloudstack.framework.events.EventBusException; import org.apache.log4j.Logger; @@ -38,8 +33,6 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.inject.Inject; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -185,111 +178,4 @@ public class ActionEventUtils { AccountVO account = _accountDao.findByIdIncludingRemoved(accountId); return account.getDomainId(); } - - public static class ActionEventCallback implements MethodInterceptor, AnnotationInterceptor { - - @Override - public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { - EventVO event = interceptStart(method); - boolean success = true; - try { - return methodProxy.invokeSuper(object, args); - } catch (Exception e){ - success = false; - interceptException(method, event); - throw e; - } finally { - if(success){ - interceptComplete(method, event); - } - } - } - - @Override - public boolean needToIntercept(AnnotatedElement element) { - if (!(element instanceof Method)) { - return false; - - } - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - return true; - } - - return false; - } - - @Override - public EventVO interceptStart(AnnotatedElement element) { - EventVO event = null; - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - boolean async = actionEvent.async(); - if(async){ - UserContext ctx = UserContext.current(); - long userId = ctx.getCallerUserId(); - long accountId = ctx.getAccountId(); - long startEventId = ctx.getStartEventId(); - String eventDescription = actionEvent.eventDescription(); - if(ctx.getEventDetails() != null){ - eventDescription += ". "+ctx.getEventDetails(); - } - ActionEventUtils.onStartedActionEvent(userId, accountId, actionEvent.eventType(), eventDescription, startEventId); - } - } - return event; - } - - @Override - public void interceptComplete(AnnotatedElement element, EventVO event) { - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - UserContext ctx = UserContext.current(); - long userId = ctx.getCallerUserId(); - long accountId = ctx.getAccountId(); - long startEventId = ctx.getStartEventId(); - String eventDescription = actionEvent.eventDescription(); - if(ctx.getEventDetails() != null){ - eventDescription += ". "+ctx.getEventDetails(); - } - if(actionEvent.create()){ - //This start event has to be used for subsequent events of this action - startEventId = ActionEventUtils.onCreatedActionEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully created entity for " + eventDescription); - ctx.setStartEventId(startEventId); - } else { - ActionEventUtils.onCompletedActionEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully completed " + eventDescription, startEventId); - } - } - } - - @Override - public void interceptException(AnnotatedElement element, EventVO event) { - Method method = (Method)element; - ActionEvent actionEvent = method.getAnnotation(ActionEvent.class); - if (actionEvent != null) { - UserContext ctx = UserContext.current(); - long userId = ctx.getCallerUserId(); - long accountId = ctx.getAccountId(); - long startEventId = ctx.getStartEventId(); - String eventDescription = actionEvent.eventDescription(); - if(ctx.getEventDetails() != null){ - eventDescription += ". "+ctx.getEventDetails(); - } - if(actionEvent.create()){ - long eventId = ActionEventUtils.onCreatedActionEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while creating entity for " + eventDescription); - ctx.setStartEventId(eventId); - } else { - ActionEventUtils.onCompletedActionEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while " + eventDescription, startEventId); - } - } - } - - @Override - public Callback getCallback() { - return this; - } - } } diff --git a/utils/src/com/cloud/utils/component/AnnotationInterceptor.java b/utils/src/com/cloud/utils/component/AnnotationInterceptor.java deleted file mode 100644 index e69862c9022..00000000000 --- a/utils/src/com/cloud/utils/component/AnnotationInterceptor.java +++ /dev/null @@ -1,36 +0,0 @@ -// 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 -// 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.utils.component; - -import java.lang.reflect.AnnotatedElement; - -import net.sf.cglib.proxy.Callback; - -/** - * AnnotationIntercepter says it can intercept an annotation. - */ -public interface AnnotationInterceptor { - boolean needToIntercept(AnnotatedElement element); - - T interceptStart(AnnotatedElement element); - - void interceptComplete(AnnotatedElement element, T attach); - - void interceptException(AnnotatedElement element, T attach); - - Callback getCallback(); -} diff --git a/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java b/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java deleted file mode 100644 index ea3b68573cf..00000000000 --- a/utils/src/com/cloud/utils/component/ComponentMethodProxyCache.java +++ /dev/null @@ -1,90 +0,0 @@ -// 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 -// 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.utils.component; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Method; -import java.util.WeakHashMap; - -public class ComponentMethodProxyCache { - - private static WeakHashMap> s_cache = new WeakHashMap>(); - - public ComponentMethodProxyCache() { - } - - public static Method getTargetMethod(Method method, Object target) { - synchronized(s_cache) { - WeakReference targetMethod = s_cache.get(new TargetKey(method, target)); - if(targetMethod != null && targetMethod.get() != null) - return targetMethod.get(); - - Class clazz = target.getClass(); - for(Method m : clazz.getMethods()) { - if(isMethodMatched(method, m)) { - s_cache.put(new TargetKey(method, target), new WeakReference(m)); - return m; - } - } - - return method; - } - } - - private static boolean isMethodMatched(Method m1, Method m2) { - if(!m1.getName().equals(m2.getName())) - return false; - - Class[] params1 = m1.getParameterTypes(); - Class[] params2 = m2.getParameterTypes(); - - if(params1.length != params2.length) - return false; - - for(int i = 0; i < params1.length; i++) { - if(!params1[i].isAssignableFrom(params2[i])) - return false; - } - - return true; - } - - public static class TargetKey { - Method _method; - Object _target; - - public TargetKey(Method method, Object target) { - _method = method; - _target = target; - } - - @Override - public boolean equals(Object obj) { - if(!(obj instanceof TargetKey)) - return false; - - // for target object, we just check the reference - return _method.equals(((TargetKey)obj)._method) && - _target == ((TargetKey)obj)._target; - } - - public int hashCode() { - return _target.hashCode() ^ _target.hashCode(); - } - } -} diff --git a/utils/src/com/cloud/utils/component/InterceptorLibrary.java b/utils/src/com/cloud/utils/component/InterceptorLibrary.java deleted file mode 100644 index 96be50b07ef..00000000000 --- a/utils/src/com/cloud/utils/component/InterceptorLibrary.java +++ /dev/null @@ -1,25 +0,0 @@ -// 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 -// 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.utils.component; - -import java.util.List; - -public interface InterceptorLibrary { - - void addInterceptors(List> interceptors); - -} diff --git a/utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.java b/utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.java deleted file mode 100644 index dd597344fa3..00000000000 --- a/utils/src/com/cloud/utils/component/MatchAnyMethodPointcut.java +++ /dev/null @@ -1,27 +0,0 @@ -// 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 -// 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.utils.component; - -import java.lang.reflect.Method; - -import org.springframework.aop.support.StaticMethodMatcherPointcut; - -public class MatchAnyMethodPointcut extends StaticMethodMatcherPointcut { - public boolean matches(Method method, Class cls) { - return true; - } -} diff --git a/utils/src/com/cloud/utils/db/DatabaseCallback.java b/utils/src/com/cloud/utils/db/DatabaseCallback.java deleted file mode 100644 index 718acf545c9..00000000000 --- a/utils/src/com/cloud/utils/db/DatabaseCallback.java +++ /dev/null @@ -1,84 +0,0 @@ -// 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 -// 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.utils.db; - -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; - -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.MethodInterceptor; -import net.sf.cglib.proxy.MethodProxy; - -import com.cloud.utils.component.AnnotationInterceptor; - -public class DatabaseCallback implements MethodInterceptor, AnnotationInterceptor { - - @Override - public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { - Transaction txn = interceptStart(method); - try { - return methodProxy.invokeSuper(object, args); - } finally { - interceptComplete(method, txn); - } - } - - @Override - public boolean needToIntercept(AnnotatedElement element) { - if (!(element instanceof Method)) { - return false; - - } - Method method = (Method)element; - DB db = method.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - - Class clazz = method.getDeclaringClass(); - do { - db = clazz.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - clazz = clazz.getSuperclass(); - } while (clazz != Object.class && clazz != null); - - return false; - } - - @Override - public Transaction interceptStart(AnnotatedElement element) { - return Transaction.open(((Method)element).getName()); - } - - @Override - public void interceptComplete(AnnotatedElement element, Transaction txn) { - txn.close(); - } - - @Override - public void interceptException(AnnotatedElement element, Transaction txn) { - txn.close(); - } - - @Override - public Callback getCallback() { - return this; - } - -} diff --git a/utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java b/utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java deleted file mode 100755 index 7bace706e29..00000000000 --- a/utils/src/com/cloud/utils/db/DatabaseCallbackFilter.java +++ /dev/null @@ -1,58 +0,0 @@ -// 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 -// 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.utils.db; - -import java.lang.reflect.Method; - -import net.sf.cglib.proxy.CallbackFilter; - -public class DatabaseCallbackFilter implements CallbackFilter { - @Override - public int accept(Method method) { - return checkAnnotation(method) ? 1 : 0; - } - - public static boolean checkAnnotation(Method method) { - /*Check self*/ - DB db = method.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - Class clazz = method.getDeclaringClass(); - - /*Check parent method*/ - try { - Method pMethod = clazz.getMethod(method.getName(), method.getParameterTypes()); - db = pMethod.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - } catch (SecurityException e) { - } catch (NoSuchMethodException e) { - } - - /*Check class's annotation and ancestor's annotation*/ - do { - db = clazz.getAnnotation(DB.class); - if (db != null) { - return db.txn(); - } - clazz = clazz.getSuperclass(); - } while (clazz != Object.class && clazz != null); - return false; - } -} From 2dbdc46337be375940441ac4b41f95f25bbbf21d Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati Date: Tue, 2 Apr 2013 11:07:41 -0700 Subject: [PATCH 039/120] CLOUDSTACK-1734: Make SHA1 default password encoding mechanism Description: Making SHA256SALT the default encoding algorithm to encode passwords when creating/updating users. Introducing a new configurable list to allow admins to separately configure the order of preference for encoding and authentication schemes. Since passwords are now sent by clients as clear text, fixing the Plain text authenticator to check against the password passed in rather than its md5 digest. --- .../admin/account/CreateAccountCmd.java | 2 +- .../api/command/admin/user/CreateUserCmd.java | 2 +- .../api/command/admin/user/UpdateUserCmd.java | 2 +- client/tomcatconf/applicationContext.xml.in | 54 +++++++++++++++++++ client/tomcatconf/componentContext.xml.in | 28 ---------- .../tomcatconf/nonossComponentContext.xml.in | 28 ---------- developer/developer-prefill.sql | 2 +- .../server/auth/LDAPUserAuthenticator.java | 5 +- .../server/auth/MD5UserAuthenticator.java | 4 ++ .../auth/PlainTextUserAuthenticator.java | 32 +++-------- .../auth/SHA256SaltedUserAuthenticator.java | 3 ++ .../cloud/server/ManagementServerImpl.java | 15 ++++-- .../com/cloud/user/AccountManagerImpl.java | 15 ++++-- 13 files changed, 99 insertions(+), 93 deletions(-) diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java index 89673ea6123..95d0d07d9ce 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/CreateAccountCmd.java @@ -63,7 +63,7 @@ public class CreateAccountCmd extends BaseCmd { @Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, required=true, description="lastname") private String lastName; - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Clear text password (Default hashed to SHA256SALT). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") private String password; @Parameter(name=ApiConstants.TIMEZONE, type=CommandType.STRING, description="Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.") diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java index fb29e1a2629..7b3f230d1ec 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/user/CreateUserCmd.java @@ -56,7 +56,7 @@ public class CreateUserCmd extends BaseCmd { @Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, required=true, description="lastname") private String lastname; - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Hashed password (Default is MD5). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="Clear text password (Default hashed to SHA256SALT). If you wish to use any other hashing algorithm, you would need to write a custom authentication adapter See Docs section.") private String password; @Parameter(name=ApiConstants.TIMEZONE, type=CommandType.STRING, description="Specifies a timezone for this command. For more information on the timezone parameter, see Time Zone Format.") diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java index 1f31662e8ca..5ea2dbdef55 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/user/UpdateUserCmd.java @@ -59,7 +59,7 @@ public class UpdateUserCmd extends BaseCmd { @Parameter(name=ApiConstants.LASTNAME, type=CommandType.STRING, description="last name") private String lastname; - @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="Hashed password (default is MD5). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter") + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="Clear text password (default hashed to SHA256SALT). If you wish to use any other hasing algorithm, you would need to write a custom authentication adapter") private String password; @Parameter(name=ApiConstants.SECRET_KEY, type=CommandType.STRING, description="The secret key for the user. Must be specified with userApiKey") diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 636eac2b939..d3699b93cfb 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -379,6 +379,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 0b02eb687c9..11472adf7b8 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -131,34 +131,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/developer/developer-prefill.sql b/developer/developer-prefill.sql index 6300d35df64..e4f90cad6e8 100644 --- a/developer/developer-prefill.sql +++ b/developer/developer-prefill.sql @@ -36,7 +36,7 @@ INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, -- Add system user with encrypted password=password INSERT INTO `cloud`.`user` (id, uuid, username, password, account_id, firstname, lastname, email, state, created) VALUES (2, UUID(), 'admin', '5f4dcc3b5aa765d61d8327deb882cf99', - '2', 'Admin', 'User', 'admin@mailprovider.com', 'enabled', NOW()); + '2', 'Admin', 'User', 'admin@mailprovider.com', 'disabled', NOW()); -- Add configurations INSERT INTO `cloud`.`configuration` (category, instance, component, name, value) diff --git a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java index 61eebe5fc93..d928a5b9e17 100644 --- a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java +++ b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java @@ -151,7 +151,10 @@ public class LDAPUserAuthenticator extends DefaultUserAuthenticator { @Override public boolean configure(String name, Map params) throws ConfigurationException { - super.configure(name, params); + if (name == null) { + name = "LDAP"; + } + super.configure(name, params); return true; } diff --git a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java index 026125ea0f6..e5b169fc456 100644 --- a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java +++ b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java @@ -59,8 +59,12 @@ public class MD5UserAuthenticator extends DefaultUserAuthenticator { return true; } + @Override public boolean configure(String name, Map params) throws ConfigurationException { + if(name == null) { + name = "MD5"; + } super.configure(name, params); return true; } diff --git a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java index 52e7cb3e297..f102275905f 100644 --- a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java +++ b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java @@ -28,7 +28,6 @@ import org.apache.log4j.Logger; import com.cloud.user.UserAccount; import com.cloud.user.dao.UserAccountDao; - import com.cloud.utils.exception.CloudRuntimeException; @@ -43,45 +42,26 @@ public class PlainTextUserAuthenticator extends DefaultUserAuthenticator { if (s_logger.isDebugEnabled()) { s_logger.debug("Retrieving user: " + username); } + UserAccount user = _userAccountDao.getUserAccount(username, domainId); if (user == null) { s_logger.debug("Unable to find user with " + username + " in domain " + domainId); return false; } - - MessageDigest md5; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new CloudRuntimeException("Error", e); - } - md5.reset(); - BigInteger pwInt = new BigInteger(1, md5.digest(password.getBytes())); - - // make sure our MD5 hash value is 32 digits long... - StringBuffer sb = new StringBuffer(); - String pwStr = pwInt.toString(16); - int padding = 32 - pwStr.length(); - for (int i = 0; i < padding; i++) { - sb.append('0'); - } - sb.append(pwStr); - - - // Will: The MD5Authenticator is now a straight pass-through comparison of the - // the passwords because we will not assume that the password passed in has - // already been MD5 hashed. I am keeping the above code in case this requirement changes - // or people need examples of how to MD5 hash passwords in java. - if (!user.getPassword().equals(sb.toString())) { + if (!user.getPassword().equals(password)) { s_logger.debug("Password does not match"); return false; } return true; } + @Override public boolean configure(String name, Map params) throws ConfigurationException { + if (name == null) { + name = "PLAINTEXT"; + } super.configure(name, params); return true; } diff --git a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java index 1b29f69794a..da939273ea1 100644 --- a/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java +++ b/plugins/user-authenticators/sha256salted/src/com/cloud/server/auth/SHA256SaltedUserAuthenticator.java @@ -44,6 +44,9 @@ public class SHA256SaltedUserAuthenticator extends DefaultUserAuthenticator { @Override public boolean configure(String name, Map params) throws ConfigurationException { + if (name == null) { + name = "SHA256SALT"; + } super.configure(name, params); return true; } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index d0904e1049c..af77ba5645f 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -457,7 +457,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe private Map _availableIdsMap; - List _userAuthenticators; + private List _userAuthenticators; + private List _userPasswordEncoders; @Inject ClusterManager _clusterMgr; private String _hashKey = null; @@ -473,7 +474,15 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe public void setUserAuthenticators(List authenticators) { _userAuthenticators = authenticators; } - + + public List getUserPasswordEncoders() { + return _userPasswordEncoders; + } + + public void setUserPasswordEncoders(List encoders) { + _userPasswordEncoders = encoders; + } + public List getHostAllocators() { return _hostAllocators; } @@ -3342,7 +3351,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe // This means its a new account, set the password using the // authenticator - for (UserAuthenticator authenticator: _userAuthenticators) { + for (UserAuthenticator authenticator: _userPasswordEncoders) { encodedPassword = authenticator.encode(password); if (encodedPassword != null) { break; diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 40db4ed2f86..52ca79d5a60 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -222,6 +222,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Inject VolumeManager volumeMgr; private List _userAuthenticators; + List _userPasswordEncoders; private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AccountChecker")); @@ -241,7 +242,15 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M public void setUserAuthenticators(List authenticators) { _userAuthenticators = authenticators; } - + + public List getUserPasswordEncoders() { + return _userPasswordEncoders; + } + + public void setUserPasswordEncoders(List encoders) { + _userPasswordEncoders = encoders; + } + public List getSecurityCheckers() { return _securityCheckers; } @@ -947,7 +956,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M if (password != null) { String encodedPassword = null; - for (Iterator en = _userAuthenticators.iterator(); en.hasNext();) { + for (Iterator en = _userPasswordEncoders.iterator(); en.hasNext();) { UserAuthenticator authenticator = en.next(); encodedPassword = authenticator.encode(password); if (encodedPassword != null) { @@ -1733,7 +1742,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } String encodedPassword = null; - for (UserAuthenticator authenticator : _userAuthenticators) { + for (UserAuthenticator authenticator : _userPasswordEncoders) { encodedPassword = authenticator.encode(password); if (encodedPassword != null) { break; From 04a511a1a828a829962681525780f80935a161f9 Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Tue, 2 Apr 2013 23:29:24 -0600 Subject: [PATCH 040/120] CLOUDSTACK-1900 : Save a default db.properties during upgrade, and make sure we only pull the old configs once. Signed-off-by: Marcus Sorensen 1364966964 -0600 --- packaging/centos63/cloud.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packaging/centos63/cloud.spec b/packaging/centos63/cloud.spec index 7d6e63880b1..5baf58f9fb5 100644 --- a/packaging/centos63/cloud.spec +++ b/packaging/centos63/cloud.spec @@ -363,9 +363,12 @@ if getent passwd cloud | grep -q /var/lib/cloud; then fi # if saved configs from upgrade exist, copy them over -if [ -d "%{_sysconfdir}/cloud.rpmsave/management" ]; then +if [ -f "%{_sysconfdir}/cloud.rpmsave/management/db.properties" ]; then + mv %{_sysconfdir}/%{name}/management/db.properties %{_sysconfdir}/%{name}/management/db.properties.rpmnew cp -p %{_sysconfdir}/cloud.rpmsave/management/db.properties %{_sysconfdir}/%{name}/management cp -p %{_sysconfdir}/cloud.rpmsave/management/key %{_sysconfdir}/%{name}/management + # make sure we only do this on the first install of this RPM, don't want to overwrite on a reinstall + mv %{_sysconfdir}/cloud.rpmsave/management/db.properties %{_sysconfdir}/cloud.rpmsave/management/db.properties.rpmsave fi # Choose server.xml and tomcat.conf links based on old config, if exists @@ -407,6 +410,8 @@ fi if [ -f "%{_sysconfdir}/cloud.rpmsave/agent/agent.properties" ]; then mv %{_sysconfdir}/%{name}/agent/agent.properties %{_sysconfdir}/%{name}/agent/agent.properties.rpmnew cp -p %{_sysconfdir}/cloud.rpmsave/agent/agent.properties %{_sysconfdir}/%{name}/agent + # make sure we only do this on the first install of this RPM, don't want to overwrite on a reinstall + mv %{_sysconfdir}/cloud.rpmsave/agent/agent.properties %{_sysconfdir}/cloud.rpmsave/agent/agent.properties.rpmsave fi #%post awsapi From 8bb28fd7134626b3a967474abf3ae418aace72be Mon Sep 17 00:00:00 2001 From: Hugo Trippaers Date: Wed, 3 Apr 2013 08:35:39 +0200 Subject: [PATCH 041/120] With commit 16216720c6e981af4860ba83426b5ce91de1dc81 autoscanning is removed so Nicira needs to be properly added to the componentContext --- client/tomcatconf/componentContext.xml.in | 17 +++++++++++++++++ client/tomcatconf/nonossComponentContext.xml.in | 7 +++++++ 2 files changed, 24 insertions(+) diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 18d21c0a758..51980c912af 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -140,6 +140,7 @@ + @@ -148,6 +149,7 @@ + + + + + + + + + + + + diff --git a/client/tomcatconf/nonossComponentContext.xml.in b/client/tomcatconf/nonossComponentContext.xml.in index 11472adf7b8..a9418d73882 100644 --- a/client/tomcatconf/nonossComponentContext.xml.in +++ b/client/tomcatconf/nonossComponentContext.xml.in @@ -78,6 +78,10 @@ + + @@ -230,6 +234,7 @@ + @@ -238,6 +243,7 @@ + @@ -275,6 +281,7 @@ + From bca7f9df5f6936c4ed95694970779303502f6eec Mon Sep 17 00:00:00 2001 From: Gavin Lee Date: Wed, 3 Apr 2013 16:57:42 +0800 Subject: [PATCH 042/120] CLOUDSTACK-1596: Choosing a hypervisor matrix to xml and add to Install Guide --- docs/en-US/Installation_Guide.xml | 1 + docs/en-US/choosing-a-hypervisor.xml | 136 +++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 docs/en-US/choosing-a-hypervisor.xml diff --git a/docs/en-US/Installation_Guide.xml b/docs/en-US/Installation_Guide.xml index fed53fc4a1d..28df071d42f 100644 --- a/docs/en-US/Installation_Guide.xml +++ b/docs/en-US/Installation_Guide.xml @@ -50,6 +50,7 @@ + diff --git a/docs/en-US/choosing-a-hypervisor.xml b/docs/en-US/choosing-a-hypervisor.xml new file mode 100644 index 00000000000..3c654881329 --- /dev/null +++ b/docs/en-US/choosing-a-hypervisor.xml @@ -0,0 +1,136 @@ + +%BOOK_ENTITIES; +]> + + + + Choosing a Hypervisor: Supported Features + &PRODUCT; supports many popular hypervisors. Your cloud can consist entirely of hosts running a single hypervisor, or you can use multiple hypervisors. Each cluster of hosts must run the same hypervisor. + You might already have an installed base of nodes running a particular hypervisor, in which case, your choice of hypervisor has already been made. If you are starting from scratch, you need to decide what hypervisor software best suits your needs. A discussion of the relative advantages of each hypervisor is outside the scope of our documentation. However, it will help you to know which features of each hypervisor are supported by &PRODUCT;. The following table provides this information. + + + + + + + + + + + + Feature + XenServer 6.0.2 + vSphere 4.1/5.0 + KVM - RHEL 6.2 + OVM 2.3 + Bare Metal + + + + + Network Throttling + Yes + Yes + No + No + N/A + + + Security groups in zones that use basic networking + Yes + No + Yes + No + No + + + iSCSI + Yes + Yes + Yes + Yes + N/A + + + FibreChannel + Yes + Yes + Yes + No + N/A + + + Local Disk + Yes + Yes + Yes + No + Yes + + + HA + Yes + Yes (Native) + Yes + Yes + N/A + + + Snapshots of local disk + Yes + Yes + Yes + No + N/A + + + Local disk as data disk + No + No + No + No + N/A + + + Work load balancing + No + DRS + No + No + N/A + + + Manual live migration of VMs from host to host + Yes + Yes + Yes + Yes + N/A + + + Conserve management traffic IP address by using link local network to communicate with virtual router + Yes + No + Yes + Yes + N/A + + + + + From 213c163011c1e783229997ffe857303d2022f3ed Mon Sep 17 00:00:00 2001 From: Gavin Lee Date: Wed, 3 Apr 2013 17:26:37 +0800 Subject: [PATCH 043/120] Convert tab to space chars --- docs/en-US/choosing-a-hypervisor.xml | 218 +++++++++++++-------------- 1 file changed, 109 insertions(+), 109 deletions(-) diff --git a/docs/en-US/choosing-a-hypervisor.xml b/docs/en-US/choosing-a-hypervisor.xml index 3c654881329..bf83fe3d17f 100644 --- a/docs/en-US/choosing-a-hypervisor.xml +++ b/docs/en-US/choosing-a-hypervisor.xml @@ -23,114 +23,114 @@ &PRODUCT; supports many popular hypervisors. Your cloud can consist entirely of hosts running a single hypervisor, or you can use multiple hypervisors. Each cluster of hosts must run the same hypervisor. You might already have an installed base of nodes running a particular hypervisor, in which case, your choice of hypervisor has already been made. If you are starting from scratch, you need to decide what hypervisor software best suits your needs. A discussion of the relative advantages of each hypervisor is outside the scope of our documentation. However, it will help you to know which features of each hypervisor are supported by &PRODUCT;. The following table provides this information. - - - - - - - - - - - Feature - XenServer 6.0.2 - vSphere 4.1/5.0 - KVM - RHEL 6.2 - OVM 2.3 - Bare Metal - - - - - Network Throttling - Yes - Yes - No - No - N/A - - - Security groups in zones that use basic networking - Yes - No - Yes - No - No - - - iSCSI - Yes - Yes - Yes - Yes - N/A - - - FibreChannel - Yes - Yes - Yes - No - N/A - - - Local Disk - Yes - Yes - Yes - No - Yes - - - HA - Yes - Yes (Native) - Yes - Yes - N/A - - - Snapshots of local disk - Yes - Yes - Yes - No - N/A - - - Local disk as data disk - No - No - No - No - N/A - - - Work load balancing - No - DRS - No - No - N/A - - - Manual live migration of VMs from host to host - Yes - Yes - Yes - Yes - N/A - - - Conserve management traffic IP address by using link local network to communicate with virtual router - Yes - No - Yes - Yes - N/A - - - + + + + + + + + + + + Feature + XenServer 6.0.2 + vSphere 4.1/5.0 + KVM - RHEL 6.2 + OVM 2.3 + Bare Metal + + + + + Network Throttling + Yes + Yes + No + No + N/A + + + Security groups in zones that use basic networking + Yes + No + Yes + No + No + + + iSCSI + Yes + Yes + Yes + Yes + N/A + + + FibreChannel + Yes + Yes + Yes + No + N/A + + + Local Disk + Yes + Yes + Yes + No + Yes + + + HA + Yes + Yes (Native) + Yes + Yes + N/A + + + Snapshots of local disk + Yes + Yes + Yes + No + N/A + + + Local disk as data disk + No + No + No + No + N/A + + + Work load balancing + No + DRS + No + No + N/A + + + Manual live migration of VMs from host to host + Yes + Yes + Yes + Yes + N/A + + + Conserve management traffic IP address by using link local network to communicate with virtual router + Yes + No + Yes + Yes + N/A + + + From d392445f7e9adab7d6effd4daf0d76bb0e6f9bd9 Mon Sep 17 00:00:00 2001 From: Dave Cahill Date: Wed, 13 Mar 2013 17:27:09 +0900 Subject: [PATCH 044/120] Rename MidoNetElement and MidoNetGuestNetworkGuru - Creating this as a separate commit so that it is marked as a rename - Over 50% code changed, so would count as a delete and add otherwise Signed-off-by: Dave Cahill Signed-off-by: Hugo Trippaers --- .../src/com/cloud/network/element/MidoNetElement.java} | 0 .../src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename plugins/network-elements/{midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java => midonet/src/com/cloud/network/element/MidoNetElement.java} (100%) rename plugins/network-elements/{midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java => midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java} (100%) diff --git a/plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java b/plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java similarity index 100% rename from plugins/network-elements/midokura-midonet/src/com/cloud/network/element/MidokuraMidonetElement.java rename to plugins/network-elements/midonet/src/com/cloud/network/element/MidoNetElement.java diff --git a/plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java b/plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java similarity index 100% rename from plugins/network-elements/midokura-midonet/src/com/cloud/network/guru/MidokuraMidonetGuestNetworkGuru.java rename to plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetGuestNetworkGuru.java From eddf7b9357bc18497b8cb16a6c6f3382ac52f61c Mon Sep 17 00:00:00 2001 From: Dave Cahill Date: Mon, 25 Mar 2013 10:56:13 +0900 Subject: [PATCH 045/120] MidoNet Networking Plugin - Supports DHCP, Source NAT, Static NAT, Firewall rules, Port Forwarding - Renamed MidokuraMidonet to MidoNet - Related Jira ticket is CLOUDSTACK-996 Signed-off-by: Dave Cahill Signed-off-by: Hugo Trippaers --- api/src/com/cloud/network/Network.java | 3 +- api/src/com/cloud/network/Networks.java | 1 + .../com/cloud/network/PhysicalNetwork.java | 3 +- .../network/ExternalNetworkDeviceManager.java | 1 - client/pom.xml | 5 + .../kvm/resource/LibvirtDomainXMLParser.java | 3 + .../hypervisor/kvm/resource/LibvirtVMDef.java | 11 +- .../network-elements/midokura-midonet/pom.xml | 30 - plugins/network-elements/midonet/pom.xml | 66 + .../cloud/network/element/MidoNetElement.java | 1622 ++++++++++++++++- .../network/element/SimpleFirewallRule.java | 192 ++ .../network/guru/MidoNetGuestNetworkGuru.java | 144 +- .../guru/MidoNetPublicNetworkGuru.java | 223 +++ .../network/resource/MidoNetVifDriver.java | 179 ++ .../network/element/MidoNetElementTest.java | 178 ++ plugins/pom.xml | 1 + .../src/com/cloud/configuration/Config.java | 4 + .../com/cloud/network/NetworkManagerImpl.java | 20 + ui/scripts/system.js | 114 ++ 19 files changed, 2720 insertions(+), 80 deletions(-) delete mode 100644 plugins/network-elements/midokura-midonet/pom.xml create mode 100644 plugins/network-elements/midonet/pom.xml create mode 100644 plugins/network-elements/midonet/src/com/cloud/network/element/SimpleFirewallRule.java create mode 100644 plugins/network-elements/midonet/src/com/cloud/network/guru/MidoNetPublicNetworkGuru.java create mode 100644 plugins/network-elements/midonet/src/com/cloud/network/resource/MidoNetVifDriver.java create mode 100644 plugins/network-elements/midonet/test/com/cloud/network/element/MidoNetElementTest.java diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index c2ab655b103..c0b0117fc7e 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -136,8 +136,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Provider VPCVirtualRouter = new Provider("VpcVirtualRouter", false); public static final Provider None = new Provider("None", false); // NiciraNvp is not an "External" provider, otherwise we get in trouble with NetworkServiceImpl.providersConfiguredForExternalNetworking - public static final Provider NiciraNvp = new Provider("NiciraNvp", false); - public static final Provider MidokuraMidonet = new Provider("MidokuraMidonet", true); + public static final Provider NiciraNvp = new Provider("NiciraNvp", false); private String name; private boolean isExternal; diff --git a/api/src/com/cloud/network/Networks.java b/api/src/com/cloud/network/Networks.java index e3d21584ad8..f085e9f3029 100755 --- a/api/src/com/cloud/network/Networks.java +++ b/api/src/com/cloud/network/Networks.java @@ -62,6 +62,7 @@ public class Networks { Vnet("vnet", Long.class), Storage("storage", Integer.class), Lswitch("lswitch", String.class), + Mido("mido", String.class), UnDecided(null, null); private String scheme; diff --git a/api/src/com/cloud/network/PhysicalNetwork.java b/api/src/com/cloud/network/PhysicalNetwork.java index 343a2b14e33..a2044a61047 100644 --- a/api/src/com/cloud/network/PhysicalNetwork.java +++ b/api/src/com/cloud/network/PhysicalNetwork.java @@ -36,7 +36,8 @@ public interface PhysicalNetwork extends Identity, InternalIdentity { L3, GRE, STT, - VNS; + VNS, + MIDO; } public enum BroadcastDomainRange { diff --git a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java index bc22804ae06..aeed81d2011 100644 --- a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java +++ b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java @@ -43,7 +43,6 @@ public interface ExternalNetworkDeviceManager extends Manager { public static final NetworkDevice F5BigIpLoadBalancer = new NetworkDevice("F5BigIpLoadBalancer", Network.Provider.F5BigIp.getName()); public static final NetworkDevice JuniperSRXFirewall = new NetworkDevice("JuniperSRXFirewall", Network.Provider.JuniperSRX.getName()); public static final NetworkDevice NiciraNvp = new NetworkDevice("NiciraNvp", Network.Provider.NiciraNvp.getName()); - public static final NetworkDevice MidokuraMidonet = new NetworkDevice("MidokuraMidonet", Network.Provider.MidokuraMidonet.getName()); public NetworkDevice(String deviceName, String ntwkServiceprovider) { _name = deviceName; diff --git a/client/pom.xml b/client/pom.xml index 05934f4db17..ff861b778d7 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -80,6 +80,11 @@ cloud-plugin-network-vns ${project.version} + + org.apache.cloudstack + cloud-plugin-network-midonet + ${project.version} + org.apache.cloudstack cloud-plugin-hypervisor-xen diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java index 403ed379c9f..ac4baf122a9 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtDomainXMLParser.java @@ -111,6 +111,9 @@ public class LibvirtDomainXMLParser { String bridge = getAttrValue("source", "bridge", nic); def.defBridgeNet(bridge, dev, mac, nicModel.valueOf(model.toUpperCase())); + } else if (type.equalsIgnoreCase("ethernet")) { + String scriptPath = getAttrValue("script", "path", nic); + def.defEthernet(dev, mac, nicModel.valueOf(model.toUpperCase()), scriptPath); } interfaces.add(def); } diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java index 63133a8440f..9cddb2e4323 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java @@ -711,13 +711,19 @@ public class LibvirtVMDef { _model = model; } - public void defEthernet(String targetName, String macAddr, nicModel model) { + public void defEthernet(String targetName, String macAddr, nicModel model, String scriptPath) { _netType = guestNetType.ETHERNET; _networkName = targetName; + _sourceName = targetName; _macAddr = macAddr; _model = model; + _scriptPath = scriptPath; } + public void defEthernet(String targetName, String macAddr, nicModel model) { + defEthernet(targetName, macAddr, model, null); + } + public void setHostNetType(hostNicType hostNetType) { _hostNetType = hostNetType; } @@ -790,6 +796,9 @@ public class LibvirtVMDef { if (_model != null) { netBuilder.append("\n"); } + if (_scriptPath != null) { + netBuilder.append("