diff --git a/api/src/com/cloud/domain/Domain.java b/api/src/com/cloud/domain/Domain.java index 99af533cbc7..f8277c2cd28 100644 --- a/api/src/com/cloud/domain/Domain.java +++ b/api/src/com/cloud/domain/Domain.java @@ -59,4 +59,8 @@ public interface Domain extends OwnedBy, Identity, InternalIdentity { void setState(State state); String getNetworkDomain(); + + public String getUuid(); + + int getRegionId(); } diff --git a/api/src/com/cloud/event/EventCategory.java b/api/src/com/cloud/event/EventCategory.java new file mode 100644 index 00000000000..cee6529b550 --- /dev/null +++ b/api/src/com/cloud/event/EventCategory.java @@ -0,0 +1,55 @@ +/* + * 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.event; + +import java.util.ArrayList; +import java.util.List; + +public class EventCategory { + private static List eventCategories = new ArrayList(); + private String eventCategoryName; + + public EventCategory(String categoryName) { + this.eventCategoryName = categoryName; + eventCategories.add(this); + } + + public String getName() { + return eventCategoryName; + } + + public static List listAllEventCategories() { + return eventCategories; + } + + public static EventCategory getEventCategory(String categoryName) { + for (EventCategory category : eventCategories) { + if (category.getName().equalsIgnoreCase(categoryName)) { + return category; + } + } + return null; + } + + public static final EventCategory ACTION_EVENT = new EventCategory("ActionEvent"); + public static final EventCategory ALERT_EVENT = new EventCategory("AlertEvent"); + public static final EventCategory USAGE_EVENT = new EventCategory("UsageEvent"); + public static final EventCategory RESOURCE_STATE_CHANGE_EVENT = new EventCategory("ResourceStateEvent"); +} diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index d666c1e4130..0dd97cb438c 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -16,7 +16,41 @@ // under the License. package com.cloud.event; +import com.cloud.configuration.Configuration; +import com.cloud.dc.DataCenter; +import com.cloud.dc.Pod; +import com.cloud.dc.StorageNetworkIpRange; +import com.cloud.dc.Vlan; +import com.cloud.domain.Domain; +import com.cloud.host.Host; +import com.cloud.network.*; +import com.cloud.network.as.*; +import com.cloud.network.router.VirtualRouter; +import com.cloud.network.rules.LoadBalancer; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.security.SecurityGroup; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.Vpc; +import com.cloud.offering.DiskOffering; +import com.cloud.offering.NetworkOffering; +import com.cloud.offering.ServiceOffering; +import com.cloud.projects.Project; +import com.cloud.storage.Snapshot; +import com.cloud.storage.Volume; +import com.cloud.template.VirtualMachineTemplate; +import com.cloud.user.Account; +import com.cloud.user.User; +import com.cloud.vm.VirtualMachine; + +import java.util.HashMap; +import java.util.Map; + public class EventTypes { + + //map of Event and corresponding entity for which Event is applicable + private static Map entityEventDetails = null; + // VM Events public static final String EVENT_VM_CREATE = "VM.CREATE"; public static final String EVENT_VM_DESTROY = "VM.DESTROY"; @@ -319,10 +353,323 @@ public class EventTypes { public static final String EVENT_AUTOSCALEVMGROUP_UPDATE = "AUTOSCALEVMGROUP.UPDATE"; public static final String EVENT_AUTOSCALEVMGROUP_ENABLE = "AUTOSCALEVMGROUP.ENABLE"; public static final String EVENT_AUTOSCALEVMGROUP_DISABLE = "AUTOSCALEVMGROUP.DISABLE"; - + + public static final String EVENT_BAREMETAL_DHCP_SERVER_ADD = "PHYSICAL.DHCP.ADD"; public static final String EVENT_BAREMETAL_DHCP_SERVER_DELETE = "PHYSICAL.DHCP.DELETE"; - public static final String EVENT_BAREMETAL_PXE_SERVER_ADD = "PHYSICAL.PXE.ADD"; public static final String EVENT_BAREMETAL_PXE_SERVER_DELETE = "PHYSICAL.PXE.DELETE"; + + static { + + // TODO: need a way to force author adding event types to declare the entity details as well, with out braking + // current ActionEvent annotation semantics + + entityEventDetails = new HashMap(); + + entityEventDetails.put(EVENT_VM_CREATE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_DESTROY, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_START, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_STOP, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_REBOOT, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_UPDATE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_UPGRADE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_RESETPASSWORD, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_MIGRATE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_MOVE, VirtualMachine.class.getName()); + entityEventDetails.put(EVENT_VM_RESTORE, VirtualMachine.class.getName()); + + entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class.getName()); + entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class.getName()); + entityEventDetails.put(EVENT_ROUTER_START, VirtualRouter.class.getName()); + entityEventDetails.put(EVENT_ROUTER_STOP, VirtualRouter.class.getName()); + entityEventDetails.put(EVENT_ROUTER_REBOOT, VirtualRouter.class.getName()); + entityEventDetails.put(EVENT_ROUTER_HA, VirtualRouter.class.getName()); + entityEventDetails.put(EVENT_ROUTER_UPGRADE, VirtualRouter.class.getName()); + + entityEventDetails.put(EVENT_PROXY_CREATE, "ConsoleProxy"); + entityEventDetails.put(EVENT_PROXY_DESTROY, "ConsoleProxy"); + entityEventDetails.put(EVENT_PROXY_START, "ConsoleProxy"); + entityEventDetails.put(EVENT_PROXY_STOP, "ConsoleProxy"); + entityEventDetails.put(EVENT_PROXY_REBOOT, "ConsoleProxy"); + entityEventDetails.put(EVENT_ROUTER_HA, "ConsoleProxy"); + entityEventDetails.put(EVENT_PROXY_HA, "ConsoleProxy"); + + entityEventDetails.put(EVENT_VNC_CONNECT, "VNC"); + entityEventDetails.put(EVENT_VNC_DISCONNECT, "VNC"); + + // Network Events + entityEventDetails.put(EVENT_NETWORK_CREATE, Network.class.getName()); + entityEventDetails.put(EVENT_NETWORK_DELETE, Network.class.getName()); + entityEventDetails.put(EVENT_NETWORK_UPDATE, Network.class.getName()); + entityEventDetails.put(EVENT_NETWORK_RESTART, Network.class.getName()); + entityEventDetails.put(EVENT_NET_IP_ASSIGN, PublicIpAddress.class.getName()); + entityEventDetails.put(EVENT_NET_IP_RELEASE, PublicIpAddress.class.getName()); + entityEventDetails.put(EVENT_NET_RULE_ADD, Network.class.getName()); + entityEventDetails.put(EVENT_NET_RULE_DELETE, Network.class.getName()); + entityEventDetails.put(EVENT_NET_RULE_MODIFY, Network.class.getName()); + entityEventDetails.put(EVENT_FIREWALL_OPEN, Network.class.getName()); + entityEventDetails.put(EVENT_FIREWALL_CLOSE, Network.class.getName()); + + // Load Balancers + entityEventDetails.put(EVENT_ASSIGN_TO_LOAD_BALANCER_RULE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_REMOVE_FROM_LOAD_BALANCER_RULE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LOAD_BALANCER_CREATE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LOAD_BALANCER_DELETE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LB_STICKINESSPOLICY_CREATE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LB_STICKINESSPOLICY_DELETE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LOAD_BALANCER_UPDATE, LoadBalancer.class.getName()); + + // Account events + entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class.getName()); + entityEventDetails.put(EVENT_ACCOUNT_CREATE, Account.class.getName()); + entityEventDetails.put(EVENT_ACCOUNT_DELETE, Account.class.getName()); + entityEventDetails.put(EVENT_ACCOUNT_MARK_DEFAULT_ZONE, Account.class.getName()); + + // UserVO Events + entityEventDetails.put(EVENT_USER_LOGIN, User.class.getName()); + entityEventDetails.put(EVENT_USER_LOGOUT, User.class.getName()); + entityEventDetails.put(EVENT_USER_CREATE, User.class.getName()); + entityEventDetails.put(EVENT_USER_DELETE, User.class.getName()); + entityEventDetails.put(EVENT_USER_DISABLE, User.class.getName()); + entityEventDetails.put(EVENT_USER_UPDATE, User.class.getName()); + entityEventDetails.put(EVENT_USER_ENABLE, User.class.getName()); + entityEventDetails.put(EVENT_USER_LOCK, User.class.getName()); + + // Template Events + entityEventDetails.put(EVENT_TEMPLATE_CREATE, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_DELETE, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_UPDATE, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_DOWNLOAD_START, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_DOWNLOAD_SUCCESS, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_DOWNLOAD_FAILED, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_COPY, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_EXTRACT, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_UPLOAD, VirtualMachineTemplate.class.getName()); + entityEventDetails.put(EVENT_TEMPLATE_CLEANUP, VirtualMachineTemplate.class.getName()); + + // Volume Events + entityEventDetails.put(EVENT_VOLUME_CREATE, Volume.class.getName()); + entityEventDetails.put(EVENT_VOLUME_DELETE, Volume.class.getName()); + entityEventDetails.put(EVENT_VOLUME_ATTACH, Volume.class.getName()); + entityEventDetails.put(EVENT_VOLUME_DETACH, Volume.class.getName()); + entityEventDetails.put(EVENT_VOLUME_EXTRACT, Volume.class.getName()); + entityEventDetails.put(EVENT_VOLUME_UPLOAD, Volume.class.getName()); + entityEventDetails.put(EVENT_VOLUME_MIGRATE, Volume.class.getName()); + entityEventDetails.put(EVENT_VOLUME_RESIZE, Volume.class.getName()); + + // Domains + entityEventDetails.put(EVENT_DOMAIN_CREATE, Domain.class.getName()); + entityEventDetails.put(EVENT_DOMAIN_DELETE, Domain.class.getName()); + entityEventDetails.put(EVENT_DOMAIN_UPDATE, Domain.class.getName()); + + // Snapshots + entityEventDetails.put(EVENT_SNAPSHOT_CREATE, Snapshot.class.getName()); + entityEventDetails.put(EVENT_SNAPSHOT_DELETE, Snapshot.class.getName()); + entityEventDetails.put(EVENT_SNAPSHOT_POLICY_CREATE, Snapshot.class.getName()); + entityEventDetails.put(EVENT_SNAPSHOT_POLICY_UPDATE, Snapshot.class.getName()); + entityEventDetails.put(EVENT_SNAPSHOT_POLICY_DELETE, Snapshot.class.getName()); + + // ISO + entityEventDetails.put(EVENT_ISO_CREATE, "Iso"); + entityEventDetails.put(EVENT_ISO_DELETE, "Iso"); + entityEventDetails.put(EVENT_ISO_COPY, "Iso"); + entityEventDetails.put(EVENT_ISO_ATTACH, "Iso"); + entityEventDetails.put(EVENT_ISO_DETACH, "Iso"); + entityEventDetails.put(EVENT_ISO_EXTRACT, "Iso"); + entityEventDetails.put(EVENT_ISO_UPLOAD, "Iso"); + + // SSVM + entityEventDetails.put(EVENT_SSVM_CREATE, "SecondaryStorageVm"); + entityEventDetails.put(EVENT_SSVM_DESTROY, "SecondaryStorageVm"); + entityEventDetails.put(EVENT_SSVM_START, "SecondaryStorageVm"); + entityEventDetails.put(EVENT_SSVM_STOP, "SecondaryStorageVm"); + entityEventDetails.put(EVENT_SSVM_REBOOT, "SecondaryStorageVm"); + entityEventDetails.put(EVENT_SSVM_HA, "SecondaryStorageVm"); + + // Service Offerings + entityEventDetails.put(EVENT_SERVICE_OFFERING_CREATE, ServiceOffering.class.getName()); + entityEventDetails.put(EVENT_SERVICE_OFFERING_EDIT, ServiceOffering.class.getName()); + entityEventDetails.put(EVENT_SERVICE_OFFERING_DELETE, ServiceOffering.class.getName()); + + // Disk Offerings + entityEventDetails.put(EVENT_DISK_OFFERING_CREATE, DiskOffering.class.getName()); + entityEventDetails.put(EVENT_DISK_OFFERING_EDIT, DiskOffering.class.getName()); + entityEventDetails.put(EVENT_DISK_OFFERING_DELETE, DiskOffering.class.getName()); + + // Network offerings + entityEventDetails.put(EVENT_NETWORK_OFFERING_CREATE, NetworkOffering.class.getName()); + entityEventDetails.put(EVENT_NETWORK_OFFERING_ASSIGN, NetworkOffering.class.getName()); + entityEventDetails.put(EVENT_NETWORK_OFFERING_EDIT, NetworkOffering.class.getName()); + entityEventDetails.put(EVENT_NETWORK_OFFERING_REMOVE, NetworkOffering.class.getName()); + entityEventDetails.put(EVENT_NETWORK_OFFERING_DELETE, NetworkOffering.class.getName()); + + // Pods + entityEventDetails.put(EVENT_POD_CREATE, Pod.class.getName()); + entityEventDetails.put(EVENT_POD_EDIT, Pod.class.getName()); + entityEventDetails.put(EVENT_POD_DELETE, Pod.class.getName()); + + // Zones + entityEventDetails.put(EVENT_ZONE_CREATE, DataCenter.class.getName()); + entityEventDetails.put(EVENT_ZONE_EDIT, DataCenter.class.getName()); + entityEventDetails.put(EVENT_ZONE_DELETE, DataCenter.class.getName()); + + // VLANs/IP ranges + entityEventDetails.put(EVENT_VLAN_IP_RANGE_CREATE, Vlan.class.getName()); + entityEventDetails.put(EVENT_VLAN_IP_RANGE_DELETE,Vlan.class.getName()); + + entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class.getName()); + entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class.getName()); + entityEventDetails.put(EVENT_STORAGE_IP_RANGE_UPDATE, StorageNetworkIpRange.class.getName()); + + // Configuration Table + entityEventDetails.put(EVENT_CONFIGURATION_VALUE_EDIT, Configuration.class.getName()); + + // Security Groups + entityEventDetails.put(EVENT_SECURITY_GROUP_AUTHORIZE_INGRESS, SecurityGroup.class.getName()); + entityEventDetails.put(EVENT_SECURITY_GROUP_REVOKE_INGRESS, SecurityGroup.class.getName()); + entityEventDetails.put(EVENT_SECURITY_GROUP_AUTHORIZE_EGRESS, SecurityGroup.class.getName()); + entityEventDetails.put(EVENT_SECURITY_GROUP_REVOKE_EGRESS, SecurityGroup.class.getName()); + entityEventDetails.put(EVENT_SECURITY_GROUP_CREATE, SecurityGroup.class.getName()); + entityEventDetails.put(EVENT_SECURITY_GROUP_DELETE, SecurityGroup.class.getName()); + entityEventDetails.put(EVENT_SECURITY_GROUP_ASSIGN, SecurityGroup.class.getName()); + entityEventDetails.put(EVENT_SECURITY_GROUP_REMOVE, SecurityGroup.class.getName()); + + // Host + entityEventDetails.put(EVENT_HOST_RECONNECT, Host.class.getName()); + + // Maintenance + entityEventDetails.put(EVENT_MAINTENANCE_CANCEL, Host.class.getName()); + entityEventDetails.put(EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE, Host.class.getName()); + entityEventDetails.put(EVENT_MAINTENANCE_PREPARE, Host.class.getName()); + entityEventDetails.put(EVENT_MAINTENANCE_PREPARE_PRIMARY_STORAGE, Host.class.getName()); + + // VPN + entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_CREATE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_DESTROY, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_VPN_USER_ADD, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_VPN_USER_REMOVE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_GATEWAY_CREATE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_GATEWAY_DELETE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_DELETE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_UPDATE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_CREATE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_DELETE, RemoteAccessVpn.class.getName()); + entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_RESET, RemoteAccessVpn.class.getName()); + + // Custom certificates + entityEventDetails.put(EVENT_UPLOAD_CUSTOM_CERTIFICATE, "Certificate"); + + // OneToOnenat + entityEventDetails.put(EVENT_ENABLE_STATIC_NAT, StaticNat.class.getName()); + entityEventDetails.put(EVENT_DISABLE_STATIC_NAT, StaticNat.class.getName()); + + entityEventDetails.put(EVENT_ZONE_VLAN_ASSIGN,Vlan.class.getName()); + entityEventDetails.put(EVENT_ZONE_VLAN_RELEASE,Vlan.class.getName()); + + // Projects + entityEventDetails.put(EVENT_PROJECT_CREATE, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_UPDATE, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_DELETE, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_ACTIVATE, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_SUSPEND, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_ACCOUNT_ADD, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_INVITATION_UPDATE, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_INVITATION_REMOVE, Project.class.getName()); + entityEventDetails.put(EVENT_PROJECT_ACCOUNT_REMOVE, Project.class.getName()); + + // Network as a Service + entityEventDetails.put(EVENT_NETWORK_ELEMENT_CONFIGURE,Network.class.getName()); + + // Physical Network Events + entityEventDetails.put(EVENT_PHYSICAL_NETWORK_CREATE, PhysicalNetwork.class.getName()); + entityEventDetails.put(EVENT_PHYSICAL_NETWORK_DELETE, PhysicalNetwork.class.getName()); + entityEventDetails.put(EVENT_PHYSICAL_NETWORK_UPDATE, PhysicalNetwork.class.getName()); + + // Physical Network Service Provider Events + entityEventDetails.put(EVENT_SERVICE_PROVIDER_CREATE, PhysicalNetworkServiceProvider.class.getName()); + entityEventDetails.put(EVENT_SERVICE_PROVIDER_DELETE, PhysicalNetworkServiceProvider.class.getName()); + entityEventDetails.put(EVENT_SERVICE_PROVIDER_UPDATE, PhysicalNetworkServiceProvider.class.getName()); + + // Physical Network TrafficType Events + entityEventDetails.put(EVENT_TRAFFIC_TYPE_CREATE, PhysicalNetworkTrafficType.class.getName()); + entityEventDetails.put(EVENT_TRAFFIC_TYPE_DELETE, PhysicalNetworkTrafficType.class.getName()); + entityEventDetails.put(EVENT_TRAFFIC_TYPE_UPDATE, PhysicalNetworkTrafficType.class.getName()); + + // external network device events + entityEventDetails.put(EVENT_EXTERNAL_LB_DEVICE_ADD, PhysicalNetwork.class.getName()); + entityEventDetails.put(EVENT_EXTERNAL_LB_DEVICE_DELETE, PhysicalNetwork.class.getName()); + entityEventDetails.put(EVENT_EXTERNAL_LB_DEVICE_CONFIGURE, PhysicalNetwork.class.getName()); + + // external switch management device events (E.g.: Cisco Nexus 1000v Virtual Supervisor Module. + entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_ADD, "Nexus1000v"); + entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_DELETE, "Nexus1000v"); + entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_CONFIGURE, "Nexus1000v"); + entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_ENABLE, "Nexus1000v"); + entityEventDetails.put(EVENT_EXTERNAL_SWITCH_MGMT_DEVICE_DISABLE, "Nexus1000v"); + + + entityEventDetails.put(EVENT_EXTERNAL_FIREWALL_DEVICE_ADD, PhysicalNetwork.class.getName()); + entityEventDetails.put(EVENT_EXTERNAL_FIREWALL_DEVICE_DELETE, PhysicalNetwork.class.getName()); + entityEventDetails.put(EVENT_EXTERNAL_FIREWALL_DEVICE_CONFIGURE, PhysicalNetwork.class.getName()); + + // VPC + entityEventDetails.put(EVENT_VPC_CREATE, Vpc.class.getName()); + entityEventDetails.put(EVENT_VPC_UPDATE, Vpc.class.getName()); + entityEventDetails.put(EVENT_VPC_DELETE, Vpc.class.getName()); + entityEventDetails.put(EVENT_VPC_RESTART, Vpc.class.getName()); + + // VPC offerings + entityEventDetails.put(EVENT_VPC_OFFERING_CREATE, Vpc.class.getName()); + entityEventDetails.put(EVENT_VPC_OFFERING_UPDATE, Vpc.class.getName()); + entityEventDetails.put(EVENT_VPC_OFFERING_DELETE, Vpc.class.getName()); + + // Private gateway + entityEventDetails.put(EVENT_PRIVATE_GATEWAY_CREATE, PrivateGateway.class.getName()); + entityEventDetails.put(EVENT_PRIVATE_GATEWAY_DELETE, PrivateGateway.class.getName()); + + // Static routes + entityEventDetails.put(EVENT_STATIC_ROUTE_CREATE, StaticRoute.class.getName()); + entityEventDetails.put(EVENT_STATIC_ROUTE_DELETE, StaticRoute.class.getName()); + + // tag related events + entityEventDetails.put(EVENT_TAGS_CREATE, "Tag"); + entityEventDetails.put(EVENT_TAGS_DELETE, "tag"); + + // external network device events + entityEventDetails.put(EVENT_EXTERNAL_NVP_CONTROLLER_ADD, "NvpController"); + entityEventDetails.put(EVENT_EXTERNAL_NVP_CONTROLLER_DELETE, "NvpController"); + entityEventDetails.put(EVENT_EXTERNAL_NVP_CONTROLLER_CONFIGURE, "NvpController"); + + // AutoScale + entityEventDetails.put(EVENT_COUNTER_CREATE, AutoScaleCounter.class.getName()); + entityEventDetails.put(EVENT_COUNTER_DELETE, AutoScaleCounter.class.getName()); + entityEventDetails.put(EVENT_CONDITION_CREATE, Condition.class.getName()); + entityEventDetails.put(EVENT_CONDITION_DELETE, Condition.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEPOLICY_CREATE, AutoScalePolicy.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEPOLICY_UPDATE, AutoScalePolicy.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEPOLICY_DELETE, AutoScalePolicy.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMPROFILE_CREATE, AutoScaleVmProfile.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMPROFILE_DELETE, AutoScaleVmProfile.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMPROFILE_UPDATE, AutoScaleVmProfile.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_CREATE, AutoScaleVmGroup.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_DELETE, AutoScaleVmGroup.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_UPDATE, AutoScaleVmGroup.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_ENABLE, AutoScaleVmGroup.class.getName()); + entityEventDetails.put(EVENT_AUTOSCALEVMGROUP_DISABLE, AutoScaleVmGroup.class.getName()); + } + + public static String getEntityForEvent (String eventName) { + String entityClassName = entityEventDetails.get(eventName); + if (entityClassName == null || entityClassName.isEmpty()) { + return null; + } + int index = entityClassName.lastIndexOf("."); + String entityName = entityClassName; + if (index != -1) { + entityName = entityClassName.substring(index+1); + } + return entityName; + } } diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 27977f94f7b..889b9afd1e4 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -28,13 +28,24 @@ import org.apache.cloudstack.api.InternalIdentity; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; -import com.cloud.utils.fsm.FiniteState; -import com.cloud.utils.fsm.StateMachine; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Networks.Mode; +import com.cloud.network.Networks.TrafficType; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.utils.fsm.StateObject; + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; /** * owned by an account. */ -public interface Network extends ControlledEntity, InternalIdentity, Identity { +public interface Network extends ControlledEntity, StateObject, InternalIdentity, Identity { public enum GuestType { Shared, @@ -205,7 +216,8 @@ public interface Network extends ControlledEntity, InternalIdentity, Identity { OperationFailed; } - enum State implements FiniteState { + public enum State { + Allocated("Indicates the network configuration is in allocated but not setup"), Setup("Indicates the network configuration is setup"), Implementing("Indicates the network configuration is being implemented"), @@ -213,39 +225,8 @@ public interface Network extends ControlledEntity, InternalIdentity, Identity { Shutdown("Indicates the network configuration is being destroyed"), Destroy("Indicates that the network is destroyed"); + protected static final StateMachine2 s_fsm = new StateMachine2(); - @Override - public StateMachine getStateMachine() { - return s_fsm; - } - - @Override - public State getNextState(Event event) { - return s_fsm.getNextState(this, event); - } - - @Override - public List getFromStates(Event event) { - return s_fsm.getFromStates(this, event); - } - - @Override - public Set getPossibleEvents() { - return s_fsm.getPossibleEvents(this); - } - - String _description; - - @Override - public String getDescription() { - return _description; - } - - private State(String description) { - _description = description; - } - - private static StateMachine s_fsm = new StateMachine(); static { s_fsm.addTransition(State.Allocated, Event.ImplementNetwork, State.Implementing); s_fsm.addTransition(State.Implementing, Event.OperationSucceeded, State.Implemented); @@ -254,6 +235,15 @@ public interface Network extends ControlledEntity, InternalIdentity, Identity { s_fsm.addTransition(State.Shutdown, Event.OperationSucceeded, State.Allocated); s_fsm.addTransition(State.Shutdown, Event.OperationFailed, State.Implemented); } + + public static StateMachine2 getStateMachine() { + return s_fsm; + } + + String _description; + private State(String description) { + _description = description; + } } public class IpAddresses { diff --git a/api/src/com/cloud/storage/Snapshot.java b/api/src/com/cloud/storage/Snapshot.java index 6810a676302..3f6b8f5a8e4 100644 --- a/api/src/com/cloud/storage/Snapshot.java +++ b/api/src/com/cloud/storage/Snapshot.java @@ -18,13 +18,14 @@ package com.cloud.storage; import java.util.Date; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.utils.fsm.StateObject; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.api.InternalIdentity; -import com.cloud.hypervisor.Hypervisor.HypervisorType; - -public interface Snapshot extends ControlledEntity, Identity, InternalIdentity { +public interface Snapshot extends ControlledEntity, Identity, InternalIdentity, StateObject { public enum Type { MANUAL, RECURRING, @@ -53,14 +54,29 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity { } } - public enum Status { + public enum State { Creating, CreatedOnPrimary, BackingUp, BackedUp, Error; - @Override + private final static StateMachine2 s_fsm = new StateMachine2(); + + public static StateMachine2 getStateMachine() { + return s_fsm; + } + + static { + s_fsm.addTransition(null, Event.CreateRequested, Creating); + s_fsm.addTransition(Creating, Event.OperationSucceeded, CreatedOnPrimary); + s_fsm.addTransition(Creating, Event.OperationNotPerformed, BackedUp); + s_fsm.addTransition(Creating, Event.OperationFailed, Error); + s_fsm.addTransition(CreatedOnPrimary, Event.BackupToSecondary, BackingUp); + s_fsm.addTransition(BackingUp, Event.OperationSucceeded, BackedUp); + s_fsm.addTransition(BackingUp, Event.OperationFailed, Error); + } + public String toString() { return this.name(); } @@ -70,6 +86,15 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity { } } + enum Event { + CreateRequested, + OperationNotPerformed, + BackupToSecondary, + BackedupToSecondary, + OperationSucceeded, + OperationFailed + } + public static final long MANUAL_POLICY_ID = 0L; long getAccountId(); @@ -84,7 +109,7 @@ public interface Snapshot extends ControlledEntity, Identity, InternalIdentity { Type getType(); - Status getStatus(); + State getState(); HypervisorType getHypervisorType(); diff --git a/api/src/com/cloud/user/Account.java b/api/src/com/cloud/user/Account.java index a5b3e87156d..e65e017c266 100755 --- a/api/src/com/cloud/user/Account.java +++ b/api/src/com/cloud/user/Account.java @@ -62,5 +62,8 @@ public interface Account extends ControlledEntity, InternalIdentity, Identity { public String getNetworkDomain(); public Long getDefaultZoneId(); - + + public int getRegionId(); + + public String getUuid(); } diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index acc298fb8c6..8026891c5fa 100755 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -27,10 +27,10 @@ import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; import org.apache.cloudstack.api.command.admin.user.RegisterCmd; import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.api.command.admin.user.RegisterCmd; + import com.cloud.domain.Domain; -import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceUnavailableException; import com.cloud.utils.Pair; public interface AccountService { @@ -62,35 +62,7 @@ public interface AccountService { * @return the user if created successfully, null otherwise */ UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long domainId, String networkDomain, - Map details); - - /** - * Deletes a user by userId - * - * @param accountId - * - id of the account do delete - * - * @return true if delete was successful, false otherwise - */ - boolean deleteUserAccount(long accountId); - - /** - * Disables a user by userId - * - * @param userId - * - the userId - * @return UserAccount object - */ - UserAccount disableUser(long userId); - - /** - * Enables a user - * - * @param userId - * - the userId - * @return UserAccount object - */ - UserAccount enableUser(long userId); + Map details, String accountUUID, String userUUID, Integer regionId); /** * Locks a user by userId. A locked user cannot access the API, but will still have running VMs/IP addresses @@ -101,71 +73,11 @@ public interface AccountService { */ UserAccount lockUser(long userId); - /** - * Update a user by userId - * - * @param userId - * @return UserAccount object - */ - UserAccount updateUser(UpdateUserCmd cmd); - - /** - * Disables an account by accountName and domainId - * - * @param accountName - * TODO - * @param domainId - * TODO - * @param accountId - * @param disabled - * account if success - * @return true if disable was successful, false otherwise - */ - Account disableAccount(String accountName, Long domainId, Long accountId) throws ConcurrentOperationException, ResourceUnavailableException; - - /** - * Enables an account by accountId - * - * @param accountName - * - the enableAccount command defining the accountId to be deleted. - * @param domainId - * TODO - * @param accountId - * @return account object - */ - Account enableAccount(String accountName, Long domainId, Long accountId); - - /** - * Locks an account by accountId. A locked account cannot access the API, but will still have running VMs/IP - * addresses - * allocated/etc. - * - * @param accountName - * - the LockAccount command defining the accountId to be locked. - * @param domainId - * TODO - * @param accountId - * @return account object - */ - Account lockAccount(String accountName, Long domainId, Long accountId); - - /** - * Updates an account name - * - * @param cmd - * - the parameter containing accountId - * @return updated account object - */ - - Account updateAccount(UpdateAccountCmd cmd); - Account getSystemAccount(); User getSystemUser(); - User createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId); - - boolean deleteUser(DeleteUserCmd deleteUserCmd); + User createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId, String userUUID, Integer regionId); boolean isAdmin(short accountType); diff --git a/api/src/com/cloud/user/DomainService.java b/api/src/com/cloud/user/DomainService.java index 64c1de4c828..1a9635499f1 100644 --- a/api/src/com/cloud/user/DomainService.java +++ b/api/src/com/cloud/user/DomainService.java @@ -27,7 +27,7 @@ import com.cloud.utils.Pair; public interface DomainService { - Domain createDomain(String name, Long parentId, String networkDomain); + Domain createDomain(String name, Long parentId, String networkDomain, String domainUUID, Integer regionId); Domain getDomain(long id); @@ -41,12 +41,19 @@ public interface DomainService { */ boolean isChildDomain(Long parentId, Long childId); - boolean deleteDomain(long domainId, Boolean cleanup); - Pair, Integer> searchForDomains(ListDomainsCmd cmd) throws PermissionDeniedException; Pair, Integer> searchForDomainChildren(ListDomainChildrenCmd cmd) throws PermissionDeniedException; + /** + * find the domain by its path + * + * @param domainPath + * the path to use to lookup a domain + * @return domainVO the domain with the matching path, or null if no domain with the given path exists + */ + Domain findDomainByPath(String domainPath); + } diff --git a/api/src/com/cloud/user/User.java b/api/src/com/cloud/user/User.java index 3742c7bf3e2..7d80c435e3d 100644 --- a/api/src/com/cloud/user/User.java +++ b/api/src/com/cloud/user/User.java @@ -73,4 +73,5 @@ public interface User extends OwnedBy, InternalIdentity { boolean isRegistered(); + public int getRegionId(); } diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 083b66f9a44..79b7aba616d 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -373,6 +373,9 @@ public class ApiConstants { public static final String VSM_CONFIG_STATE = "vsmconfigstate"; public static final String VSM_DEVICE_STATE = "vsmdevicestate"; public static final String ADD_VSM_FLAG = "addvsmflag"; + public static final String END_POINT = "endpoint"; + public static final String REGION_ID = "regionid"; + public static final String IS_PROPAGATE = "ispropagate"; public static final String VPC_OFF_ID = "vpcofferingid"; public static final String NETWORK = "network"; public static final String VPC_ID = "vpcid"; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index ae968d6cd0b..d8e2bffed3a 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -28,6 +28,7 @@ import java.util.regex.Pattern; import javax.inject.Inject; import org.apache.cloudstack.query.QueryService; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.configuration.ConfigurationService; diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java index f589b185fde..b95f182c32f 100644 --- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java +++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java @@ -60,6 +60,7 @@ import org.apache.cloudstack.api.response.ProjectAccountResponse; import org.apache.cloudstack.api.response.ProjectInvitationResponse; import org.apache.cloudstack.api.response.ProjectResponse; import org.apache.cloudstack.api.response.ProviderResponse; +import org.apache.cloudstack.api.response.RegionResponse; import org.apache.cloudstack.api.response.RemoteAccessVpnResponse; import org.apache.cloudstack.api.response.ResourceCountResponse; import org.apache.cloudstack.api.response.ResourceLimitResponse; @@ -92,6 +93,7 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.region.Region; import com.cloud.async.AsyncJob; import com.cloud.capacity.Capacity; @@ -313,6 +315,8 @@ public interface ResponseGenerator { StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result); + RegionResponse createRegionResponse(Region region); + /** * @param resourceTag * @param keyValueOnly TODO 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 57789c97db9..b0f73d1d8f8 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 @@ -78,6 +78,19 @@ public class CreateAccountCmd extends BaseCmd { @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters") private Map details; + //@Parameter(name = ApiConstants.REGION_DETAILS, type = CommandType.MAP, description = "details for account used to store region specific parameters") + //private Map regionDetails; + + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.STRING, description="Account UUID, required for adding account from another Region") + private String accountUUID; + + @Parameter(name=ApiConstants.USER_ID, type=CommandType.STRING, description="User UUID, required for adding account from another Region") + private String userUUID; + + @Parameter(name=ApiConstants.REGION_ID, type=CommandType.INTEGER, description="Id of the Region creating the account") + private Integer regionId; + + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -132,6 +145,18 @@ public class CreateAccountCmd extends BaseCmd { return params; } + public String getAccountUUID() { + return accountUUID; + } + + public String getUserUUID() { + return userUUID; + } + + public Integer getRegionId() { + return regionId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -149,7 +174,8 @@ public class CreateAccountCmd extends BaseCmd { @Override public void execute(){ UserContext.current().setEventDetails("Account Name: "+getAccountName()+", Domain Id:"+getDomainId()); - UserAccount userAccount = _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), getDomainId(), getNetworkDomain(), getDetails()); + UserAccount userAccount = _accountService.createUserAccount(getUsername(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimeZone(), getAccountName(), getAccountType(), getDomainId(), getNetworkDomain(), getDetails(), + getAccountUUID(), getUserUUID(), getRegionId()); if (userAccount != null) { AccountResponse response = _responseGenerator.createUserAccountResponse(userAccount); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/DeleteAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/DeleteAccountCmd.java index ba41606d858..959d7ce985b 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/DeleteAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/DeleteAccountCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.account; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -24,6 +26,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; @@ -45,14 +48,24 @@ public class DeleteAccountCmd extends BaseAsyncCmd { required=true, description="Account id") private Long id; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// + public Long getId() { return id; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -90,7 +103,8 @@ public class DeleteAccountCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Account Id: "+getId()); - boolean result = _accountService.deleteUserAccount(getId()); + + boolean result = _regionService.deleteUserAccount(this); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/DisableAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/DisableAccountCmd.java index e08ffbcff75..60e9fd5aa60 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/DisableAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/DisableAccountCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.account; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -24,6 +26,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; @@ -55,6 +58,11 @@ public class DisableAccountCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.LOCK, type=CommandType.BOOLEAN, required=true, description="If true, only lock the account; else disable the account") private Boolean lockRequested; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -71,6 +79,14 @@ public class DisableAccountCmd extends BaseAsyncCmd { return domainId; } + public Boolean getIsPropagate() { + return isPropagate; + } + + public Boolean getLockRequested() { + return lockRequested; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -108,11 +124,7 @@ public class DisableAccountCmd extends BaseAsyncCmd { @Override public void execute() throws ConcurrentOperationException, ResourceUnavailableException{ UserContext.current().setEventDetails("Account Name: "+getAccountName()+", Domain Id:"+getDomainId()); - Account result = null; - if(lockRequested) - result = _accountService.lockAccount(getAccountName(), getDomainId(), getId()); - else - result = _accountService.disableAccount(getAccountName(), getDomainId(), getId()); + Account result = _regionService.disableAccount(this); if (result != null){ AccountResponse response = _responseGenerator.createAccountResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/EnableAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/EnableAccountCmd.java index efd5d599a98..9a92f789132 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/EnableAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/EnableAccountCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.account; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -24,6 +26,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.user.Account; @@ -47,6 +50,11 @@ public class EnableAccountCmd extends BaseCmd { description="Enables specified account in this domain.") private Long domainId; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -63,6 +71,10 @@ public class EnableAccountCmd extends BaseCmd { return domainId; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -89,7 +101,7 @@ public class EnableAccountCmd extends BaseCmd { @Override public void execute(){ - Account result = _accountService.enableAccount(getAccountName(), getDomainId(), getId()); + Account result = _regionService.enableAccount(this); if (result != null){ AccountResponse response = _responseGenerator.createAccountResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/account/UpdateAccountCmd.java b/api/src/org/apache/cloudstack/api/command/admin/account/UpdateAccountCmd.java index 77f53f9518b..6fad48bf66e 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/account/UpdateAccountCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/account/UpdateAccountCmd.java @@ -19,6 +19,8 @@ package org.apache.cloudstack.api.command.admin.account; import java.util.Collection; import java.util.Map; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -27,6 +29,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.user.Account; @@ -60,6 +63,11 @@ public class UpdateAccountCmd extends BaseCmd{ @Parameter(name = ApiConstants.ACCOUNT_DETAILS, type = CommandType.MAP, description = "details for account used to store specific parameters") private Map details; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -94,6 +102,10 @@ public class UpdateAccountCmd extends BaseCmd{ return params; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -119,7 +131,7 @@ public class UpdateAccountCmd extends BaseCmd{ @Override public void execute(){ - Account result = _accountService.updateAccount(this); + Account result = _regionService.updateAccount(this); if (result != null){ AccountResponse response = _responseGenerator.createAccountResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java b/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java index 5eae4865732..e0ba69359ad 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/domain/CreateDomainCmd.java @@ -49,6 +49,12 @@ public class CreateDomainCmd extends BaseCmd { @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="Network domain for networks in the domain") private String networkDomain; + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.STRING, description="Domain UUID, required for adding domain from another Region") + private String domainUUID; + + @Parameter(name=ApiConstants.REGION_ID, type=CommandType.INTEGER, description="Id of the Region creating the Domain") + private Integer regionId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -65,6 +71,14 @@ public class CreateDomainCmd extends BaseCmd { return networkDomain; } + public String getDomainUUID() { + return domainUUID; + } + + public Integer getRegionId() { + return regionId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -82,7 +96,7 @@ public class CreateDomainCmd extends BaseCmd { @Override public void execute(){ UserContext.current().setEventDetails("Domain Name: "+getDomainName()+((getParentDomainId()!=null)?", Parent DomainId :"+getParentDomainId():"")); - Domain domain = _domainService.createDomain(getDomainName(), getParentDomainId(), getNetworkDomain()); + Domain domain = _domainService.createDomain(getDomainName(), getParentDomainId(), getNetworkDomain(), getDomainUUID(), getRegionId()); if (domain != null) { DomainResponse response = _responseGenerator.createDomainResponse(domain); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java b/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java index 93ff299f0d0..eae393da81e 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/domain/DeleteDomainCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.domain; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -24,6 +26,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.domain.Domain; @@ -47,7 +50,11 @@ public class DeleteDomainCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.CLEANUP, type=CommandType.BOOLEAN, description="true if all domain resources (child domains, accounts) have to be cleaned up, false otherwise") private Boolean cleanup; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean propagate; + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -60,6 +67,10 @@ public class DeleteDomainCmd extends BaseAsyncCmd { return cleanup; } + public Boolean isPropagate() { + return propagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -92,7 +103,7 @@ public class DeleteDomainCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Domain Id: "+getId()); - boolean result = _domainService.deleteDomain(id, cleanup); + boolean result = _regionService.deleteDomain(this); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/admin/domain/UpdateDomainCmd.java b/api/src/org/apache/cloudstack/api/command/admin/domain/UpdateDomainCmd.java index b5f3321e349..c217f16c93a 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/domain/UpdateDomainCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/domain/UpdateDomainCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.domain; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -23,10 +25,12 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.domain.Domain; import com.cloud.user.Account; +import com.cloud.user.UserAccount; import com.cloud.user.UserContext; @APICommand(name = "updateDomain", description="Updates a domain with a new name", responseObject=DomainResponse.class) @@ -48,6 +52,11 @@ public class UpdateDomainCmd extends BaseCmd { @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="Network domain for the domain's networks; empty string will update domainName with NULL value") private String networkDomain; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -64,6 +73,10 @@ public class UpdateDomainCmd extends BaseCmd { return networkDomain; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -81,7 +94,8 @@ public class UpdateDomainCmd extends BaseCmd { @Override public void execute(){ UserContext.current().setEventDetails("Domain Id: "+getId()); - Domain domain = _mgr.updateDomain(this); + Domain domain = _regionService.updateDomain(this); + if (domain != null) { DomainResponse response = _responseGenerator.createDomainResponse(domain); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/AddRegionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/AddRegionCmd.java new file mode 100644 index 00000000000..20366702dd1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/region/AddRegionCmd.java @@ -0,0 +1,109 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.region; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.RegionResponse; +import org.apache.cloudstack.region.Region; +import org.apache.cloudstack.region.RegionService; +import org.apache.log4j.Logger; + +import com.cloud.user.Account; + +@APICommand(name = "addRegion", description="Adds a Region", responseObject=RegionResponse.class) +public class AddRegionCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(AddRegionCmd.class.getName()); + + private static final String s_name = "addregionresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.ID, type=CommandType.INTEGER, required=true, description="Id of the Region") + private Integer id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, required=true, description="Name of the region") + private String regionName; + + @Parameter(name=ApiConstants.END_POINT, type=CommandType.STRING, required=true, description="Region service endpoint") + private String endPoint; + + @Parameter(name=ApiConstants.API_KEY, type=CommandType.STRING, description="API key of Admin user") + private String apiKey; + + @Parameter(name=ApiConstants.SECRET_KEY, type=CommandType.STRING, description="Secret Key of Admin user") + private String secretKey; + + @Inject public RegionService _regionService; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Integer getId() { + return id; + } + + public String getRegionName() { + return regionName; + } + + public String getEndPoint() { + return endPoint; + } + + public String getApiKey() { + return apiKey; + } + + public String getSecretKey() { + return secretKey; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + Region region = _regionService.addRegion(getId(), getRegionName(), getEndPoint(), getApiKey(), getSecretKey()); + if (region != null) { + RegionResponse response = _responseGenerator.createRegionResponse(region); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Region"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java new file mode 100644 index 00000000000..79c34d0690f --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/region/RemoveRegionCmd.java @@ -0,0 +1,79 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.region; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.region.RegionService; +import org.apache.log4j.Logger; + +import com.cloud.user.Account; + +@APICommand(name = "removeRegion", description="Removes specified region", responseObject=SuccessResponse.class) +public class RemoveRegionCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(RemoveRegionCmd.class.getName()); + private static final String s_name = "updateregionresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.INTEGER, required=true, description="ID of the region to delete") + private Integer id; + + @Inject RegionService _regionService; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Integer getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + boolean result = _regionService.removeRegion(id); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove region"); + } + } +} diff --git a/api/src/org/apache/cloudstack/api/command/admin/region/UpdateRegionCmd.java b/api/src/org/apache/cloudstack/api/command/admin/region/UpdateRegionCmd.java new file mode 100644 index 00000000000..16693b64650 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/admin/region/UpdateRegionCmd.java @@ -0,0 +1,108 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.admin.region; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.RegionResponse; +import org.apache.cloudstack.region.Region; +import org.apache.cloudstack.region.RegionService; +import org.apache.log4j.Logger; + +import com.cloud.user.Account; + +@APICommand(name = "updateRegion", description="Updates a region", responseObject=RegionResponse.class) +public class UpdateRegionCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(UpdateRegionCmd.class.getName()); + private static final String s_name = "updateregionresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.INTEGER, required=true, description="Id of region to update") + private Integer id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="updates region with this name") + private String regionName; + + @Parameter(name=ApiConstants.END_POINT, type=CommandType.STRING, description="updates region with this end point") + private String endPoint; + + @Parameter(name=ApiConstants.API_KEY, type=CommandType.STRING, description="new API key for the Region") + private String apiKey; + + @Parameter(name=ApiConstants.SECRET_KEY, type=CommandType.STRING, description="new Secret Key for the Region") + private String secretKey; + + @Inject RegionService _regionService; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Integer getId() { + return id; + } + + public String getRegionName() { + return regionName; + } + + public String getEndPoint() { + return endPoint; + } + + public String getApiKey() { + return apiKey; + } + + public String getSecretKey() { + return secretKey; + } + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } + + @Override + public void execute(){ + Region region = _regionService.updateRegion(getId(), getRegionName(), getEndPoint(), getApiKey(), getSecretKey()); + if (region != null) { + RegionResponse response = _responseGenerator.createRegionResponse(region); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update Region"); + } + } +} 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 6ea8d9b20cb..d1f72c45dd7 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 @@ -65,6 +65,12 @@ public class CreateUserCmd extends BaseCmd { @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required=true, description="Unique username.") private String username; + @Parameter(name=ApiConstants.USER_ID, type=CommandType.STRING, description="User UUID, required for adding account from another Region") + private String userUUID; + + @Parameter(name=ApiConstants.REGION_ID, type=CommandType.INTEGER, description="Id of the Region creating the User") + private Integer regionId; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -101,6 +107,14 @@ public class CreateUserCmd extends BaseCmd { return username; } + public String getUserUUID() { + return userUUID; + } + + public Integer getRegionId() { + return regionId; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -132,7 +146,7 @@ public class CreateUserCmd extends BaseCmd { @Override public void execute(){ UserContext.current().setEventDetails("UserName: "+getUserName()+", FirstName :"+getFirstName()+", LastName: "+getLastName()); - User user = _accountService.createUser(getUserName(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimezone(), getAccountName(), getDomainId()); + User user = _accountService.createUser(getUserName(), getPassword(), getFirstName(), getLastName(), getEmail(), getTimezone(), getAccountName(), getDomainId(), getUserUUID(), getRegionId()); if (user != null) { UserResponse response = _responseGenerator.createUserResponse(user); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/DeleteUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/DeleteUserCmd.java index 51a61e9711f..e8f671de1b9 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/user/DeleteUserCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/user/DeleteUserCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.user; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -24,6 +26,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.api.response.UserResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.user.Account; @@ -42,6 +45,11 @@ public class DeleteUserCmd extends BaseCmd { @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType=UserResponse.class, required=true, description="Deletes a user") private Long id; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -50,6 +58,10 @@ public class DeleteUserCmd extends BaseCmd { return id; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -72,7 +84,7 @@ public class DeleteUserCmd extends BaseCmd { @Override public void execute(){ UserContext.current().setEventDetails("UserId: "+getId()); - boolean result = _accountService.deleteUser(this); + boolean result = _regionService.deleteUser(this); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java index 5860adf601c..95013ec30bc 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/user/DisableUserCmd.java @@ -16,13 +16,17 @@ // under the License. package org.apache.cloudstack.api.command.admin.user; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.UserResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.async.AsyncJob; @@ -45,6 +49,11 @@ public class DisableUserCmd extends BaseAsyncCmd { required=true, description="Disables user by user ID.") private Long id; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -53,6 +62,10 @@ public class DisableUserCmd extends BaseAsyncCmd { return id; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -86,7 +99,8 @@ public class DisableUserCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("UserId: "+getId()); - UserAccount user = _accountService.disableUser(getId()); + UserAccount user = _regionService.disableUser(this); + if (user != null){ UserResponse response = _responseGenerator.createUserResponse(user); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/admin/user/EnableUserCmd.java b/api/src/org/apache/cloudstack/api/command/admin/user/EnableUserCmd.java index d2f91e7b052..c1ba9003b05 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/user/EnableUserCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/user/EnableUserCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.user; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -23,6 +25,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.UserResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.user.Account; @@ -43,7 +46,11 @@ public class EnableUserCmd extends BaseCmd { required=true, description="Enables user by user ID.") private Long id; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -52,6 +59,10 @@ public class EnableUserCmd extends BaseCmd { return id; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -74,7 +85,8 @@ public class EnableUserCmd extends BaseCmd { @Override public void execute(){ UserContext.current().setEventDetails("UserId: "+getId()); - UserAccount user = _accountService.enableUser(getId()); + UserAccount user = _regionService.enableUser(this); + if (user != null){ UserResponse response = _responseGenerator.createUserResponse(user); response.setResponseName(getCommandName()); 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 0b9eb032b85..ee59d07cb79 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 @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.user; +import javax.inject.Inject; + import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; @@ -23,6 +25,7 @@ import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.UserResponse; +import org.apache.cloudstack.region.RegionService; import org.apache.log4j.Logger; import com.cloud.user.Account; @@ -68,6 +71,11 @@ public class UpdateUserCmd extends BaseCmd { @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, description="Unique username") private String username; + @Parameter(name=ApiConstants.IS_PROPAGATE, type=CommandType.BOOLEAN, description="True if command is sent from another Region") + private Boolean isPropagate; + + @Inject RegionService _regionService; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -108,6 +116,10 @@ public class UpdateUserCmd extends BaseCmd { return username; } + public Boolean getIsPropagate() { + return isPropagate; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -130,7 +142,8 @@ public class UpdateUserCmd extends BaseCmd { @Override public void execute(){ UserContext.current().setEventDetails("UserId: "+getId()); - UserAccount user = _accountService.updateUser(this); + UserAccount user = _regionService.updateUser(this); + if (user != null){ UserResponse response = _responseGenerator.createUserResponse(user); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/region/ListRegionsCmd.java b/api/src/org/apache/cloudstack/api/command/user/region/ListRegionsCmd.java new file mode 100644 index 00000000000..07f93a4568a --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/region/ListRegionsCmd.java @@ -0,0 +1,88 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.region; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.RegionResponse; +import org.apache.cloudstack.region.Region; +import org.apache.cloudstack.region.RegionService; +import org.apache.log4j.Logger; + +@APICommand(name = "listRegions", description="Lists Regions", responseObject=RegionResponse.class) +public class ListRegionsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListRegionsCmd.class.getName()); + + private static final String s_name = "listregionsresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.INTEGER, description="List Region by region ID.") + private Integer id; + + @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="List Region by region name.") + private String name; + + @Inject RegionService _regionService; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute(){ + List result = _regionService.listRegions(this); + ListResponse response = new ListResponse(); + List regionResponses = new ArrayList(); + for (Region region : result) { + RegionResponse regionResponse = _responseGenerator.createRegionResponse(region); + regionResponse.setObjectName("region"); + regionResponses.add(regionResponse); + } + + response.setResponses(regionResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/api/src/org/apache/cloudstack/api/response/RegionResponse.java b/api/src/org/apache/cloudstack/api/response/RegionResponse.java new file mode 100644 index 00000000000..f8bfe53aae3 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/RegionResponse.java @@ -0,0 +1,62 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.region.Region; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value = Region.class) +public class RegionResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the region") + private Integer id; + + @SerializedName(ApiConstants.NAME) @Param(description="the name of the region") + private String name; + + @SerializedName(ApiConstants.END_POINT) @Param(description="the end point of the region") + private String endPoint; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEndPoint() { + return endPoint; + } + + public void setEndPoint(String endPoint) { + this.endPoint = endPoint; + } + + } diff --git a/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java b/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java index 9b5f8c1e0bb..5b77fb2f360 100644 --- a/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java +++ b/api/src/org/apache/cloudstack/api/response/SnapshotResponse.java @@ -26,6 +26,15 @@ import org.apache.cloudstack.api.EntityReference; import com.cloud.serializer.Param; import com.cloud.storage.Snapshot; import com.google.gson.annotations.SerializedName; +import com.cloud.serializer.Param; +import com.cloud.storage.Snapshot; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import java.util.Date; +import java.util.List; @EntityReference(value=Snapshot.class) @SuppressWarnings("unused") @@ -82,7 +91,7 @@ public class SnapshotResponse extends BaseResponse implements ControlledEntityRe @SerializedName(ApiConstants.STATE) @Param(description = "the state of the snapshot. BackedUp means that snapshot is ready to be used; Creating - the snapshot is being allocated on the primary storage; BackingUp - the snapshot is being backed up on secondary storage") - private Snapshot.Status state; + private Snapshot.State state; @SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with snapshot", responseObject = ResourceTagResponse.class) private List tags; @@ -150,7 +159,7 @@ public class SnapshotResponse extends BaseResponse implements ControlledEntityRe this.intervalType = intervalType; } - public void setState(Snapshot.Status state) { + public void setState(Snapshot.State state) { this.state = state; } diff --git a/api/src/org/apache/cloudstack/region/Region.java b/api/src/org/apache/cloudstack/region/Region.java new file mode 100644 index 00000000000..7f0aeeab2ef --- /dev/null +++ b/api/src/org/apache/cloudstack/region/Region.java @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +/** + * + */ +public interface Region { + + public int getId(); + + public String getName(); + + public void setName(String name); + + public String getEndPoint(); + + public String getApiKey(); + + public String getSecretKey(); +} diff --git a/api/src/org/apache/cloudstack/region/RegionService.java b/api/src/org/apache/cloudstack/region/RegionService.java new file mode 100644 index 00000000000..8679ca92b10 --- /dev/null +++ b/api/src/org/apache/cloudstack/region/RegionService.java @@ -0,0 +1,157 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.List; + +import org.apache.cloudstack.api.command.admin.account.DeleteAccountCmd; +import org.apache.cloudstack.api.command.admin.account.DisableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.EnableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.domain.DeleteDomainCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.DisableUserCmd; +import org.apache.cloudstack.api.command.admin.user.EnableUserCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; + +import com.cloud.domain.Domain; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.UserAccount; + + +public interface RegionService { + /** + * Adds a Region to the local Region + * @param id + * @param name + * @param endPoint + * @param apiKey + * @param secretKey + * @return Return added Region object + */ + public Region addRegion(int id, String name, String endPoint, String apiKey, String secretKey); + + /** + * Update details of the Region with specified Id + * @param id + * @param name + * @param endPoint + * @param apiKey + * @param secretKey + * @return Return updated Region object + */ + public Region updateRegion(int id, String name, String endPoint, String apiKey, String secretKey); + + /** + * @param id + * @return True if region is successfully removed + */ + public boolean removeRegion(int id); + + /** List all Regions or by Id/Name + * @param id + * @param name + * @return List of Regions + */ + public List listRegions(ListRegionsCmd cmd); + + /** + * Deletes a user by userId + * isPopagate flag is set to true if sent from peer Region + * @param cmd + * + * @return true if delete was successful, false otherwise + */ + boolean deleteUserAccount(DeleteAccountCmd cmd); + + /** + * Updates an account + * isPopagate falg is set to true if sent from peer Region + * + * @param cmd + * - the parameter containing accountId or account nameand domainId + * @return updated account object + */ + Account updateAccount(UpdateAccountCmd cmd); + + /** + * Disables an account by accountName and domainId or accountId + * @param cmd + * @return + * @throws ResourceUnavailableException + * @throws ConcurrentOperationException + */ + Account disableAccount(DisableAccountCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException; + + /** + * Enables an account by accountId + * @param cmd + * @return + */ + Account enableAccount(EnableAccountCmd cmd); + + /** + * Deletes user by Id + * @param deleteUserCmd + * @return true if delete was successful, false otherwise + */ + boolean deleteUser(DeleteUserCmd deleteUserCmd); + + /** + * update an existing domain + * + * @param cmd + * - the command containing domainId and new domainName + * @return Domain object if the command succeeded + */ + public Domain updateDomain(UpdateDomainCmd updateDomainCmd); + + /** + * Deletes domain + * @param cmd + * @return true if delete was successful, false otherwise + */ + public boolean deleteDomain(DeleteDomainCmd cmd); + + /** + * Update a user by userId + * + * @param userId + * @return UserAccount object + */ + public UserAccount updateUser(UpdateUserCmd updateUserCmd); + + /** + * Disables a user by userId + * + * @param cmd + * @return UserAccount object + */ + public UserAccount disableUser(DisableUserCmd cmd); + + /** + * Enables a user + * + * @param cmd + * @return UserAccount object + */ + public UserAccount enableUser(EnableUserCmd cmd); +} diff --git a/api/src/org/apache/cloudstack/region/RegionSync.java b/api/src/org/apache/cloudstack/region/RegionSync.java new file mode 100644 index 00000000000..5a1f5a6c19d --- /dev/null +++ b/api/src/org/apache/cloudstack/region/RegionSync.java @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.Date; + +/** + * + */ +public interface RegionSync { + + public long getId(); + + public int getRegionId(); + + public String getApi(); + + Date getCreateDate(); +} diff --git a/api/test/org/apache/cloudstack/api/command/test/RegionCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/RegionCmdTest.java new file mode 100644 index 00000000000..01cd33bec80 --- /dev/null +++ b/api/test/org/apache/cloudstack/api/command/test/RegionCmdTest.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.test; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.region.AddRegionCmd; +import org.apache.cloudstack.api.response.RegionResponse; +import org.apache.cloudstack.region.Region; +import org.apache.cloudstack.region.RegionService; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +public class RegionCmdTest extends TestCase { + + private AddRegionCmd addRegionCmd; + private ResponseGenerator responseGenerator; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Before + public void setUp() { + + addRegionCmd = new AddRegionCmd() { + + @Override + public Integer getId() { + return 2; + } + + @Override + public String getRegionName() { + return "APAC"; + } + + }; + } + + @Test + public void testCreateSuccess() { + + RegionService regionService = Mockito.mock(RegionService.class); + + Region region = Mockito.mock(Region.class); + Mockito.when( + regionService.addRegion(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(region); + + addRegionCmd._regionService = regionService; + responseGenerator = Mockito.mock(ResponseGenerator.class); + + RegionResponse regionResponse = Mockito.mock(RegionResponse.class); + + Mockito.when(responseGenerator.createRegionResponse(region)).thenReturn( + regionResponse); + + addRegionCmd._responseGenerator = responseGenerator; + addRegionCmd.execute(); + + } + + @Test + public void testCreateFailure() { + + RegionService regionService = Mockito.mock(RegionService.class); + + Region region = Mockito.mock(Region.class); + Mockito.when( + regionService.addRegion(Mockito.anyInt(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) + .thenReturn(null); + + addRegionCmd._regionService = regionService; + + try { + addRegionCmd.execute(); + } catch (ServerApiException exception) { + Assert.assertEquals("Failed to add Region", + exception.getDescription()); + } + + } + +} diff --git a/client/pom.xml b/client/pom.xml index 6411ed89fa6..27bca3d1b9c 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -116,6 +116,11 @@ cloud-plugin-host-allocator-random ${project.version} + + org.apache.cloudstack + cloud-mom-rabbitmq + ${project.version} + mysql mysql-connector-java diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 755a5f27513..4b0506f7543 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -525,3 +525,9 @@ listApis=15 getApiLimit=15 resetApiLimit=1 + +#### Region commands +addRegion=1 +updateRegion=1 +removeRegion=1 +listRegions=15 diff --git a/client/tomcatconf/componentContext.xml.in b/client/tomcatconf/componentContext.xml.in index 48ed9f57c13..ca917270f5d 100644 --- a/client/tomcatconf/componentContext.xml.in +++ b/client/tomcatconf/componentContext.xml.in @@ -50,6 +50,7 @@ + + + 4.0.0 + cloud-framework-events + Apache CloudStack Event Notification Framework + + org.apache.cloudstack + cloudstack-framework + 4.1.0-SNAPSHOT + ../pom.xml + + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + com.google.code.gson + gson + ${cs.gson.version} + + + + install + src + test + + diff --git a/framework/events/src/org/apache/cloudstack/framework/events/Event.java b/framework/events/src/org/apache/cloudstack/framework/events/Event.java new file mode 100644 index 00000000000..eb6f48de3b8 --- /dev/null +++ b/framework/events/src/org/apache/cloudstack/framework/events/Event.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cloudstack.framework.events; + +import com.google.gson.Gson; + +public class Event { + + String eventCategory; + String eventType; + String eventSource; + String resourceType; + String resourceUUID; + String description; + + public Event(String eventSource, String eventCategory, String eventType, String resourceType, + String resourceUUID) { + this.eventCategory = eventCategory; + this.eventType = eventType; + this.eventSource = eventSource; + this.resourceType = resourceType; + this.resourceUUID = resourceUUID; + } + + public String getEventCategory() { + return eventCategory; + } + + public void setEventCategory(String category) { + eventCategory = category; + } + + public String getEventType() { + return eventType; + } + + public void setEventType(String type) { + eventType = type; + } + + public String getEventSource() { + return eventSource; + } + + void setEventSource(String source) { + eventSource = source; + } + + public String getDescription() { + return description; + } + + public void setDescription (Object message) { + Gson gson = new Gson(); + this.description = gson.toJson(message).toString(); + } + + public void setDescription(String description) { + this.description = description; + } + + public String getResourceType() { + return resourceType; + } + + public void setResourceType(String resourceType) { + this.resourceType = resourceType; + } + + public void setResourceUUID(String uuid) { + this.resourceUUID = uuid; + } + + public String getResourceUUID () { + return resourceUUID; + } +} \ No newline at end of file diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventBus.java b/framework/events/src/org/apache/cloudstack/framework/events/EventBus.java new file mode 100644 index 00000000000..c16ee6f96f4 --- /dev/null +++ b/framework/events/src/org/apache/cloudstack/framework/events/EventBus.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cloudstack.framework.events; + +import com.cloud.utils.component.Adapter; + +import java.util.UUID; + +/** + * Interface to publish and subscribe to CloudStack events + * + */ +public interface EventBus extends Adapter{ + + /** + * publish an event on to the event bus + * + * @param event event that needs to be published on the event bus + */ + void publish(Event event) throws EventBusException; + + /** + * subscribe to events that matches specified event topics + * + * @param topic defines category and type of the events being subscribed to + * @param subscriber subscriber that intends to receive event notification + * @return UUID returns the subscription ID + */ + UUID subscribe(EventTopic topic, EventSubscriber subscriber) throws EventBusException; + + /** + * unsubscribe to events of a category and a type + * + * @param subscriber subscriber that intends to unsubscribe from the event notification + */ + void unsubscribe(UUID subscriberId, EventSubscriber subscriber) throws EventBusException; + +} diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventBusException.java b/framework/events/src/org/apache/cloudstack/framework/events/EventBusException.java new file mode 100644 index 00000000000..5654ba04804 --- /dev/null +++ b/framework/events/src/org/apache/cloudstack/framework/events/EventBusException.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cloudstack.framework.events; + +public class EventBusException extends Exception{ + public EventBusException (String msg) { + super(msg); + } +} diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventSubscriber.java b/framework/events/src/org/apache/cloudstack/framework/events/EventSubscriber.java new file mode 100644 index 00000000000..511ebff17d2 --- /dev/null +++ b/framework/events/src/org/apache/cloudstack/framework/events/EventSubscriber.java @@ -0,0 +1,28 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.framework.events; + +public interface EventSubscriber { + + /** + * Callback method. EventBus calls this method on occurrence of subscribed event + * + * @param event details of the event + */ + void onEvent(Event event); +} diff --git a/framework/events/src/org/apache/cloudstack/framework/events/EventTopic.java b/framework/events/src/org/apache/cloudstack/framework/events/EventTopic.java new file mode 100644 index 00000000000..19b727d4519 --- /dev/null +++ b/framework/events/src/org/apache/cloudstack/framework/events/EventTopic.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cloudstack.framework.events; + +public class EventTopic { + + String eventCategory; + String eventType; + String resourceType; + String resourceUUID; + String eventSource; + + public EventTopic(String eventCategory, String eventType, String resourceType, String resourceUUID, String eventSource) { + this.eventCategory = eventCategory; + this.eventType = eventType; + this.resourceType = resourceType; + this.resourceUUID = resourceUUID; + this.eventSource = eventSource; + } + + public String getEventCategory() { + return eventCategory; + } + + public String getEventType() { + return eventType; + } + + public String getResourceType() { + return resourceType; + } + + public String getEventSource() { + return eventSource; + } + + public String getResourceUUID() { + return resourceUUID; + } +} diff --git a/framework/pom.xml b/framework/pom.xml index ca2a4f35445..9ac1ae070c0 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -32,5 +32,6 @@ ipc rest + events diff --git a/plugins/event-bus/rabbitmq/pom.xml b/plugins/event-bus/rabbitmq/pom.xml new file mode 100644 index 00000000000..6a47983a9b5 --- /dev/null +++ b/plugins/event-bus/rabbitmq/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + cloud-mom-rabbitmq + Apache CloudStack Plugin - RabbitMQ Event Bus + + org.apache.cloudstack + cloudstack-plugins + 4.1.0-SNAPSHOT + ../../pom.xml + + + + com.rabbitmq + amqp-client + 2.8.7 + + + org.apache.cloudstack + cloud-framework-events + ${project.version} + + + + install + src + + diff --git a/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java b/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java new file mode 100644 index 00000000000..ce0930d115d --- /dev/null +++ b/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java @@ -0,0 +1,556 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.cloudstack.mom.rabbitmq; + +import com.rabbitmq.client.*; +import org.apache.cloudstack.framework.events.*; +import org.apache.log4j.Logger; + +import com.cloud.utils.Ternary; +import com.cloud.utils.component.ManagerBase; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.io.IOException; +import java.net.ConnectException; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +@Local(value=EventBus.class) +public class RabbitMQEventBus extends ManagerBase implements EventBus { + + // details of AMQP server + private static String _amqpHost; + private static Integer _port; + private static String _username; + private static String _password; + + // AMQP exchange name where all CloudStack events will be published + private static String _amqpExchangeName; + + // hashmap to book keep the registered subscribers + private static ConcurrentHashMap> _subscribers; + + // connection to AMQP server, + private static Connection _connection=null; + + // AMQP server should consider messages acknowledged once delivered if _autoAck is true + private static boolean _autoAck = true; + + private ExecutorService executorService; + private String _name; + private static DisconnectHandler disconnectHandler; + private static Integer _retryInterval; + private static final Logger s_logger = Logger.getLogger(RabbitMQEventBus.class); + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + + _amqpHost = (String) params.get("server"); + if (_amqpHost == null || _amqpHost.isEmpty()) { + throw new ConfigurationException("Unable to get the AMQP server details"); + } + + _username = (String) params.get("username"); + if (_username == null || _username.isEmpty()) { + throw new ConfigurationException("Unable to get the username details"); + } + + _password = (String) params.get("password"); + if (_password == null || _password.isEmpty()) { + throw new ConfigurationException("Unable to get the password details"); + } + + _amqpExchangeName = (String) params.get("exchangename"); + if (_amqpExchangeName == null || _amqpExchangeName.isEmpty()) { + throw new ConfigurationException("Unable to get the _exchange details on the AMQP server"); + } + + try { + String portStr = (String) params.get("port"); + if (portStr == null || portStr.isEmpty()) { + throw new ConfigurationException("Unable to get the port details of AMQP server"); + } + _port = Integer.parseInt(portStr); + + String retryIntervalStr = (String) params.get("retryinterval"); + if (retryIntervalStr == null || retryIntervalStr.isEmpty()) { + // default to 10s to try out reconnect + retryIntervalStr = "10000"; + } + _retryInterval = Integer.parseInt(retryIntervalStr); + } catch (NumberFormatException e) { + throw new ConfigurationException("Invalid port number/retry interval"); + } + + _subscribers = new ConcurrentHashMap>(); + + executorService = Executors.newCachedThreadPool(); + disconnectHandler = new DisconnectHandler(); + _name = name; + return true; + } + + /** Call to subscribe to interested set of events + * + * @param topic defines category and type of the events being subscribed to + * @param subscriber subscriber that intends to receive event notification + * @return UUID that represents the subscription with event bus + * @throws EventBusException + */ + @Override + public UUID subscribe(EventTopic topic, EventSubscriber subscriber) throws EventBusException { + + if (subscriber == null || topic == null) { + throw new EventBusException("Invalid EventSubscriber/EventTopic object passed."); + } + + // create a UUID, that will be used for managing subscriptions and also used as queue name + // for on the queue used for the subscriber on the AMQP broker + UUID queueId = UUID.randomUUID(); + String queueName = queueId.toString(); + + try { + String bindingKey = createBindingKey(topic); + + // store the subscriber details before creating channel + _subscribers.put(queueName, new Ternary(bindingKey, null, subscriber)); + + // create a channel dedicated for this subscription + Connection connection = getConnection(); + Channel channel = createChannel(connection); + + // create a queue and bind it to the exchange with binding key formed from event topic + createExchange(channel, _amqpExchangeName); + channel.queueDeclare(queueName, false, false, false, null); + channel.queueBind(queueName, _amqpExchangeName, bindingKey); + + // register a callback handler to receive the events that a subscriber subscribed to + channel.basicConsume(queueName, _autoAck, queueName, + new DefaultConsumer(channel) { + @Override + public void handleDelivery(String queueName, + Envelope envelope, + AMQP.BasicProperties properties, + byte[] body) + throws IOException { + Ternary queueDetails = _subscribers.get(queueName); + if (queueDetails != null) { + EventSubscriber subscriber = queueDetails.third(); + String routingKey = envelope.getRoutingKey(); + String eventSource = getEventSourceFromRoutingKey(routingKey); + String eventCategory = getEventCategoryFromRoutingKey(routingKey); + String eventType = getEventTypeFromRoutingKey(routingKey); + String resourceType = getResourceTypeFromRoutingKey(routingKey); + String resourceUUID = getResourceUUIDFromRoutingKey(routingKey); + Event event = new Event(eventSource, eventCategory, eventType, + resourceType, resourceUUID); + event.setDescription(new String(body)); + + // deliver the event to call back object provided by subscriber + subscriber.onEvent(event); + } + } + } + ); + + // update the channel details for the subscription + Ternary queueDetails = _subscribers.get(queueName); + queueDetails.second(channel); + _subscribers.put(queueName, queueDetails); + + } catch (AlreadyClosedException closedException) { + s_logger.warn("Connection to AMQP service is lost. Subscription:" + queueName + + " will be active after reconnection"); + } catch (ConnectException connectException) { + s_logger.warn("Connection to AMQP service is lost. Subscription:" + queueName + + " will be active after reconnection"); + } catch (Exception e) { + throw new EventBusException("Failed to subscribe to event due to " + e.getMessage()); + } + + return queueId; + } + + @Override + public void unsubscribe(UUID subscriberId, EventSubscriber subscriber) throws EventBusException { + try { + String classname = subscriber.getClass().getName(); + String queueName = UUID.nameUUIDFromBytes(classname.getBytes()).toString(); + Ternary queueDetails = _subscribers.get(queueName); + Channel channel = queueDetails.second(); + channel.basicCancel(queueName); + _subscribers.remove(queueName, queueDetails); + } catch (Exception e) { + throw new EventBusException("Failed to unsubscribe from event bus due to " + e.getMessage()); + } + } + + // publish event on to the exchange created on AMQP server + @Override + public void publish(Event event) throws EventBusException { + + String routingKey = createRoutingKey(event); + String eventDescription = event.getDescription(); + + try { + Connection connection = getConnection(); + Channel channel = createChannel(connection); + createExchange(channel, _amqpExchangeName); + publishEventToExchange(channel, _amqpExchangeName, routingKey, eventDescription); + channel.close(); + } catch (AlreadyClosedException e) { + closeConnection(); + throw new EventBusException("Failed to publish event to message broker as connection to AMQP broker in lost"); + } catch (Exception e) { + throw new EventBusException("Failed to publish event to message broker due to " + e.getMessage()); + } + } + + /** creates a routing key from the event details. + * created routing key will be used while publishing the message to exchange on AMQP server + */ + private String createRoutingKey(Event event) { + + StringBuilder routingKey = new StringBuilder(); + + String eventSource = replaceNullWithWildcard(event.getEventSource()); + eventSource = eventSource.replace(".", "-"); + + String eventCategory = replaceNullWithWildcard(event.getEventCategory()); + eventCategory = eventCategory.replace(".", "-"); + + String eventType = replaceNullWithWildcard(event.getEventType()); + eventType = eventType.replace(".", "-"); + + String resourceType = replaceNullWithWildcard(event.getResourceType()); + resourceType = resourceType.replace(".", "-"); + + String resourceUuid = replaceNullWithWildcard(event.getResourceUUID()); + resourceUuid = resourceUuid.replace(".", "-"); + + // routing key will be of format: eventSource.eventCategory.eventType.resourceType.resourceUuid + routingKey.append(eventSource); + routingKey.append("."); + routingKey.append(eventCategory); + routingKey.append("."); + routingKey.append(eventType); + routingKey.append("."); + routingKey.append(resourceType); + routingKey.append("."); + routingKey.append(resourceUuid); + + return routingKey.toString(); + } + + /** creates a binding key from the event topic that subscriber specified + * binding key will be used to bind the queue created for subscriber to exchange on AMQP server + */ + private String createBindingKey(EventTopic topic) { + + StringBuilder bindingKey = new StringBuilder(); + + String eventSource = replaceNullWithWildcard(topic.getEventSource()); + eventSource = eventSource.replace(".", "-"); + + String eventCategory = replaceNullWithWildcard(topic.getEventCategory()); + eventCategory = eventCategory.replace(".", "-"); + + String eventType = replaceNullWithWildcard(topic.getEventType()); + eventType = eventType.replace(".", "-"); + + String resourceType = replaceNullWithWildcard(topic.getResourceType()); + resourceType = resourceType.replace(".", "-"); + + String resourceUuid = replaceNullWithWildcard(topic.getResourceUUID()); + resourceUuid = resourceUuid.replace(".", "-"); + + // binding key will be of format: eventSource.eventCategory.eventType.resourceType.resourceUuid + bindingKey.append(eventSource); + bindingKey.append("."); + bindingKey.append(eventCategory); + bindingKey.append("."); + bindingKey.append(eventType); + bindingKey.append("."); + bindingKey.append(resourceType); + bindingKey.append("."); + bindingKey.append(resourceUuid); + + return bindingKey.toString(); + } + + private synchronized Connection getConnection() throws Exception { + if (_connection == null) { + try { + return createConnection(); + } catch (Exception e) { + s_logger.error("Failed to create a connection to AMQP server due to " + e.getMessage()); + throw e; + } + } else { + return _connection; + } + } + + private synchronized Connection createConnection() throws Exception { + try { + ConnectionFactory factory = new ConnectionFactory(); + factory.setUsername(_username); + factory.setPassword(_password); + factory.setVirtualHost("/"); + factory.setHost(_amqpHost); + factory.setPort(_port); + Connection connection = factory.newConnection(); + connection.addShutdownListener(disconnectHandler); + _connection = connection; + return _connection; + } catch (Exception e) { + throw e; + } + } + + private synchronized void closeConnection() { + try { + if (_connection != null) { + _connection.close(); + } + } catch (Exception e) { + s_logger.warn("Failed to close connection to AMQP server due to " + e.getMessage()); + } + _connection = null; + } + + private synchronized void abortConnection () { + if (_connection == null) + return; + + try { + _connection.abort(); + } catch (Exception e) { + s_logger.warn("Failed to abort connection due to " + e.getMessage()); + } + _connection = null; + } + + private String replaceNullWithWildcard(String key) { + if (key == null || key.isEmpty()) { + return "*"; + } else { + return key; + } + } + + private Channel createChannel(Connection connection) throws Exception { + try { + return connection.createChannel(); + } catch (java.io.IOException exception) { + s_logger.warn("Failed to create a channel due to " + exception.getMessage()); + throw exception; + } + } + + private void createExchange(Channel channel, String exchangeName) throws Exception { + try { + channel.exchangeDeclare(exchangeName, "topic", true); + } catch (java.io.IOException exception) { + s_logger.error("Failed to create exchange" + exchangeName + " on RabbitMQ server"); + throw exception; + } + } + + private void publishEventToExchange(Channel channel, String exchangeName, + String routingKey, String eventDescription) throws Exception { + try { + byte[] messageBodyBytes = eventDescription.getBytes(); + channel.basicPublish(exchangeName, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, messageBodyBytes); + } catch (Exception e) { + s_logger.error("Failed to publish event " + routingKey + " on exchange " + exchangeName + + " of message broker due to " + e.getMessage()); + throw e; + } + } + + private String getEventCategoryFromRoutingKey(String routingKey) { + String[] keyParts = routingKey.split("\\."); + return keyParts[1]; + } + + private String getEventTypeFromRoutingKey(String routingKey) { + String[] keyParts = routingKey.split("\\."); + return keyParts[2]; + } + + private String getEventSourceFromRoutingKey(String routingKey) { + String[] keyParts = routingKey.split("\\."); + return keyParts[0]; + } + + private String getResourceTypeFromRoutingKey(String routingKey) { + String[] keyParts = routingKey.split("\\."); + return keyParts[3]; + } + + private String getResourceUUIDFromRoutingKey(String routingKey) { + String[] keyParts = routingKey.split("\\."); + return keyParts[4]; + } + + @Override + public String getName() { + return _name; + } + + @Override + public boolean start() { + ReconnectionTask reconnect = new ReconnectionTask(); // initiate connection to AMQP server + executorService.submit(reconnect); + return true; + } + + @Override + public boolean stop() { + + if (_connection.isOpen()) { + for (String subscriberId : _subscribers.keySet()) { + Ternary subscriberDetails = _subscribers.get(subscriberId); + Channel channel = subscriberDetails.second(); + String queueName = subscriberId; + try { + channel.queueDelete(queueName); + channel.abort(); + } catch (IOException ioe) { + s_logger.warn("Failed to delete queue: " + queueName + " on AMQP server due to " + ioe.getMessage() ); + } + } + } + + closeConnection(); + return true; + } + + // logic to deal with loss of connection to AMQP server + private class DisconnectHandler implements ShutdownListener { + + @Override + public void shutdownCompleted(ShutdownSignalException shutdownSignalException) { + if (!shutdownSignalException.isInitiatedByApplication()) { + + for (String subscriberId : _subscribers.keySet()) { + Ternary subscriberDetails = _subscribers.get(subscriberId); + subscriberDetails.second(null); + _subscribers.put(subscriberId, subscriberDetails); + } + + abortConnection(); // disconnected to AMQP server, so abort the connection and channels + s_logger.warn("Connection has been shutdown by AMQP server. Attempting to reconnect."); + + // initiate re-connect process + ReconnectionTask reconnect = new ReconnectionTask(); + executorService.submit(reconnect); + } + } + } + + // retry logic to connect back to AMQP server after loss of connection + private class ReconnectionTask implements Runnable { + + boolean connected = false; + Connection connection = null; + + public void run() { + + while (!connected) { + try { + Thread.sleep(_retryInterval); + } catch (InterruptedException ie) { + // ignore timer interrupts + } + + try { + try { + connection = createConnection(); + connected = true; + } catch (IOException ie) { + continue; // can't establish connection to AMQP server yet, so continue + } + + // prepare consumer on AMQP server for each of subscriber + for (String subscriberId : _subscribers.keySet()) { + Ternary subscriberDetails = _subscribers.get(subscriberId); + String bindingKey = subscriberDetails.first(); + EventSubscriber subscriber = subscriberDetails.third(); + + /** create a queue with subscriber ID as queue name and bind it to the exchange + * with binding key formed from event topic + */ + Channel channel = createChannel(connection); + createExchange(channel, _amqpExchangeName); + channel.queueDeclare(subscriberId, false, false, false, null); + channel.queueBind(subscriberId, _amqpExchangeName, bindingKey); + + // register a callback handler to receive the events that a subscriber subscribed to + channel.basicConsume(subscriberId, _autoAck, subscriberId, + new DefaultConsumer(channel) { + @Override + public void handleDelivery(String queueName, + Envelope envelope, + AMQP.BasicProperties properties, + byte[] body) + throws IOException { + + Ternary subscriberDetails + = _subscribers.get(queueName); // queue name == subscriber ID + + if (subscriberDetails != null) { + EventSubscriber subscriber = subscriberDetails.third(); + String routingKey = envelope.getRoutingKey(); + String eventSource = getEventSourceFromRoutingKey(routingKey); + String eventCategory = getEventCategoryFromRoutingKey(routingKey); + String eventType = getEventTypeFromRoutingKey(routingKey); + String resourceType = getResourceTypeFromRoutingKey(routingKey); + String resourceUUID = getResourceUUIDFromRoutingKey(routingKey); + + // create event object from the message details obtained from AMQP server + Event event = new Event(eventSource, eventCategory, eventType, + resourceType, resourceUUID); + event.setDescription(new String(body)); + + // deliver the event to call back object provided by subscriber + subscriber.onEvent(event); + } + } + } + ); + + // update the channel details for the subscription + subscriberDetails.second(channel); + _subscribers.put(subscriberId, subscriberDetails); + } + } catch (Exception e) { + s_logger.warn("Failed to recreate queues and binding for the subscribers due to " + e.getMessage()); + } + } + return; + } + } +} \ No newline at end of file diff --git a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java index 18abc59e30a..781b4b9b2f2 100644 --- a/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java +++ b/plugins/network-elements/ovs/src/com/cloud/network/guru/OvsGuestNetworkGuru.java @@ -19,6 +19,7 @@ package com.cloud.network.guru; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.event.ActionEventUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -27,7 +28,6 @@ import com.cloud.dc.DataCenter.NetworkType; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.event.EventTypes; -import com.cloud.event.EventUtils; import com.cloud.event.EventVO; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; import com.cloud.network.Network; @@ -99,7 +99,7 @@ public class OvsGuestNetworkGuru extends GuestNetworkGuru { throw new InsufficientVirtualNetworkCapcityException("Unable to allocate vnet as a part of network " + network + " implement ", DataCenter.class, dcId); } implemented.setBroadcastUri(BroadcastDomainType.Vswitch.toUri(vnet)); - EventUtils.saveEvent(UserContext.current().getCallerUserId(), network.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: "+vnet+ " Network Id: "+network.getId(), 0); + ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), network.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + network.getId(), 0); } else { implemented.setBroadcastUri(network.getBroadcastUri()); } diff --git a/plugins/pom.xml b/plugins/pom.xml index a3a3189a671..4daa71d9476 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -41,6 +41,7 @@ hypervisors/ovm hypervisors/xen hypervisors/kvm + event-bus/rabbitmq hypervisors/simulator hypervisors/baremetal hypervisors/ucs diff --git a/server/pom.xml b/server/pom.xml index 5160a8d09af..690f57fa350 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -95,6 +95,11 @@ cloud-api ${project.version} + + org.apache.cloudstack + cloud-framework-events + ${project.version} + install diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index cd29c7089c8..4545f0a5e99 100755 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -61,6 +61,7 @@ import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterIpAddressDao; import com.cloud.dc.dao.HostPodDao; +import com.cloud.event.AlertGenerator; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; @@ -246,6 +247,10 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { @Override public void sendAlert(short alertType, long dataCenterId, Long podId, String subject, String body) { + + // publish alert + AlertGenerator.publishAlertOnEventBus(getAlertType(alertType), dataCenterId, podId, subject, body); + // TODO: queue up these messages and send them as one set of issues once a certain number of issues is reached? If that's the case, // shouldn't we have a type/severity as part of the API so that severe errors get sent right away? try { @@ -257,6 +262,65 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { } } + private String getAlertType(short alertType) { + if (alertType == ALERT_TYPE_MEMORY) { + return "ALERT.MEMORY"; + } else if (alertType == ALERT_TYPE_CPU) { + return "ALERT.MEMORY"; + } else if (alertType == ALERT_TYPE_STORAGE) { + return "ALERT.STORAGE"; + } else if (alertType == ALERT_TYPE_STORAGE_ALLOCATED) { + return "ALERT.STORAGE.ALLOCATED"; + } else if (alertType == ALERT_TYPE_VIRTUAL_NETWORK_PUBLIC_IP) { + return "ALERT.NETWORK.PUBLICIP"; + } else if (alertType == ALERT_TYPE_PRIVATE_IP) { + return "ALERT.NETWORK.PRIVATEIP"; + } else if (alertType == ALERT_TYPE_SECONDARY_STORAGE) { + return "ALERT.STORAGE.SECONDARY"; + } else if (alertType == ALERT_TYPE_HOST) { + return "ALERT.COMPUTE.HOST"; + } else if (alertType == ALERT_TYPE_USERVM) { + return "ALERT.USERVM"; + } else if (alertType == ALERT_TYPE_DOMAIN_ROUTER) { + return "ALERT.SERVICE.DOMAINROUTER"; + } else if (alertType == ALERT_TYPE_CONSOLE_PROXY) { + return "ALERT.SERVICE.CONSOLEPROXY"; + } else if (alertType == ALERT_TYPE_ROUTING) { + return "ALERT.NETWORK.ROUTING"; + } else if (alertType == ALERT_TYPE_STORAGE_MISC) { + return "ALERT.STORAGE.MISC"; + } else if (alertType == ALERT_TYPE_USAGE_SERVER) { + return "ALERT.USAGE"; + } else if (alertType == ALERT_TYPE_MANAGMENT_NODE) { + return "ALERT.MANAGEMENT"; + } else if (alertType == ALERT_TYPE_DOMAIN_ROUTER_MIGRATE) { + return "ALERT.NETWORK.DOMAINROUTERMIGRATE"; + } else if (alertType == ALERT_TYPE_CONSOLE_PROXY_MIGRATE) { + return "ALERT.SERVICE.CONSOLEPROXYMIGRATE"; + } else if (alertType == ALERT_TYPE_USERVM_MIGRATE) { + return "ALERT.USERVM.MIGRATE"; + } else if (alertType == ALERT_TYPE_VLAN) { + return "ALERT.NETWORK.VLAN"; + } else if (alertType == ALERT_TYPE_SSVM) { + return "ALERT.SERVICE.SSVM"; + } else if (alertType == ALERT_TYPE_USAGE_SERVER_RESULT) { + return "ALERT.USAGE.RESULT"; + } else if (alertType == ALERT_TYPE_STORAGE_DELETE) { + return "ALERT.STORAGE.DELETE"; + } else if (alertType == ALERT_TYPE_UPDATE_RESOURCE_COUNT) { + return "ALERT.RESOURCE.COUNT"; + } else if (alertType == ALERT_TYPE_USAGE_SANITY_RESULT) { + return "ALERT.USAGE.SANITY"; + } else if (alertType == ALERT_TYPE_DIRECT_ATTACHED_PUBLIC_IP) { + return "ALERT.NETWORK.DIRECTPUBLICIP"; + } else if (alertType == ALERT_TYPE_LOCAL_STORAGE) { + return "ALERT.STORAGE.LOCAL"; + } else if (alertType == ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED) { + return "ALERT.RESOURCE.EXCEED"; + } + return "UNKNOWN"; + } + @Override @DB public void recalculateCapacity() { // FIXME: the right way to do this is to register a listener (see RouterStatsListener, VMSyncListener) diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index a464b936b88..8e950ab2356 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -83,6 +83,8 @@ import com.cloud.api.query.vo.StoragePoolJoinVO; import com.cloud.api.query.vo.UserAccountJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.api.query.vo.VolumeJoinVO; +import com.cloud.api.query.dao.*; +import com.cloud.api.query.vo.*; import com.cloud.async.AsyncJob; import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobVO; @@ -94,18 +96,8 @@ 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.AccountVlanMapVO; -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.dc.*; +import com.cloud.dc.dao.*; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.Event; @@ -164,17 +156,17 @@ import com.cloud.network.dao.Site2SiteCustomerGatewayDao; import com.cloud.network.dao.Site2SiteCustomerGatewayVO; import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; +import com.cloud.network.*; +import com.cloud.network.as.*; +import com.cloud.network.as.dao.*; +import com.cloud.network.dao.*; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallRuleVO; 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.StaticRouteVO; -import com.cloud.network.vpc.VpcGatewayVO; -import com.cloud.network.vpc.VpcManager; -import com.cloud.network.vpc.VpcOffering; -import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.*; import com.cloud.network.vpc.dao.StaticRouteDao; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpc.dao.VpcGatewayDao; @@ -189,57 +181,16 @@ import com.cloud.projects.ProjectAccount; import com.cloud.projects.ProjectInvitation; import com.cloud.projects.ProjectService; import com.cloud.resource.ResourceManager; -import com.cloud.server.Criteria; -import com.cloud.server.ManagementServer; -import com.cloud.server.ResourceTag; +import com.cloud.server.*; 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.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.*; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; -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.VolumeHostVO; -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.StoragePoolDao; -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.dao.*; import com.cloud.storage.snapshot.SnapshotPolicy; -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.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -801,7 +752,7 @@ public class ApiDBUtils { public static Snapshot findSnapshotById(long snapshotId) { SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - if (snapshot != null && snapshot.getRemoved() == null && snapshot.getStatus() == Snapshot.Status.BackedUp) { + if (snapshot != null && snapshot.getRemoved() == null && snapshot.getState() == Snapshot.State.BackedUp) { return snapshot; } else { return null; diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 9aae15421bd..3821aab272c 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -16,50 +16,8 @@ // under the License. package com.cloud.api; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.ResponseGenerator; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.api.ApiConstants.HostDetails; -import org.apache.cloudstack.api.ApiConstants.VMDetails; -import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; -import org.apache.cloudstack.api.response.AccountResponse; - import com.cloud.api.query.ViewResponseHelper; -import com.cloud.api.query.vo.AccountJoinVO; -import com.cloud.api.query.vo.AsyncJobJoinVO; -import com.cloud.api.query.vo.ControlledViewEntity; -import com.cloud.api.query.vo.DataCenterJoinVO; -import com.cloud.api.query.vo.DiskOfferingJoinVO; -import com.cloud.api.query.vo.DomainRouterJoinVO; -import com.cloud.api.query.vo.EventJoinVO; -import com.cloud.api.query.vo.HostJoinVO; -import com.cloud.api.query.vo.InstanceGroupJoinVO; -import com.cloud.api.query.vo.ProjectAccountJoinVO; -import com.cloud.api.query.vo.ProjectInvitationJoinVO; -import com.cloud.api.query.vo.ProjectJoinVO; -import com.cloud.api.query.vo.ResourceTagJoinVO; -import com.cloud.api.query.vo.SecurityGroupJoinVO; -import com.cloud.api.query.vo.ServiceOfferingJoinVO; -import com.cloud.api.query.vo.StoragePoolJoinVO; -import com.cloud.api.query.vo.UserAccountJoinVO; -import com.cloud.api.query.vo.UserVmJoinVO; -import com.cloud.api.query.vo.VolumeJoinVO; +import com.cloud.api.query.vo.*; import com.cloud.api.response.ApiResponseSerializer; import org.apache.cloudstack.api.response.AsyncJobResponse; import org.apache.cloudstack.api.response.AutoScalePolicyResponse; @@ -145,15 +103,8 @@ import com.cloud.configuration.Configuration; import com.cloud.configuration.Resource.ResourceOwnerType; import com.cloud.configuration.ResourceCount; import com.cloud.configuration.ResourceLimit; -import com.cloud.dc.ClusterVO; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.HostPodVO; -import com.cloud.dc.Pod; -import com.cloud.dc.StorageNetworkIpRange; -import com.cloud.dc.Vlan; +import com.cloud.dc.*; import com.cloud.dc.Vlan.VlanType; -import com.cloud.dc.VlanVO; import com.cloud.domain.Domain; import com.cloud.event.Event; import com.cloud.host.Host; @@ -186,12 +137,7 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.router.VirtualRouter; -import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.FirewallRuleVO; -import com.cloud.network.rules.LoadBalancer; -import com.cloud.network.rules.PortForwardingRule; -import com.cloud.network.rules.StaticNatRule; -import com.cloud.network.rules.StickinessPolicy; +import com.cloud.network.rules.*; import com.cloud.network.security.SecurityGroup; import com.cloud.network.security.SecurityRule; import com.cloud.network.security.SecurityRule.SecurityRuleType; @@ -209,25 +155,11 @@ import com.cloud.projects.ProjectInvitation; import com.cloud.server.Criteria; import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag.TaggedResourceType; -import com.cloud.storage.GuestOS; -import com.cloud.storage.GuestOSCategoryVO; -import com.cloud.storage.S3; -import com.cloud.storage.Snapshot; +import com.cloud.storage.*; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.StorageStats; -import com.cloud.storage.Swift; -import com.cloud.storage.UploadVO; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateS3VO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.VMTemplateSwiftVO; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeVO; import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.storage.snapshot.SnapshotSchedule; import com.cloud.template.VirtualMachineTemplate; @@ -244,6 +176,22 @@ import com.cloud.vm.InstanceGroup; import com.cloud.vm.NicProfile; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.ApiConstants.HostDetails; +import org.apache.cloudstack.api.ApiConstants.VMDetails; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.ResponseGenerator; +import org.apache.cloudstack.api.command.user.job.QueryAsyncJobResultCmd; +import org.apache.cloudstack.api.response.*; +import org.apache.cloudstack.region.Region; +import org.apache.log4j.Logger; + +import java.text.DecimalFormat; +import java.util.*; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; @Component public class ApiResponseHelper implements ResponseGenerator { @@ -381,7 +329,7 @@ public class ApiResponseHelper implements ResponseGenerator { snapshotResponse.setCreated(snapshot.getCreated()); snapshotResponse.setName(snapshot.getName()); snapshotResponse.setIntervalType(ApiDBUtils.getSnapshotIntervalTypes(snapshot.getId())); - snapshotResponse.setState(snapshot.getStatus()); + snapshotResponse.setState(snapshot.getState()); //set tag information List tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.Snapshot, snapshot.getId()); @@ -2741,6 +2689,16 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } + @Override + public RegionResponse createRegionResponse(Region region) { + RegionResponse response = new RegionResponse(); + response.setId(region.getId()); + response.setName(region.getName()); + response.setEndPoint(region.getEndPoint()); + response.setObjectName("region"); + return response; + } + @Override public ResourceTagResponse createResourceTagResponse(ResourceTag resourceTag, boolean keyValueOnly) { ResourceTagJoinVO rto = ApiDBUtils.newResourceTagView(resourceTag); @@ -3120,8 +3078,6 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } - - @Override public GuestOSResponse createGuestOSResponse(GuestOS guestOS) { GuestOSResponse response = new GuestOSResponse(); @@ -3160,5 +3116,4 @@ public class ApiResponseHelper implements ResponseGenerator { return response; } - } diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 80fffd3d8fd..aa281258d96 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -65,6 +65,10 @@ import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd; import org.apache.cloudstack.api.command.admin.user.ListUsersCmd; +import com.cloud.event.ActionEventUtils; +import com.cloud.utils.ReflectUtil; +import org.apache.cloudstack.acl.APILimitChecker; +import org.apache.cloudstack.api.*; import org.apache.cloudstack.api.command.user.account.ListAccountsCmd; import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd; import org.apache.cloudstack.api.command.user.event.ListEventsCmd; @@ -112,6 +116,8 @@ import org.springframework.stereotype.Component; import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd; import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; import com.cloud.api.response.ApiResponseSerializer; +import org.apache.cloudstack.region.RegionManager; + import com.cloud.async.AsyncCommandQueued; import com.cloud.async.AsyncJob; import com.cloud.async.AsyncJobManager; @@ -121,7 +127,6 @@ import com.cloud.configuration.ConfigurationVO; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; -import com.cloud.event.EventUtils; import com.cloud.exception.AccountLimitException; import com.cloud.exception.CloudAuthenticationException; import com.cloud.exception.InsufficientCapacityException; @@ -139,7 +144,6 @@ import com.cloud.user.UserContext; import com.cloud.user.UserVO; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.ReflectUtil; import com.cloud.utils.StringUtils; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.PluggableService; @@ -168,6 +172,8 @@ public class ApiServer implements HttpRequestHandler { private Account _systemAccount = null; private User _systemUser = null; + @Inject private RegionManager _regionMgr = null; + private static int _workerCount = 0; private static ApiServer s_instance = null; private static final DateFormat _dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); @@ -478,7 +484,7 @@ public class ApiServer implements HttpRequestHandler { asyncCmd.setStartEventId(startEventId); // save the scheduled event - Long eventId = EventUtils.saveScheduledEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, + Long eventId = ActionEventUtils.onScheduledActionEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), asyncCmd.getEventDescription(), startEventId); if (startEventId == 0) { diff --git a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java index cd3f2cbcea2..965c912a41e 100755 --- a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java +++ b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java @@ -31,7 +31,7 @@ import org.springframework.stereotype.Component; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.DataCenterVO; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.exception.ResourceAllocationException; import com.cloud.host.Host; import com.cloud.host.HostVO; @@ -84,9 +84,9 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem private void templateCreateUsage(VMTemplateVO template, HostVO host) { if (template.getAccountId() != Account.ACCOUNT_ID_SYSTEM) { - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, template.getAccountId(), host.getDataCenterId(), - template.getId(), template.getName(), null, template.getSourceTemplateId(), 0L); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_TEMPLATE_CREATE, template.getAccountId(), host.getDataCenterId(), + template.getId(), template.getName(), null, template.getSourceTemplateId(), 0L, + template.getClass().getName(), template.getUuid()); } } @@ -174,8 +174,8 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem _tmpltZoneDao.remove(templateZone.getId()); } - UsageEventVO usageEvent = new UsageEventVO(eventType, account.getId(), pxeServer.getDataCenterId(), templateId, null); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(eventType, account.getId(), pxeServer.getDataCenterId(), + templateId, null, template.getClass().getName(), template.getUuid()); } finally { if (lock != null) { _tmpltHostDao.releaseFromLockTable(lock.getId()); diff --git a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java index 411e27e23ab..8e447bc9aa6 100755 --- a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java @@ -40,8 +40,6 @@ import com.cloud.agent.api.baremetal.IpmISetBootDevCommand; import com.cloud.agent.api.baremetal.IpmiBootorResetCommand; import com.cloud.agent.manager.Commands; import org.apache.cloudstack.api.command.user.vm.StartVMCmd; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; import com.cloud.baremetal.PxeServerManager.PxeServerType; import com.cloud.configuration.Resource.ResourceType; @@ -52,14 +50,8 @@ import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.domain.DomainVO; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.exception.StorageUnavailableException; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.*; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; @@ -81,6 +73,7 @@ import com.cloud.user.AccountVO; import com.cloud.user.SSHKeyPair; import com.cloud.user.User; import com.cloud.user.UserContext; +import com.cloud.user.*; import com.cloud.uservm.UserVm; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; @@ -91,18 +84,10 @@ import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateListener; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.BareMetalVmService; -import com.cloud.vm.NicProfile; -import com.cloud.vm.NicVO; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmManagerImpl; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachine; +import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachine.Type; -import com.cloud.vm.VirtualMachineName; -import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfile.Param; @Local(value={BareMetalVmManager.class, BareMetalVmService.class}) @@ -373,8 +358,9 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet s_logger.debug("Successfully allocated DB entry for " + vm); } UserContext.current().setEventDetails("Vm Id: " + vm.getId()); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, accountId, cmd.getZoneId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), HypervisorType.BareMetal.toString()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, cmd.getZoneId(), vm.getId(), + vm.getHostName(), offering.getId(), template.getId(), HypervisorType.BareMetal.toString(), + VirtualMachine.class.getName(), vm.getUuid()); _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.user_vm); diff --git a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java b/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java index ced2618cec6..13a22dbe827 100644 --- a/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java +++ b/server/src/com/cloud/configuration/DefaultInterceptorLibrary.java @@ -16,18 +16,18 @@ // under the License. package com.cloud.configuration; -import java.util.List; - -import com.cloud.event.ActionEventCallback; +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 ActionEventCallback()); + interceptors.add(new ActionEventUtils.ActionEventCallback()); } } diff --git a/server/src/com/cloud/domain/DomainVO.java b/server/src/com/cloud/domain/DomainVO.java index bb4ce0cecf7..346e19f8f06 100644 --- a/server/src/com/cloud/domain/DomainVO.java +++ b/server/src/com/cloud/domain/DomainVO.java @@ -75,15 +75,12 @@ public class DomainVO implements Domain { @Column(name="uuid") private String uuid; + @Column(name="region_id") + private int regionId; + public DomainVO() {} - - public DomainVO(long id, String name, long owner, Long parentId, String networkDomain) { - this(name, owner, parentId, networkDomain); - this.id = id; - this.uuid = UUID.randomUUID().toString(); - } - - public DomainVO(String name, long owner, Long parentId, String networkDomain) { + + public DomainVO(String name, long owner, Long parentId, String networkDomain, int regionId) { this.parent = parentId; this.name = name; this.accountId = owner; @@ -92,8 +89,21 @@ public class DomainVO implements Domain { this.state = Domain.State.Active; this.networkDomain = networkDomain; this.uuid = UUID.randomUUID().toString(); + this.regionId = regionId; } + public DomainVO(String name, long owner, Long parentId, String networkDomain, String uuid, int regionId) { + this.parent = parentId; + this.name = name; + this.accountId = owner; + this.path =""; + this.level = 0; + this.state = Domain.State.Active; + this.networkDomain = networkDomain; + this.uuid = uuid; + this.regionId = regionId; + } + @Override public long getId() { return id; @@ -205,5 +215,13 @@ public class DomainVO implements Domain { public void setUuid(String uuid) { this.uuid = uuid; } + + public int getRegionId() { + return regionId; + } + + public void setRegionId(int regionId) { + this.regionId = regionId; + } } diff --git a/server/src/com/cloud/domain/dao/DomainDaoImpl.java b/server/src/com/cloud/domain/dao/DomainDaoImpl.java index 3b17a14839d..79ef17ed2a6 100644 --- a/server/src/com/cloud/domain/dao/DomainDaoImpl.java +++ b/server/src/com/cloud/domain/dao/DomainDaoImpl.java @@ -32,7 +32,6 @@ import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; @@ -272,4 +271,5 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom return parentDomains; } + } diff --git a/server/src/com/cloud/event/ActionEventCallback.java b/server/src/com/cloud/event/ActionEventCallback.java deleted file mode 100644 index f941400de64..00000000000 --- a/server/src/com/cloud/event/ActionEventCallback.java +++ /dev/null @@ -1,135 +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.event; - -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.user.UserContext; -import com.cloud.utils.component.AnnotationInterceptor; - -public 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(); - } - EventUtils.saveStartedEvent(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 = EventUtils.saveCreatedEvent(userId, accountId, EventVO.LEVEL_INFO, actionEvent.eventType(), "Successfully created entity for "+eventDescription); - ctx.setStartEventId(startEventId); - } else { - EventUtils.saveEvent(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 = EventUtils.saveCreatedEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while creating entity for "+eventDescription); - ctx.setStartEventId(eventId); - } else { - EventUtils.saveEvent(userId, accountId, EventVO.LEVEL_ERROR, actionEvent.eventType(), "Error while "+eventDescription, startEventId); - } - } - } - - @Override - public Callback getCallback() { - return this; - } - -} diff --git a/server/src/com/cloud/event/ActionEventUtils.java b/server/src/com/cloud/event/ActionEventUtils.java new file mode 100755 index 00000000000..22589f1a292 --- /dev/null +++ b/server/src/com/cloud/event/ActionEventUtils.java @@ -0,0 +1,296 @@ +// 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.event; + +import com.cloud.event.dao.EventDao; +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 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; +import org.springframework.stereotype.Component; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +@Component +public class ActionEventUtils { + private static final Logger s_logger = Logger.getLogger(ActionEventUtils.class); + + private static EventDao _eventDao; + private static AccountDao _accountDao; + protected static UserDao _userDao; + + // get the event bus provider if configured + protected static EventBus _eventBus; + + @Inject EventDao eventDao; + @Inject AccountDao accountDao; + @Inject UserDao userDao; + + public ActionEventUtils() { + } + + @PostConstruct + void init() { + _eventDao = eventDao; + _accountDao = accountDao; + _userDao = userDao; + + // TODO we will do injection of event bus later + } + + public static Long onActionEvent(Long userId, Long accountId, Long domainId, String type, String description) { + + publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), + type, com.cloud.event.Event.State.Completed); + + Event event = persistActionEvent(userId, accountId, domainId, null, type, Event.State.Completed, + description, null); + + return event.getId(); + } + + /* + * Save event after scheduling an async job + */ + public static Long onScheduledActionEvent(Long userId, Long accountId, String type, String description, + long startEventId) { + + publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type, + com.cloud.event.Event.State.Scheduled); + + Event event = persistActionEvent(userId, accountId, null, null, type, Event.State.Scheduled, + description, startEventId); + + return event.getId(); + } + + /* + * Save event after starting execution of an async job + */ + public static Long onStartedActionEvent(Long userId, Long accountId, String type, String description, + long startEventId) { + + publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type, + com.cloud.event.Event.State.Started); + + Event event = persistActionEvent(userId, accountId, null, null, type, Event.State.Started, + description, startEventId); + return event.getId(); + } + + public static Long onCompletedActionEvent(Long userId, Long accountId, String level, String type, + String description, long startEventId) { + + publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type, + com.cloud.event.Event.State.Completed); + + Event event = persistActionEvent(userId, accountId, null, level, type, Event.State.Completed, + description, startEventId); + + return event.getId(); + } + + public static Long onCreatedActionEvent(Long userId, Long accountId, String level, String type, String description) { + + publishOnEventBus(userId, accountId, EventCategory.ACTION_EVENT.getName(), type, + com.cloud.event.Event.State.Created); + + Event event = persistActionEvent(userId, accountId, null, level, type, Event.State.Created, description, null); + + return event.getId(); + } + + private static Event persistActionEvent(Long userId, Long accountId, Long domainId, String level, String type, + Event.State state, String description, Long startEventId) { + EventVO event = new EventVO(); + event.setUserId(userId); + event.setAccountId(accountId); + event.setType(type); + event.setState(state); + event.setDescription(description); + if (domainId != null) { + event.setDomainId(domainId); + } else { + event.setDomainId(getDomainId(accountId)); + } + if (level != null && !level.isEmpty()) { + event.setLevel(level); + } + if (startEventId != null) { + event.setStartId(startEventId); + } + event = _eventDao.persist(event); + return event; + } + + private static void publishOnEventBus(long userId, long accountId, String eventCategory, + String eventType, Event.State state) { + if (_eventBus == null) { + return; // no provider is configured to provide events bus, so just return + } + + org.apache.cloudstack.framework.events.Event event = new org.apache.cloudstack.framework.events.Event( + ManagementServer.Name, + eventCategory, + eventType, + EventTypes.getEntityForEvent(eventType), null); + + Map eventDescription = new HashMap(); + Account account = _accountDao.findById(accountId); + User user = _userDao.findById(userId); + eventDescription.put("user", user.getUuid()); + eventDescription.put("account", account.getUuid()); + eventDescription.put("event", eventType); + eventDescription.put("status", state.toString()); + event.setDescription(eventDescription); + + try { + _eventBus.publish(event); + } catch (EventBusException e) { + s_logger.warn("Failed to publish action event on the the event bus."); + } + } + + private static long getDomainId(long accountId){ + 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/server/src/com/cloud/event/AlertGenerator.java b/server/src/com/cloud/event/AlertGenerator.java new file mode 100644 index 00000000000..2dc7f3eb9e1 --- /dev/null +++ b/server/src/com/cloud/event/AlertGenerator.java @@ -0,0 +1,93 @@ +// 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.event; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.server.ManagementServer; +import org.apache.cloudstack.framework.events.*; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +@Component +public class AlertGenerator { + + private static final Logger s_logger = Logger.getLogger(AlertGenerator.class); + private static DataCenterDao _dcDao; + private static HostPodDao _podDao; + + // get the event bus provider if configured + protected static EventBus _eventBus = null; + + @Inject DataCenterDao dcDao; + @Inject HostPodDao podDao; + + public AlertGenerator() { + } + + @PostConstruct + void init() { + _dcDao = dcDao; + _podDao = podDao; + } + + public static void publishAlertOnEventBus(String alertType, long dataCenterId, Long podId, String subject, String body) { + if (_eventBus == null) { + return; // no provider is configured to provider events bus, so just return + } + + org.apache.cloudstack.framework.events.Event event = + new org.apache.cloudstack.framework.events.Event(ManagementServer.Name, + EventCategory.ALERT_EVENT.getName(), + alertType, + null, + null); + + Map eventDescription = new HashMap(); + DataCenterVO dc = _dcDao.findById(dataCenterId); + HostPodVO pod = _podDao.findById(podId); + + eventDescription.put("event", alertType); + if (dc != null) { + eventDescription.put("dataCenterId", dc.getUuid()); + } else { + eventDescription.put("dataCenterId", null); + } + if (pod != null) { + eventDescription.put("podId", pod.getUuid()); + } else { + eventDescription.put("podId", null); + } + event.setDescription(eventDescription); + + try { + _eventBus.publish(event); + } catch (EventBusException e) { + s_logger.warn("Failed to publish alert on the the event bus."); + } + } +} diff --git a/server/src/com/cloud/event/UsageEventUtils.java b/server/src/com/cloud/event/UsageEventUtils.java new file mode 100644 index 00000000000..d59262af2ba --- /dev/null +++ b/server/src/com/cloud/event/UsageEventUtils.java @@ -0,0 +1,143 @@ +// 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.event; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.server.ManagementServer; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; +import org.apache.cloudstack.framework.events.EventBus; +import org.apache.cloudstack.framework.events.Event; +import org.apache.cloudstack.framework.events.EventBusException; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +@Component +public class UsageEventUtils { + + private static UsageEventDao _usageEventDao; + private static AccountDao _accountDao; + private static DataCenterDao _dcDao; + private static final Logger s_logger = Logger.getLogger(UsageEventUtils.class); + + // get the event bus provider if configured + protected static EventBus _eventBus; + + @Inject UsageEventDao usageEventDao; + @Inject AccountDao accountDao; + @Inject DataCenterDao dcDao; + + public UsageEventUtils() { + } + + @PostConstruct + void init() { + _usageEventDao = usageEventDao; + _accountDao = accountDao; + _dcDao = dcDao; + } + + public static void publishUsageEvent(String usageType, long accountId, long zoneId, + long resourceId, String resourceName, + Long offeringId, Long templateId, Long size, + String entityType, String entityUUID) { + saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size); + publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID); + } + + public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId, + String resourceName, String entityType, String entityUUID) { + saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName); + publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID); + } + + public static void publishUsageEvent(String usageType, long accountId, long zoneId, + long ipAddressId, String ipAddress, boolean isSourceNat, + String guestType, boolean isSystem, String entityType, String entityUUID) { + saveUsageEvent(usageType, accountId, zoneId, ipAddressId, ipAddress, isSourceNat, guestType, isSystem); + publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID); + } + + public static void publishUsageEvent(String usageType, long accountId, long zoneId, long resourceId, + String resourceName, Long offeringId, Long templateId, String resourceType, + String entityType, String entityUUID) { + saveUsageEvent(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, resourceType); + publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID); + } + + public static void publishUsageEvent(String usageType, long accountId,long zoneId, long vmId, + long securityGroupId, String entityType, String entityUUID) { + saveUsageEvent(usageType, accountId, zoneId, vmId, securityGroupId); + publishUsageEvent(usageType, accountId, zoneId, entityType, entityUUID); + } + + public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId, Long size) { + _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, size)); + } + + public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName) { + _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName)); + } + + public static void saveUsageEvent(String usageType, long accountId, long zoneId, long ipAddressId, String ipAddress, boolean isSourceNat, String guestType, boolean isSystem) { + _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, ipAddressId, ipAddress, isSourceNat, guestType, isSystem)); + } + + public static void saveUsageEvent(String usageType, long accountId, long zoneId, long resourceId, String resourceName, Long offeringId, Long templateId, String resourceType) { + _usageEventDao.persist( new UsageEventVO(usageType, accountId, zoneId, resourceId, resourceName, offeringId, templateId, resourceType)); + } + + public static void saveUsageEvent(String usageType, long accountId,long zoneId, long vmId, long securityGroupId) { + _usageEventDao.persist( new UsageEventVO( usageType, accountId, zoneId, vmId, securityGroupId)); + } + + private static void publishUsageEvent(String usageEventType, Long accountId, Long zoneId, String resourceType, String resourceUUID) { + + if (_eventBus == null) { + return; // no provider is configured to provider events bus, so just return + } + + Account account = _accountDao.findById(accountId); + DataCenterVO dc = _dcDao.findById(zoneId); + + Event event = new Event(ManagementServer.Name, EventCategory.USAGE_EVENT.getName(), usageEventType, + resourceType, resourceUUID); + + Map eventDescription = new HashMap(); + eventDescription.put("account", account.getUuid()); + eventDescription.put("zone", dc.getUuid()); + eventDescription.put("event", usageEventType); + eventDescription.put("resource", resourceType); + eventDescription.put("id", resourceUUID); + event.setDescription(eventDescription); + + try { + _eventBus.publish(event); + } catch (EventBusException e) { + s_logger.warn("Failed to publish usage event on the the event bus."); + } + } +} diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 643f1a48276..68e100fee1d 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -43,14 +43,7 @@ import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; -import com.cloud.agent.api.AgentControlAnswer; -import com.cloud.agent.api.AgentControlCommand; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.CheckNetworkAnswer; -import com.cloud.agent.api.CheckNetworkCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.StartupCommand; -import com.cloud.agent.api.StartupRoutingCommand; +import com.cloud.agent.api.*; import com.cloud.agent.api.to.NicTO; import com.cloud.alert.AlertManager; import com.cloud.api.ApiDBUtils; @@ -58,15 +51,9 @@ import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.AccountVlanMapVO; -import com.cloud.dc.DataCenter; +import com.cloud.dc.*; import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.Pod; -import com.cloud.dc.PodVlanMapVO; -import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; -import com.cloud.dc.VlanVO; import com.cloud.dc.dao.AccountVlanMapDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.PodVlanMapDao; @@ -77,29 +64,16 @@ import com.cloud.deploy.DeploymentPlan; import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.AccountLimitException; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.ConnectionException; -import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientVirtualNetworkCapcityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.exception.UnsupportedServiceException; +import com.cloud.exception.*; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress.State; -import com.cloud.network.Network.Capability; -import com.cloud.network.Network.GuestType; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; +import com.cloud.network.Network.*; import com.cloud.network.Networks.AddressFormat; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.IsolationType; @@ -132,15 +106,8 @@ import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; import com.cloud.network.lb.LoadBalancingRulesManager; -import com.cloud.network.rules.FirewallManager; -import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.*; import com.cloud.network.rules.FirewallRule.Purpose; -import com.cloud.network.rules.FirewallRuleVO; -import com.cloud.network.rules.PortForwardingRuleVO; -import com.cloud.network.rules.RulesManager; -import com.cloud.network.rules.StaticNat; -import com.cloud.network.rules.StaticNatRule; -import com.cloud.network.rules.StaticNatRuleImpl; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.NetworkACLManager; import com.cloud.network.vpc.VpcManager; @@ -153,39 +120,23 @@ import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.org.Grouping; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.User; -import com.cloud.user.UserContext; +import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; +import com.cloud.utils.db.*; import com.cloud.utils.db.JoinBuilder.JoinType; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.Nic; -import com.cloud.vm.NicProfile; -import com.cloud.vm.NicVO; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.ReservationContextImpl; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; +import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Type; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.VirtualMachineProfileImpl; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; @@ -231,8 +182,6 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @Inject LoadBalancingRulesManager _lbMgr; @Inject - UsageEventDao _usageEventDao; - @Inject RemoteAccessVpnService _vpnMgr; @Inject PodVlanMapDao _podVlanMapDao; @@ -282,12 +231,18 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L @Inject NetworkACLManager _networkACLMgr; @Inject + UsageEventDao _usageEventDao; + @Inject NetworkModel _networkModel; @Inject UserIpv6AddressDao _ipv6Dao; @Inject Ipv6AddressManager _ipv6Mgr; + protected StateMachine2 _stateMachine; + private final HashMap _systemNetworks = new HashMap(5); + private static Long _privateOfferingId = null; + ScheduledExecutorService _executor; SearchBuilder AssignIpAddressSearch; @@ -419,11 +374,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L VlanVO vlan = _vlanDao.findById(addr.getVlanId()); String guestType = vlan.getVlanType().toString(); - - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(), addr.getAddress().toString(), addr.isSourceNat(), guestType, - addr.getSystem()); - _usageEventDao.persist(usageEvent); + addr.getSystem(), addr.getClass().getName(), addr.getUuid()); // don't increment resource count for direct ip addresses if (addr.getAssociatedWithNetworkId() != null) { _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip); @@ -1058,6 +1011,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L _agentMgr.registerForHostEvents(this, true, false, true); + Network.State.getStateMachine().registerListener(new NetworkStateListener(_usageEventDao, _networksDao)); + s_logger.info("Network Manager is configured."); return true; @@ -1075,6 +1030,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L } protected NetworkManagerImpl() { + setStateMachine(); } @Override @@ -1434,9 +1390,7 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L NetworkOfferingVO offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); network.setReservationId(context.getReservationId()); - network.setState(Network.State.Implementing); - - _networksDao.update(networkId, network); + stateTransitTo(network, Event.ImplementNetwork); Network result = guru.implement(network, offering, dest, context); network.setCidr(result.getCidr()); @@ -1449,16 +1403,23 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L // implement network elements and re-apply all the network rules implementNetworkElementsAndResources(dest, context, network, offering); - network.setState(Network.State.Implemented); + stateTransitTo(network,Event.OperationSucceeded); + network.setRestartRequired(false); _networksDao.update(network.getId(), network); implemented.set(guru, network); return implemented; + } catch (NoTransitionException e) { + s_logger.error(e.getMessage()); + return null; } finally { if (implemented.first() == null) { s_logger.debug("Cleaning up because we're unable to implement the network " + network); - network.setState(Network.State.Shutdown); - _networksDao.update(networkId, network); + try { + stateTransitTo(network,Event.OperationFailed); + } catch (NoTransitionException e) { + s_logger.error(e.getMessage()); + } shutdownNetwork(networkId, context, false); } @@ -2080,9 +2041,12 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L s_logger.debug("Network is not implemented: " + network); return false; } - + try { + stateTransitTo(network, Event.DestroyNetwork); + } catch (NoTransitionException e) { network.setState(Network.State.Shutdown); _networksDao.update(network.getId(), network); + } boolean success = shutdownNetworkElementsAndResources(context, cleanupElements, network); @@ -2097,15 +2061,22 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L guru.shutdown(profile, _networkOfferingDao.findById(network.getNetworkOfferingId())); applyProfileToNetwork(network, profile); - + try { + stateTransitTo(network, Event.OperationSucceeded); + } catch (NoTransitionException e) { network.setState(Network.State.Allocated); network.setRestartRequired(false); + } _networksDao.update(network.getId(), network); _networksDao.clearCheckForGc(networkId); result = true; } else { + try { + stateTransitTo(network, Event.OperationFailed); + } catch (NoTransitionException e) { network.setState(Network.State.Implemented); _networksDao.update(network.getId(), network); + } result = false; } txn.commit(); @@ -2265,8 +2236,11 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L s_logger.warn("Failed to delete network " + network + "; was unable to cleanup corresponding ip ranges"); } else { // commit transaction only when ips and vlans for the network are released successfully - network.setState(Network.State.Destroy); - _networksDao.update(network.getId(), network); + try { + stateTransitTo(network, Event.DestroyNetwork); + } catch (NoTransitionException e) { + s_logger.debug(e.getMessage()); + } _networksDao.remove(network.getId()); NetworkOffering ntwkOff = _configMgr.getNetworkOffering(network.getNetworkOfferingId()); @@ -2772,10 +2746,9 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L String guestType = vlan.getVlanType().toString(); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_IP_RELEASE, + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(), - ip.isSourceNat(), guestType, ip.getSystem()); - _usageEventDao.persist(usageEvent); + ip.isSourceNat(), guestType, ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } ip = _ipAddressDao.markAsUnavailable(addrId); @@ -3522,6 +3495,15 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L return _networkLockTimeout; } + + protected boolean stateTransitTo(NetworkVO network, Network.Event e) throws NoTransitionException { + return _stateMachine.transitTo(network, e, null, _networksDao); + } + + private void setStateMachine() { + _stateMachine = Network.State.getStateMachine(); + } + private Map> getServiceProvidersMap(long networkId) { Map> map = new HashMap>(); List nsms = _ntwkSrvcDao.getServicesInNetwork(networkId); diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index f0282abee1d..6872c3f8401 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -58,17 +58,10 @@ import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientAddressCapacityException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.exception.UnsupportedServiceException; +import com.cloud.exception.*; import com.cloud.network.IpAddress.State; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; @@ -93,6 +86,7 @@ import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao; import com.cloud.network.dao.PhysicalNetworkTrafficTypeVO; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.dao.*; import com.cloud.network.element.NetworkElement; import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.element.VpcVirtualRouterElement; @@ -113,13 +107,7 @@ import com.cloud.projects.ProjectManager; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.AccountVO; -import com.cloud.user.DomainManager; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.User; -import com.cloud.user.UserContext; +import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.utils.AnnotationHelper; import com.cloud.utils.NumbersUtil; @@ -131,20 +119,15 @@ import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.*; import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.NicVO; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.ReservationContextImpl; -import com.cloud.vm.SecondaryStorageVmVO; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; +import com.cloud.vm.*; import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import java.util.*; /** * NetworkServiceImpl implements NetworkService. @@ -1688,10 +1671,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { continue; } long isDefault = (nic.isDefaultNic()) ? 1 : 0; - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), null, oldNetworkOfferingId, null, 0L); - _usageEventDao.persist(usageEvent); - usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getHostName(), networkOfferingId, null, isDefault); - _usageEventDao.persist(usageEvent); + UsageEventUtils.saveUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), null, oldNetworkOfferingId, null, 0L); + UsageEventUtils.saveUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), vm.getHostName(), networkOfferingId, null, isDefault); } txn.commit(); } else { diff --git a/server/src/com/cloud/network/NetworkStateListener.java b/server/src/com/cloud/network/NetworkStateListener.java new file mode 100644 index 00000000000..bafe6d2d1f9 --- /dev/null +++ b/server/src/com/cloud/network/NetworkStateListener.java @@ -0,0 +1,98 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.network; + +import com.cloud.event.EventCategory; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.network.Network.Event; +import com.cloud.network.Network.State; +import com.cloud.network.dao.NetworkDao; +import com.cloud.server.ManagementServer; +import com.cloud.utils.fsm.StateListener; +import org.apache.cloudstack.framework.events.EventBus; +import org.apache.cloudstack.framework.events.EventBusException; +import org.apache.log4j.Logger; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +public class NetworkStateListener implements StateListener { + + @Inject protected UsageEventDao _usageEventDao; + @Inject protected NetworkDao _networkDao; + + // get the event bus provider if configured + @Inject protected EventBus _eventBus; + + private static final Logger s_logger = Logger.getLogger(NetworkStateListener.class); + + public NetworkStateListener(UsageEventDao usageEventDao, NetworkDao networkDao) { + this._usageEventDao = usageEventDao; + this._networkDao = networkDao; + } + + @Override + public boolean preStateTransitionEvent(State oldState, Event event, State newState, Network vo, boolean status, Object opaque) { + pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState); + return true; + } + + @Override + public boolean postStateTransitionEvent(State oldState, Event event, State newState, Network vo, boolean status, Object opaque) { + pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); + return true; + } + + private void pubishOnEventBus(String event, String status, Network vo, State oldState, State newState) { + + if (_eventBus == null) { + return; // no provider is configured to provide events bus, so just return + } + + String resourceName = getEntityFromClassName(Network.class.getName()); + org.apache.cloudstack.framework.events.Event eventMsg = new org.apache.cloudstack.framework.events.Event( + ManagementServer.Name, + EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(), + event, + resourceName, + vo.getUuid()); + Map eventDescription = new HashMap(); + eventDescription.put("resource", resourceName); + eventDescription.put("id", vo.getUuid()); + eventDescription.put("old-state", oldState.name()); + eventDescription.put("new-state", newState.name()); + eventMsg.setDescription(eventDescription); + try { + _eventBus.publish(eventMsg); + } catch (EventBusException e) { + s_logger.warn("Failed to publish state change event on the the event bus."); + } + } + + private String getEntityFromClassName(String entityClassName) { + int index = entityClassName.lastIndexOf("."); + String entityName = entityClassName; + if (index != -1) { + entityName = entityClassName.substring(index+1); + } + return entityName; + } +} diff --git a/server/src/com/cloud/network/dao/NetworkDao.java b/server/src/com/cloud/network/dao/NetworkDao.java index 342a2c5017d..1d3f0b84aa6 100644 --- a/server/src/com/cloud/network/dao/NetworkDao.java +++ b/server/src/com/cloud/network/dao/NetworkDao.java @@ -22,10 +22,12 @@ import java.util.Map; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.network.Networks.TrafficType; +import com.cloud.network.Network.State; import com.cloud.utils.db.GenericDao; import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.fsm.StateDao; -public interface NetworkDao extends GenericDao { +public interface NetworkDao extends GenericDao , StateDao { List listByOwner(long ownerId); diff --git a/server/src/com/cloud/network/dao/NetworkDaoImpl.java b/server/src/com/cloud/network/dao/NetworkDaoImpl.java index 60f421bab75..8fadf041762 100644 --- a/server/src/com/cloud/network/dao/NetworkDaoImpl.java +++ b/server/src/com/cloud/network/dao/NetworkDaoImpl.java @@ -32,6 +32,8 @@ import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; +import com.cloud.network.Network.State; +import com.cloud.network.Network.Event; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.TrafficType; @@ -44,13 +46,10 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.*; import com.cloud.utils.db.JoinBuilder.JoinType; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.SequenceFetcher; -import com.cloud.utils.db.Transaction; import com.cloud.utils.net.NetUtils; @Component @@ -566,6 +565,20 @@ public class NetworkDaoImpl extends GenericDaoBase implements N return customSearch(sc, null).get(0); } + @Override + public boolean updateState(State currentState, Event event, State nextState, Network vo, Object data) { + // TODO: ensure this update is correct + Transaction txn = Transaction.currentTxn(); + txn.start(); + + NetworkVO networkVo = (NetworkVO) vo; + networkVo.setState(nextState); + super.update(networkVo.getId(), networkVo); + + txn.commit(); + return true; + } + @Override public List listNetworksByAccount(long accountId, long zoneId, Network.GuestType type, boolean isSystem) { SearchCriteria sc = OfferingAccountNetworkSearch.create(); @@ -582,7 +595,6 @@ public class NetworkDaoImpl extends GenericDaoBase implements N public List listRedundantNetworks() { SearchCriteria sc = AllFieldsSearch.create(); sc.setJoinParameters("offerings", "isRedundant", true); - return listBy(sc, null); } } diff --git a/server/src/com/cloud/network/dao/NetworkVO.java b/server/src/com/cloud/network/dao/NetworkVO.java index 5ecb22f24e3..d51a065ff83 100644 --- a/server/src/com/cloud/network/dao/NetworkVO.java +++ b/server/src/com/cloud/network/dao/NetworkVO.java @@ -259,6 +259,7 @@ public class NetworkVO implements Network { return state; } + // don't use this directly when possible, use Network state machine instead public void setState(State state) { this.state = state; } diff --git a/server/src/com/cloud/network/dao/UserIpv6AddressDao.java b/server/src/com/cloud/network/dao/UserIpv6AddressDao.java index 0e245efcde1..81e0da83764 100644 --- a/server/src/com/cloud/network/dao/UserIpv6AddressDao.java +++ b/server/src/com/cloud/network/dao/UserIpv6AddressDao.java @@ -1,3 +1,19 @@ +// 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.dao; import java.util.List; diff --git a/server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java b/server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java index 14935c3f762..8a1115dd3b6 100644 --- a/server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/UserIpv6AddressDaoImpl.java @@ -1,3 +1,19 @@ +// 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.dao; import java.util.List; diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java index 7bce18cd00f..d3b4c0beabf 100644 --- a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -42,7 +42,7 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; @@ -64,15 +64,10 @@ import com.cloud.network.element.FirewallServiceProvider; import com.cloud.network.element.NetworkACLServiceProvider; import com.cloud.network.element.PortForwardingServiceProvider; import com.cloud.network.element.StaticNatServiceProvider; -import com.cloud.network.rules.FirewallManager; -import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.*; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; -import com.cloud.network.rules.FirewallRuleVO; -import com.cloud.network.rules.PortForwardingRule; -import com.cloud.network.rules.PortForwardingRuleVO; -import com.cloud.network.rules.StaticNat; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.VpcManager; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -85,15 +80,14 @@ import com.cloud.user.DomainManager; import com.cloud.user.UserContext; 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.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.*; import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.UserVmVO; @@ -692,8 +686,8 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, } if (generateUsageEvent && needUsageEvent) { - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_DELETE, rule.getAccountId(), 0, rule.getId(), null); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_RULE_DELETE, rule.getAccountId(), 0, rule.getId(), + null, rule.getClass().getName(), rule.getUuid()); } txn.commit(); diff --git a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java index 37cd7d49ff7..b1606db71b1 100644 --- a/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -21,6 +21,7 @@ import java.util.List; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.event.ActionEventUtils; import org.apache.log4j.Logger; import com.cloud.configuration.Config; @@ -30,7 +31,6 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.event.EventTypes; -import com.cloud.event.EventUtils; import com.cloud.event.EventVO; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; @@ -139,7 +139,7 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { } implemented.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlanTag)); - EventUtils.saveEvent(UserContext.current().getCallerUserId(), config.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: "+vnet+ " Network Id: "+config.getId(), 0); + ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), config.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + config.getId(), 0); } else { vlanTag = Integer.parseInt(config.getBroadcastUri().getHost()); implemented.setBroadcastUri(config.getBroadcastUri()); diff --git a/server/src/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/com/cloud/network/guru/GuestNetworkGuru.java index bca511499b1..ab8a06958da 100755 --- a/server/src/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/com/cloud/network/guru/GuestNetworkGuru.java @@ -19,13 +19,13 @@ package com.cloud.network.guru; import java.util.ArrayList; import java.util.List; import java.util.Random; -import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.ejb.Local; import javax.inject.Inject; +import com.cloud.event.ActionEventUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -38,7 +38,6 @@ import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.event.EventTypes; -import com.cloud.event.EventUtils; import com.cloud.event.EventVO; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapcityException; @@ -300,8 +299,8 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur "part of network " + network + " implement ", DataCenter.class, dcId); } implemented.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vnet)); - EventUtils.saveEvent(UserContext.current().getCallerUserId(), network.getAccountId(), - EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: "+vnet+ " Network Id: "+network.getId(), 0); + ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), network.getAccountId(), + EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + network.getId(), 0); } else { implemented.setBroadcastUri(network.getBroadcastUri()); } @@ -435,9 +434,9 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur s_logger.debug("Releasing vnet for the network id=" + profile.getId()); _dcDao.releaseVnet(profile.getBroadcastUri().getHost(), profile.getDataCenterId(), profile.getPhysicalNetworkId(), profile.getAccountId(), profile.getReservationId()); - EventUtils.saveEvent(UserContext.current().getCallerUserId(), profile.getAccountId(), + ActionEventUtils.onCompletedActionEvent(UserContext.current().getCallerUserId(), profile.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_RELEASE, "Released Zone Vlan: " - +profile.getBroadcastUri().getHost()+" for Network: "+profile.getId(), 0); + + profile.getBroadcastUri().getHost() + " for Network: " + profile.getId(), 0); } profile.setBroadcastUri(null); } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 653a4d35833..85e850c0b5a 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -29,7 +29,9 @@ import java.util.Set; import javax.ejb.Local; import javax.inject.Inject; -import javax.naming.ConfigurationException; + +import com.cloud.event.UsageEventUtils; +import org.apache.log4j.Logger; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLBStickinessPolicyCmd; import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; @@ -38,7 +40,6 @@ import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleI import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; import org.apache.cloudstack.api.response.ServiceResponse; -import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.configuration.Config; @@ -51,7 +52,6 @@ import com.cloud.dc.dao.VlanDao; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InsufficientAddressCapacityException; @@ -871,8 +871,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements if (generateUsageEvent) { // Generate usage event right after all rules were marked for revoke - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(), null); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_DELETE, lb.getAccountId(), 0, lb.getId(), + null, LoadBalancingRule.class.getName(), lb.getUuid()); } txn.commit(); @@ -1104,8 +1104,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } s_logger.debug("Load balancer " + newRule.getId() + " for Ip address id=" + sourceIpId + ", public port " + srcPortStart + ", private port " + defPortStart + " is added successfully."); UserContext.current().setEventDetails("Load balancer Id: " + newRule.getId()); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), null); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), + ipAddr.getDataCenterId(), newRule.getId(), null, LoadBalancingRule.class.getName(), newRule.getUuid()); txn.commit(); return newRule; diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index c65f2d93811..0a00d22b42a 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -34,7 +34,7 @@ import com.cloud.configuration.ConfigurationManager; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InsufficientAddressCapacityException; @@ -289,9 +289,9 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } UserContext.current().setEventDetails("Rule Id: " + newRule.getId()); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), - ipAddress.getDataCenterId(), newRule.getId(), null); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), + ipAddress.getDataCenterId(), newRule.getId(), null, PortForwardingRule.class.getName(), + newRule.getUuid()); txn.commit(); return newRule; } catch (Exception e) { @@ -371,8 +371,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } UserContext.current().setEventDetails("Rule Id: " + newRule.getId()); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), 0, newRule.getId(), null); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), 0, newRule.getId(), + null, FirewallRule.class.getName(), newRule.getUuid()); txn.commit(); StaticNatRule staticNatRule = new StaticNatRuleImpl(newRule, dstIp); diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java index 54864b3e06e..eafe88e36a4 100755 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java @@ -59,13 +59,8 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; -import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.AgentUnavailableException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.OperationTimedoutException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceInUseException; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.*; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network; import com.cloud.network.NetworkManager; @@ -78,6 +73,7 @@ import com.cloud.network.security.dao.SecurityGroupRulesDao; import com.cloud.network.security.dao.SecurityGroupVMMapDao; import com.cloud.network.security.dao.SecurityGroupWorkDao; import com.cloud.network.security.dao.VmRulesetLogDao; +import com.cloud.network.security.dao.*; import com.cloud.projects.ProjectManager; import com.cloud.tags.dao.ResourceTagDao; import com.cloud.user.Account; @@ -98,19 +94,14 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateListener; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.Nic; -import com.cloud.vm.NicProfile; -import com.cloud.vm.UserVmManager; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; +import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; - import edu.emory.mathcs.backport.java.util.Collections; +import org.apache.cloudstack.api.command.user.securitygroup.*; +import java.util.*; @Local(value = { SecurityGroupManager.class, SecurityGroupService.class }) public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGroupManager, SecurityGroupService, StateListener { @@ -157,8 +148,6 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro @Inject ProjectManager _projectMgr; @Inject - UsageEventDao _usageEventDao; - @Inject ResourceTagDao _resourceTagDao; ScheduledExecutorService _executorPool; @@ -458,8 +447,9 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro // For each group, find the security rules that allow the group for (SecurityGroupVMMapVO mapVO : groupsForVm) {// FIXME: use custom sql in the dao //Add usage events for security group assign - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SECURITY_GROUP_ASSIGN, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), mapVO.getSecurityGroupId()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SECURITY_GROUP_ASSIGN, vm.getAccountId(), + vm.getDataCenterId(), vm.getId(), mapVO.getSecurityGroupId(), + vm.getClass().getName(), vm.getUuid()); List allowingRules = _securityGroupRuleDao.listByAllowedSecurityGroupId(mapVO.getSecurityGroupId()); // For each security rule that allows a group that the vm belongs to, find the group it belongs to @@ -474,8 +464,9 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro // For each group, find the security rules rules that allow the group for (SecurityGroupVMMapVO mapVO : groupsForVm) {// FIXME: use custom sql in the dao //Add usage events for security group remove - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SECURITY_GROUP_REMOVE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), mapVO.getSecurityGroupId()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SECURITY_GROUP_REMOVE, + vm.getAccountId(), vm.getDataCenterId(), vm.getId(), mapVO.getSecurityGroupId(), + vm.getClass().getName(), vm.getUuid()); List allowingRules = _securityGroupRuleDao.listByAllowedSecurityGroupId(mapVO.getSecurityGroupId()); // For each security rule that allows a group that the vm belongs to, find the group it belongs to diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index d4b24246fa4..82c0015e317 100755 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -35,7 +35,7 @@ import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AccountLimitException; import com.cloud.exception.InvalidParameterValueException; @@ -47,8 +47,8 @@ import com.cloud.network.NetworkModel; import com.cloud.network.PublicIpAddress; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.VpnUser; +import com.cloud.network.*; import com.cloud.network.VpnUser.State; -import com.cloud.network.VpnUserVO; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; @@ -71,15 +71,14 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.PasswordGenerator; import com.cloud.utils.Ternary; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.*; import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.net.NetUtils; @Component @@ -280,8 +279,8 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc for(VpnUserVO user : vpnUsers){ // VPN_USER_REMOVE event is already generated for users in Revoke state if(user.getState() != VpnUser.State.Revoke){ - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), + 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } } if (vpnFwRules != null) { @@ -332,8 +331,8 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc } VpnUser user = _vpnUsersDao.persist(new VpnUserVO(vpnOwnerId, owner.getDomainId(), username, password)); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), user.getUsername()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), + user.getUsername(), user.getClass().getName(), user.getUuid()); txn.commit(); return user; } @@ -349,8 +348,8 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc txn.start(); user.setState(State.Revoke); _vpnUsersDao.update(user.getId(), user); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), + user.getUsername(), user.getClass().getName(), user.getUuid()); txn.commit(); return true; } @@ -406,8 +405,8 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc List vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); for(VpnUserVO user : vpnUsers){ if(user.getState() != VpnUser.State.Revoke){ - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, user.getId(), user.getUsername()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_ADD, user.getAccountId(), 0, + user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); } } txn.commit(); @@ -482,8 +481,8 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc Transaction txn = Transaction.currentTxn(); txn.start(); _vpnUsersDao.remove(user.getId()); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), 0, user.getId(), user.getUsername()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VPN_USER_REMOVE, user.getAccountId(), + 0, user.getId(), user.getUsername(), user.getClass().getName(), user.getUuid()); txn.commit(); } s_logger.warn("Failed to apply vpn for user " + user.getUsername() + ", accountId=" + user.getAccountId()); diff --git a/server/src/com/cloud/projects/ProjectManagerImpl.java b/server/src/com/cloud/projects/ProjectManagerImpl.java index 72ed940804f..45a9a242147 100755 --- a/server/src/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/com/cloud/projects/ProjectManagerImpl.java @@ -204,7 +204,7 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager { StringBuilder acctNm = new StringBuilder("PrjAcct-"); acctNm.append(name).append("-").append(owner.getDomainId()); - Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, domainId, null, null); + Account projectAccount = _accountMgr.createAccount(acctNm.toString(), Account.ACCOUNT_TYPE_PROJECT, domainId, null, null, "", 0); Project project = _projectDao.persist(new ProjectVO(name, displayText, owner.getDomainId(), projectAccount.getId())); diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index b55e94967e8..fa685144b54 100755 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -106,6 +106,10 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.utils.script.Script; import com.cloud.uuididentity.dao.IdentityDao; +import org.apache.cloudstack.region.RegionVO; +import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; @Component public class ConfigurationServerImpl extends ManagerBase implements ConfigurationServer { @@ -126,6 +130,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio @Inject private ResourceCountDao _resourceCountDao; @Inject private NetworkOfferingServiceMapDao _ntwkOfferingServiceMapDao; @Inject private IdentityDao _identityDao; + @Inject private RegionDao _regionDao; public ConfigurationServerImpl() { setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP); @@ -229,6 +234,8 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio // Create default networks createDefaultNetworks(); + createDefaultRegion(); + // Create userIpAddress ranges // Update existing vlans with networkId @@ -276,7 +283,6 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio // We should not update seed data UUID column here since this will be invoked in upgrade case as well. //updateUuids(); - // Set init to true _configDao.update("init", "Hidden", "true"); @@ -332,6 +338,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio @DB protected void saveUser() { + //ToDo: Add regionId to default users and accounts // insert system account String insertSql = "INSERT INTO `cloud`.`account` (id, uuid, account_name, type, domain_id) VALUES (1, UUID(), 'system', '1', '1')"; Transaction txn = Transaction.currentTxn(); @@ -1265,4 +1272,9 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio return svcProviders; } + private void createDefaultRegion(){ + //Get Region name and URL from db.properties + _regionDao.persist(new RegionVO(_regionDao.getRegionId(), "Local", "http://localhost:8080/client/api", "", "")); + } + } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index be612c8b98a..a1d12c5f24c 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -28,7 +28,6 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -51,6 +50,8 @@ import javax.naming.ConfigurationException; import com.cloud.storage.dao.*; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ApiConstants; + +import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd; import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd; @@ -139,7 +140,6 @@ import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.EventUtils; import com.cloud.event.EventVO; import com.cloud.event.dao.EventDao; import com.cloud.exception.ConcurrentOperationException; @@ -242,7 +242,6 @@ import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; import com.cloud.utils.ssh.SSHKeysHelper; import com.cloud.vm.ConsoleProxyVO; -import com.cloud.vm.DomainRouterVO; import com.cloud.vm.InstanceGroupVO; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.UserVmVO; @@ -2436,12 +2435,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Override public Long saveStartedEvent(Long userId, Long accountId, String type, String description, long startEventId) { - return EventUtils.saveStartedEvent(userId, accountId, type, description, startEventId); + return ActionEventUtils.onStartedActionEvent(userId, accountId, type, description, startEventId); } @Override public Long saveCompletedEvent(Long userId, Long accountId, String level, String type, String description, long startEventId) { - return EventUtils.saveEvent(userId, accountId, level, type, description, startEventId); + return ActionEventUtils.onCompletedActionEvent(userId, accountId, level, type, description, startEventId); } @Override @@ -2828,8 +2827,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe // This means its a new account, set the password using the // authenticator - for (Iterator en = _userAuthenticators.iterator(); en.hasNext();) { - UserAuthenticator authenticator = en.next(); + for (UserAuthenticator authenticator: _userAuthenticators) { encodedPassword = authenticator.encode(password); if (encodedPassword != null) { break; diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 2c59739ed6d..45e3a7f537b 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -55,27 +55,8 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.BackupSnapshotCommand; -import com.cloud.agent.api.CleanupSnapshotBackupCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.CreateStoragePoolCommand; -import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer; -import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; -import com.cloud.agent.api.DeleteStoragePoolCommand; -import com.cloud.agent.api.ManageSnapshotCommand; -import com.cloud.agent.api.ModifyStoragePoolAnswer; -import com.cloud.agent.api.ModifyStoragePoolCommand; -import com.cloud.agent.api.UpgradeSnapshotCommand; -import com.cloud.agent.api.storage.CopyVolumeAnswer; -import com.cloud.agent.api.storage.CopyVolumeCommand; -import com.cloud.agent.api.storage.CreateAnswer; -import com.cloud.agent.api.storage.CreateCommand; -import com.cloud.agent.api.storage.DeleteTemplateCommand; -import com.cloud.agent.api.storage.DeleteVolumeCommand; -import com.cloud.agent.api.storage.DestroyCommand; -import com.cloud.agent.api.storage.ResizeVolumeCommand; -import com.cloud.agent.api.storage.ResizeVolumeAnswer; +import com.cloud.agent.api.*; +import com.cloud.agent.api.storage.*; import com.cloud.agent.api.to.StorageFilerTO; import com.cloud.agent.api.to.VolumeTO; import com.cloud.agent.manager.Commands; @@ -106,21 +87,9 @@ import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; -import com.cloud.event.dao.UsageEventDao; -import com.cloud.exception.AgentUnavailableException; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.DiscoveryException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.InsufficientStorageCapacityException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.OperationTimedoutException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceInUseException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.exception.StorageUnavailableException; +import com.cloud.exception.*; import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; @@ -142,32 +111,17 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume.Event; import com.cloud.storage.Volume.Type; import com.cloud.storage.allocator.StoragePoolAllocator; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.storage.dao.SnapshotDao; -import com.cloud.storage.dao.SnapshotPolicyDao; -import com.cloud.storage.dao.StoragePoolDao; -import com.cloud.storage.dao.StoragePoolHostDao; -import com.cloud.storage.dao.StoragePoolWorkDao; -import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.storage.dao.VMTemplateHostDao; -import com.cloud.storage.dao.VMTemplatePoolDao; -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.dao.*; import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.listener.StoragePoolMonitor; +import com.cloud.storage.listener.VolumeStateListener; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.storage.snapshot.SnapshotScheduler; import com.cloud.tags.dao.ResourceTagDao; import com.cloud.template.TemplateManager; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.User; -import com.cloud.user.UserContext; +import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; @@ -179,36 +133,16 @@ import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.GenericSearchBuilder; -import com.cloud.utils.db.GlobalLock; -import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.*; import com.cloud.utils.db.JoinBuilder.JoinType; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; -import com.cloud.vm.ConsoleProxyVO; -import com.cloud.vm.DiskProfile; -import com.cloud.vm.DomainRouterVO; -import com.cloud.vm.SecondaryStorageVmVO; -import com.cloud.vm.UserVmManager; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; +import com.cloud.vm.*; import com.cloud.vm.VirtualMachine.State; -import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.VirtualMachineProfileImpl; -import com.cloud.vm.dao.ConsoleProxyDao; -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.dao.*; @Component @Local(value = { StorageManager.class, StorageService.class }) @@ -303,8 +237,6 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Inject protected ClusterDao _clusterDao; @Inject - protected UsageEventDao _usageEventDao; - @Inject protected VirtualMachineManager _vmMgr; @Inject protected DomainRouterDao _domrDao; @@ -654,9 +586,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C Pair volumeDetails = createVolumeFromSnapshot(volume, snapshot); if (volumeDetails != null) { createdVolume = volumeDetails.first(); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(), createdVolume.getDataCenterId(), createdVolume.getId(), createdVolume.getName(), - createdVolume.getDiskOfferingId(), null, createdVolume.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(), + createdVolume.getDataCenterId(), createdVolume.getId(), createdVolume.getName(), createdVolume.getDiskOfferingId(), + null, createdVolume.getSize(), Volume.class.getName(), createdVolume.getUuid()); } return createdVolume; } @@ -776,8 +708,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C volume.setPoolId(destPool.getId()); volume.setPodId(destPool.getPodId()); stateTransitTo(volume, Event.CopySucceeded); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), null, volume.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), + null, volume.getSize(), Volume.class.getName(), volume.getUuid()); _volumeHostDao.remove(volumeHostVO.getId()); txn.commit(); return volume; @@ -1042,6 +975,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C LocalStorageSearch.join("poolHost", storageHostSearch, storageHostSearch.entity().getPoolId(), LocalStorageSearch.entity().getId(), JoinBuilder.JoinType.INNER); LocalStorageSearch.and("type", LocalStorageSearch.entity().getPoolType(), SearchCriteria.Op.IN); LocalStorageSearch.done(); + + Volume.State.getStateMachine().registerListener( new VolumeStateListener()); + return true; } @@ -1953,8 +1889,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId); } - if (snapshotCheck.getStatus() != Snapshot.Status.BackedUp) { - throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.Status.BackedUp + " state yet and can't be used for volume creation"); + if (snapshotCheck.getState() != Snapshot.State.BackedUp) { + throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for volume creation"); } diskOfferingId = snapshotCheck.getDiskOfferingId(); @@ -2045,8 +1981,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C volume = _volsDao.persist(volume); if(cmd.getSnapshotId() == null){ //for volume created from snapshot, create usage event after volume creation - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size, + Volume.class.getName(), volume.getUuid()); } UserContext.current().setEventDetails("Volume Id: " + volume.getId()); @@ -2291,8 +2228,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C // Decrement the resource count for volumes belonging user VM's only _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume); // Log usage event for volumes belonging user VM's only - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), + Volume.class.getName(), volume.getUuid()); } try { @@ -2457,7 +2395,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } // remove snapshots in Error state - List snapshots = _snapshotDao.listAllByStatus(Snapshot.Status.Error); + List snapshots = _snapshotDao.listAllByStatus(Snapshot.State.Error); for (SnapshotVO snapshotVO : snapshots) { try{ _snapshotDao.expunge(snapshotVO.getId()); @@ -3126,10 +3064,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C // Save usage event and update resource count for user vm volumes if (vm instanceof UserVm) { - - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size); - _usageEventDao.persist(usageEvent); - + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), + vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size, + Volume.class.getName(), vol.getUuid()); _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); } return toDiskProfile(vol, offering); @@ -3190,9 +3127,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C offeringId = offering.getId(); } - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(), - vol.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), + vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(), + vol.getSize(), Volume.class.getName(), vol.getUuid()); _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); } diff --git a/server/src/com/cloud/storage/dao/SnapshotDao.java b/server/src/com/cloud/storage/dao/SnapshotDao.java index b32d2782b6a..3b961f6fa89 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDao.java +++ b/server/src/com/cloud/storage/dao/SnapshotDao.java @@ -16,15 +16,16 @@ // under the License. package com.cloud.storage.dao; -import java.util.List; - import com.cloud.storage.Snapshot; import com.cloud.storage.Snapshot.Type; import com.cloud.storage.SnapshotVO; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; -public interface SnapshotDao extends GenericDao { +import java.util.List; + +public interface SnapshotDao extends GenericDao, StateDao { List listByVolumeId(long volumeId); List listByVolumeId(Filter filter, long volumeId); SnapshotVO findNextSnapshot(long parentSnapId); @@ -39,7 +40,7 @@ public interface SnapshotDao extends GenericDao { List listByHostId(Filter filter, long hostId); List listByHostId(long hostId); public Long countSnapshotsForAccount(long accountId); - List listByInstanceId(long instanceId, Snapshot.Status... status); - List listByStatus(long volumeId, Snapshot.Status... status); - List listAllByStatus(Snapshot.Status... status); + List listByInstanceId(long instanceId, Snapshot.State... status); + List listByStatus(long volumeId, Snapshot.State... status); + List listAllByStatus(Snapshot.State... status); } diff --git a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java index 8347c4e1301..17bcf9b1bcf 100644 --- a/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java +++ b/server/src/com/cloud/storage/dao/SnapshotDaoImpl.java @@ -29,6 +29,8 @@ import org.springframework.stereotype.Component; import com.cloud.server.ResourceTag.TaggedResourceType; import com.cloud.storage.Snapshot; +import com.cloud.storage.Snapshot.Event; +import com.cloud.storage.Snapshot.State; import com.cloud.storage.Snapshot.Type; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Volume; @@ -39,11 +41,9 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; +import com.cloud.utils.db.*; import com.cloud.utils.db.JoinBuilder.JoinType; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; -import com.cloud.utils.db.Transaction; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.dao.VMInstanceDaoImpl; @@ -117,7 +117,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements public List listByHostId(Filter filter, long hostId ) { SearchCriteria sc = HostIdSearch.create(); sc.setParameters("hostId", hostId); - sc.setParameters("status", Snapshot.Status.BackedUp); + sc.setParameters("status", Snapshot.State.BackedUp); return listBy(sc, filter); } @@ -153,7 +153,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements HostIdSearch = createSearchBuilder(); HostIdSearch.and("hostId", HostIdSearch.entity().getSecHostId(), SearchCriteria.Op.EQ); - HostIdSearch.and("status", HostIdSearch.entity().getStatus(), SearchCriteria.Op.EQ); + HostIdSearch.and("status", HostIdSearch.entity().getState(), SearchCriteria.Op.EQ); HostIdSearch.done(); VolumeIdTypeSearch = createSearchBuilder(); @@ -180,7 +180,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements StatusSearch = createSearchBuilder(); StatusSearch.and("volumeId", StatusSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); - StatusSearch.and("status", StatusSearch.entity().getStatus(), SearchCriteria.Op.IN); + StatusSearch.and("status", StatusSearch.entity().getState(), SearchCriteria.Op.IN); StatusSearch.done(); CountSnapshotsByAccount = createSearchBuilder(Long.class); @@ -190,7 +190,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements CountSnapshotsByAccount.done(); InstanceIdSearch = createSearchBuilder(); - InstanceIdSearch.and("status", InstanceIdSearch.entity().getStatus(), SearchCriteria.Op.IN); + InstanceIdSearch.and("status", InstanceIdSearch.entity().getState(), SearchCriteria.Op.IN); SearchBuilder instanceSearch = _instanceDao.createSearchBuilder(); instanceSearch.and("instanceId", instanceSearch.entity().getId(), SearchCriteria.Op.EQ); @@ -282,7 +282,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements } @Override - public List listByInstanceId(long instanceId, Snapshot.Status... status) { + public List listByInstanceId(long instanceId, Snapshot.State... status) { SearchCriteria sc = this.InstanceIdSearch.create(); if (status != null && status.length != 0) { @@ -295,7 +295,7 @@ public class SnapshotDaoImpl extends GenericDaoBase implements } @Override - public List listByStatus(long volumeId, Snapshot.Status... status) { + public List listByStatus(long volumeId, Snapshot.State... status) { SearchCriteria sc = this.StatusSearch.create(); sc.setParameters("volumeId", volumeId); sc.setParameters("status", (Object[])status); @@ -317,9 +317,20 @@ public class SnapshotDaoImpl extends GenericDaoBase implements } @Override - public List listAllByStatus(Snapshot.Status... status) { + public List listAllByStatus(Snapshot.State... status) { SearchCriteria sc = this.StatusSearch.create(); sc.setParameters("status", (Object[])status); return listBy(sc, null); } + + @Override + public boolean updateState(State currentState, Event event, State nextState, Snapshot snapshot, Object data) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + SnapshotVO snapshotVO = (SnapshotVO)snapshot; + snapshotVO.setStatus(nextState); + super.update(snapshotVO.getId(), snapshotVO); + txn.commit(); + return true; + } } diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index 2f8d75702fc..6d3cf2a101b 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -37,17 +37,10 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; -import com.cloud.agent.api.storage.DeleteTemplateCommand; -import com.cloud.agent.api.storage.DeleteVolumeCommand; -import com.cloud.agent.api.storage.DownloadCommand; -import com.cloud.agent.api.storage.ListVolumeAnswer; -import com.cloud.agent.api.storage.ListVolumeCommand; +import com.cloud.agent.api.storage.*; import com.cloud.agent.api.storage.DownloadCommand.Proxy; import com.cloud.agent.api.storage.DownloadCommand.ResourceType; -import com.cloud.agent.api.storage.DownloadProgressCommand; import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType; -import com.cloud.agent.api.storage.ListTemplateAnswer; -import com.cloud.agent.api.storage.ListTemplateCommand; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.configuration.Config; @@ -56,8 +49,7 @@ import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; -import com.cloud.event.dao.UsageEventDao; +import com.cloud.event.UsageEventUtils; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.StorageUnavailableException; @@ -67,26 +59,9 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.StorageManager; -import com.cloud.storage.SwiftVO; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeHostVO; -import com.cloud.storage.VolumeVO; +import com.cloud.storage.*; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.Volume.Event; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.dao.StoragePoolHostDao; -import com.cloud.storage.dao.SwiftDao; -import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.storage.dao.VMTemplateHostDao; -import com.cloud.storage.dao.VMTemplatePoolDao; -import com.cloud.storage.dao.VMTemplateSwiftDao; -import com.cloud.storage.dao.VMTemplateZoneDao; -import com.cloud.storage.dao.VolumeDao; -import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.storage.dao.*; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.template.TemplateConstants; @@ -100,7 +75,6 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.SecondaryStorageVm; import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.UserVmManager; @@ -150,11 +124,6 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor ConfigurationDao _configDao; @Inject UserVmManager _vmMgr; - - - @Inject - private UsageEventDao _usageEventDao; - @Inject private ClusterDao _clusterDao; @Inject @@ -513,8 +482,9 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor eventType = EventTypes.EVENT_ISO_CREATE; } if(template.getAccountId() != Account.ACCOUNT_ID_SYSTEM){ - UsageEventVO usageEvent = new UsageEventVO(eventType, template.getAccountId(), host.getDataCenterId(), template.getId(), template.getName(), null, template.getSourceTemplateId() , size); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(eventType, template.getAccountId(), host.getDataCenterId(), + template.getId(), template.getName(), null, template.getSourceTemplateId(), size, + template.getClass().getName(), template.getUuid()); } } txn.commit(); @@ -546,8 +516,8 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor } String eventType = EventTypes.EVENT_VOLUME_UPLOAD; if(volume.getAccountId() != Account.ACCOUNT_ID_SYSTEM){ - UsageEventVO usageEvent = new UsageEventVO(eventType, volume.getAccountId(), host.getDataCenterId(), volume.getId(), volume.getName(), null, 0l , size); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(eventType, volume.getAccountId(), host.getDataCenterId(), + volume.getId(), volume.getName(), null, 0l, size, volume.getClass().getName(), volume.getUuid()); } }else if (dnldStatus == Status.DOWNLOAD_ERROR || dnldStatus == Status.ABANDONED || dnldStatus == Status.UNKNOWN){ //Decrement the volume count diff --git a/server/src/com/cloud/storage/listener/SnapshotStateListener.java b/server/src/com/cloud/storage/listener/SnapshotStateListener.java new file mode 100644 index 00000000000..17ccce54c82 --- /dev/null +++ b/server/src/com/cloud/storage/listener/SnapshotStateListener.java @@ -0,0 +1,94 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.storage.listener; + +import com.cloud.event.EventCategory; +import com.cloud.storage.Snapshot; +import com.cloud.storage.Snapshot.Event; +import com.cloud.storage.Snapshot.State; +import com.cloud.server.ManagementServer; +import com.cloud.utils.fsm.StateListener; + +import org.apache.cloudstack.framework.events.EventBus; +import org.apache.cloudstack.framework.events.EventBusException; +import org.apache.log4j.Logger; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +public class SnapshotStateListener implements StateListener { + + // get the event bus provider if configured + @Inject protected EventBus _eventBus; + + private static final Logger s_logger = Logger.getLogger(VolumeStateListener.class); + + public SnapshotStateListener() { + + } + + @Override + public boolean preStateTransitionEvent(State oldState, Event event, State newState, Snapshot vo, boolean status, Object opaque) { + pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState); + return true; + } + + @Override + public boolean postStateTransitionEvent(State oldState, Event event, State newState, Snapshot vo, boolean status, Object opaque) { + pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); + return true; + } + + private void pubishOnEventBus(String event, String status, Snapshot vo, State oldState, State newState) { + + if (_eventBus == null) { + return; // no provider is configured to provide events bus, so just return + } + + String resourceName = getEntityFromClassName(Snapshot.class.getName()); + org.apache.cloudstack.framework.events.Event eventMsg = new org.apache.cloudstack.framework.events.Event( + ManagementServer.Name, + EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(), + event, + resourceName, + vo.getUuid()); + Map eventDescription = new HashMap(); + eventDescription.put("resource", resourceName); + eventDescription.put("id", vo.getUuid()); + eventDescription.put("old-state", oldState.name()); + eventDescription.put("new-state", newState.name()); + eventMsg.setDescription(eventDescription); + try { + _eventBus.publish(eventMsg); + } catch (EventBusException e) { + s_logger.warn("Failed to publish state change event on the the event bus."); + } + } + + private String getEntityFromClassName(String entityClassName) { + int index = entityClassName.lastIndexOf("."); + String entityName = entityClassName; + if (index != -1) { + entityName = entityClassName.substring(index+1); + } + return entityName; + } +} diff --git a/server/src/com/cloud/storage/listener/VolumeStateListener.java b/server/src/com/cloud/storage/listener/VolumeStateListener.java new file mode 100644 index 00000000000..ee715e0131d --- /dev/null +++ b/server/src/com/cloud/storage/listener/VolumeStateListener.java @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.storage.listener; + +import com.cloud.event.EventCategory; +import com.cloud.storage.Volume; +import com.cloud.storage.Volume.Event; +import com.cloud.storage.Volume.State; +import com.cloud.server.ManagementServer; +import com.cloud.utils.fsm.StateListener; +import org.apache.cloudstack.framework.events.EventBus; +import org.apache.cloudstack.framework.events.EventBusException; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +public class VolumeStateListener implements StateListener { + + // get the event bus provider if configured + @Inject protected EventBus _eventBus = null; + + private static final Logger s_logger = Logger.getLogger(VolumeStateListener.class); + + public VolumeStateListener() { + + } + + @Override + public boolean preStateTransitionEvent(State oldState, Event event, State newState, Volume vo, boolean status, Object opaque) { + pubishOnEventBus(event.name(), "preStateTransitionEvent", vo, oldState, newState); + return true; + } + + @Override + public boolean postStateTransitionEvent(State oldState, Event event, State newState, Volume vo, boolean status, Object opaque) { + pubishOnEventBus(event.name(), "postStateTransitionEvent", vo, oldState, newState); + return true; + } + + private void pubishOnEventBus(String event, String status, Volume vo, State oldState, State newState) { + + if (_eventBus == null) { + return; // no provider is configured to provide events bus, so just return + } + + String resourceName = getEntityFromClassName(Volume.class.getName()); + org.apache.cloudstack.framework.events.Event eventMsg = new org.apache.cloudstack.framework.events.Event( + ManagementServer.Name, + EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(), + event, + resourceName, + vo.getUuid()); + Map eventDescription = new HashMap(); + eventDescription.put("resource", resourceName); + eventDescription.put("id", vo.getUuid()); + eventDescription.put("old-state", oldState.name()); + eventDescription.put("new-state", newState.name()); + eventMsg.setDescription(eventDescription); + try { + _eventBus.publish(eventMsg); + } catch (EventBusException e) { + s_logger.warn("Failed to state change event on the the event bus."); + } + } + + private String getEntityFromClassName(String entityClassName) { + int index = entityClassName.lastIndexOf("."); + String entityName = entityClassName; + if (index != -1) { + entityName = entityClassName.substring(index+1); + } + return entityName; + } +} diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index 4ad43cc7908..c7beff08684 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -33,22 +33,11 @@ import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.BackupSnapshotAnswer; -import com.cloud.agent.api.BackupSnapshotCommand; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.DeleteSnapshotBackupCommand; -import com.cloud.agent.api.DeleteSnapshotsDirCommand; -import com.cloud.agent.api.DownloadSnapshotFromS3Command; -import com.cloud.agent.api.ManageSnapshotAnswer; -import com.cloud.agent.api.ManageSnapshotCommand; -import com.cloud.agent.api.downloadSnapshotFromSwiftCommand; +import com.cloud.agent.api.*; import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.alert.AlertManager; -import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; import com.cloud.api.commands.ListRecurringSnapshotScheduleCmd; -import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; import com.cloud.configuration.Config; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; @@ -57,11 +46,7 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; -import com.cloud.event.ActionEvent; -import com.cloud.event.EventTypes; -import com.cloud.event.EventUtils; -import com.cloud.event.EventVO; -import com.cloud.event.UsageEventVO; +import com.cloud.event.*; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; @@ -71,44 +56,21 @@ import com.cloud.exception.StorageUnavailableException; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.network.PhysicalNetworkTrafficType; import com.cloud.org.Grouping; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.resource.ResourceManager; import com.cloud.server.ResourceTag.TaggedResourceType; -import com.cloud.storage.Snapshot; -import com.cloud.storage.Snapshot.Status; +import com.cloud.storage.*; import com.cloud.storage.Snapshot.Type; -import com.cloud.storage.SnapshotPolicyVO; -import com.cloud.storage.SnapshotScheduleVO; -import com.cloud.storage.SnapshotVO; -import com.cloud.storage.Storage; import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeVO; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.storage.dao.SnapshotDao; -import com.cloud.storage.dao.SnapshotPolicyDao; -import com.cloud.storage.dao.SnapshotScheduleDao; -import com.cloud.storage.dao.StoragePoolDao; -import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.*; +import com.cloud.storage.listener.SnapshotStateListener; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.AccountVO; -import com.cloud.user.DomainManager; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.User; -import com.cloud.user.UserContext; +import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.utils.DateUtil; import com.cloud.utils.DateUtil.IntervalType; @@ -124,12 +86,24 @@ import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.*; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; +import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd; +import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; +import java.util.*; @Component @Local(value = { SnapshotManager.class, SnapshotService.class }) @@ -199,6 +173,8 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, private int _deltaSnapshotMax; private int _backupsnapshotwait; + private StateMachine2 _snapshotFsm; + protected SearchBuilder PolicySnapshotSearch; protected SearchBuilder PoliciesForSnapSearch; @@ -263,6 +239,13 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, if (snapshot == null) { throw new CloudRuntimeException("Can not find snapshot " + snapshotId); } + + try { + stateTransitTo(snapshot, Snapshot.Event.CreateRequested); + } catch (NoTransitionException nte) { + s_logger.debug("Failed to update snapshot state due to " + nte.getMessage()); + } + // Send a ManageSnapshotCommand to the agent String vmName = _storageMgr.getVmNameOnVolume(volume); long volumeId = volume.getId(); @@ -293,14 +276,16 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, if (preSnapshotPath != null && preSnapshotPath.equals(answer.getSnapshotPath())) { // empty snapshot s_logger.debug("CreateSnapshot: this is empty snapshot "); + try { snapshot.setPath(preSnapshotPath); snapshot.setBackupSnapshotId(preSnapshotVO.getBackupSnapshotId()); snapshot.setSwiftId(preSnapshotVO.getSwiftId()); - - snapshot.setStatus(Snapshot.Status.BackedUp); snapshot.setPrevSnapshotId(preId); snapshot.setSecHostId(preSnapshotVO.getSecHostId()); - _snapshotDao.update(snapshotId, snapshot); + stateTransitTo(snapshot, Snapshot.Event.OperationNotPerformed); + } catch (NoTransitionException nte) { + s_logger.debug("CreateSnapshot: failed to update state of snapshot due to " + nte.getMessage()); + } } else { long preSnapshotId = 0; @@ -350,6 +335,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, if (answer != null) { s_logger.error(answer.getDetails()); } + try { + stateTransitTo(snapshot, Snapshot.Event.OperationFailed); + } catch (NoTransitionException nte) { + s_logger.debug("Failed to update snapshot state due to " + nte.getMessage()); + } throw new CloudRuntimeException("Creating snapshot for volume " + volumeId + " on primary storage failed."); } @@ -414,7 +404,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } if(userVm.getHypervisorType() == HypervisorType.VMware || userVm.getHypervisorType() == HypervisorType.KVM) { - List activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.Status.Creating, Snapshot.Status.CreatedOnPrimary, Snapshot.Status.BackingUp); + List activeSnapshots = _snapshotDao.listByInstanceId(volume.getInstanceId(), Snapshot.State.Creating, Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); if(activeSnapshots.size() > 1) throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later"); } @@ -423,19 +413,15 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, snapshot = createSnapshotOnPrimary(volume, policyId, snapshotId); if (snapshot != null) { - if (snapshot.getStatus() == Snapshot.Status.CreatedOnPrimary) { + if (snapshot.getState() == Snapshot.State.CreatedOnPrimary) { backedUp = backupSnapshotToSecondaryStorage(snapshot); - } else if (snapshot.getStatus() == Snapshot.Status.BackedUp) { + } else if (snapshot.getState() == Snapshot.State.BackedUp) { // For empty snapshot we set status to BackedUp in createSnapshotOnPrimary backedUp = true; } else { - snapshot.setStatus(Status.Error); - _snapshotDao.update(snapshot.getId(), snapshot); throw new CloudRuntimeException("Failed to create snapshot: " + snapshot + " on primary storage"); } if (!backedUp) { - snapshot.setStatus(Status.Error); - _snapshotDao.update(snapshot.getId(), snapshot); throw new CloudRuntimeException("Created snapshot: " + snapshot + " on primary but failed to backup on secondary"); } } else { @@ -448,23 +434,15 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId()); if ((freshSnapshot != null) && backedUp) { - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, - volume.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(), + snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, + volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); } if( !backedUp ) { - snapshot.setStatus(Status.Error); - _snapshotDao.update(snapshot.getId(), snapshot); } else { _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot); } - } else { - snapshot = _snapshotDao.findById(snapshotId); - if (snapshot != null) { - snapshot.setStatus(Status.Error); - _snapshotDao.update(snapshotId, snapshot); - } } /* @@ -482,9 +460,12 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, private SnapshotVO updateDBOnCreate(Long id, String snapshotPath, long preSnapshotId) { SnapshotVO createdSnapshot = _snapshotDao.findByIdIncludingRemoved(id); createdSnapshot.setPath(snapshotPath); - createdSnapshot.setStatus(Snapshot.Status.CreatedOnPrimary); createdSnapshot.setPrevSnapshotId(preSnapshotId); - _snapshotDao.update(id, createdSnapshot); + try { + stateTransitTo(createdSnapshot, Snapshot.Event.OperationSucceeded); + } catch (NoTransitionException nte) { + s_logger.debug("Faile to update state of snapshot due to " + nte.getMessage()); + } return createdSnapshot; } @@ -626,9 +607,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, throw new CloudRuntimeException("Can not acquire lock for snapshot: " + ss); } try { - - snapshot.setStatus(Snapshot.Status.BackingUp); - _snapshotDao.update(snapshot.getId(), snapshot); + try { + stateTransitTo(snapshot, Snapshot.Event.BackupToSecondary); + } catch (NoTransitionException nte) { + s_logger.debug("Failed to update the state of snapshot while backing up snapshot"); + } long volumeId = snapshot.getVolumeId(); VolumeVO volume = _volsDao.lockRow(volumeId, true); @@ -709,10 +692,18 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, if (answer.isFull()) { snapshot.setPrevSnapshotId(0); } - snapshot.setStatus(Snapshot.Status.BackedUp); - _snapshotDao.update(snapshotId, snapshot); + try { + stateTransitTo(snapshot, Snapshot.Event.OperationSucceeded); + } catch (NoTransitionException nte) { + s_logger.debug("Failed to update the state of snapshot while backing up snapshot"); + } } else { + try { + stateTransitTo(snapshot, Snapshot.Event.OperationFailed); + } catch (NoTransitionException nte) { + s_logger.debug("Failed to update the state of snapshot while backing up snapshot"); + } s_logger.warn("Failed to back up snapshot on secondary storage, deleting the record from the DB"); _snapshotDao.remove(snapshotId); } @@ -771,7 +762,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, s_logger.debug("Max snaps: " + policy.getMaxSnaps() + " exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest snapshot: " + oldSnapId); if(deleteSnapshotInternal(oldSnapId)){ //log Snapshot delete event - EventUtils.saveEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0); + ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0); } snaps.remove(oldestSnapshot); } @@ -791,7 +782,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, _accountMgr.checkAccess(caller, null, true, snapshotCheck); - if( !Status.BackedUp.equals(snapshotCheck.getStatus() ) ) { + if( !Snapshot.State.BackedUp.equals(snapshotCheck.getState() ) ) { throw new InvalidParameterValueException("Can't delete snapshotshot " + snapshotId + " due to it is not in BackedUp Status"); } @@ -816,9 +807,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, Transaction txn = Transaction.currentTxn(); txn.start(); _snapshotDao.remove(snapshotId); - if (snapshot.getStatus() == Snapshot.Status.BackedUp) { - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, 0L); - _usageEventDao.persist(usageEvent); + if (snapshot.getState() == Snapshot.State.BackedUp) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), + snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null, 0L, + snapshot.getClass().getName(), snapshot.getUuid()); } _resourceLimitMgr.decrementResourceCount(snapshot.getAccountId(), ResourceType.snapshot); txn.commit(); @@ -970,7 +962,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SearchBuilder sb = _snapshotDao.createSearchBuilder(); _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); - sb.and("status", sb.entity().getStatus(), SearchCriteria.Op.EQ); + sb.and("status", sb.entity().getState(), SearchCriteria.Op.EQ); sb.and("volumeId", sb.entity().getVolumeId(), SearchCriteria.Op.EQ); sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE); sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ); @@ -1119,9 +1111,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } // Log event after successful deletion - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), volume.getDataCenterId(), snapshot.getId(), snapshot.getName(), null, null, - volume.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshot.getAccountId(), + volume.getDataCenterId(), snapshot.getId(), snapshot.getName(), null, null, + volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid()); } } } @@ -1448,6 +1440,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, s_logger.info("Snapshot Manager is configured."); + _snapshotFsm = Snapshot.State.getStateMachine(); + _snapshotFsm.registerListener(new SnapshotStateListener()); + return true; } @@ -1529,11 +1524,15 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, @Override public boolean canOperateOnVolume(VolumeVO volume) { - List snapshots = _snapshotDao.listByStatus(volume.getId(), Status.Creating, Status.CreatedOnPrimary, Status.BackingUp); + List snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating, + Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp); if (snapshots.size() > 0) { return false; } return true; } + protected boolean stateTransitTo(Snapshot snapshot, Snapshot.Event e) throws NoTransitionException { + return _snapshotFsm.transitTo(snapshot, e, null, _snapshotDao); + } } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java index cbd2933a1a7..5af0af00ae4 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotCmd; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -41,7 +42,6 @@ import com.cloud.async.AsyncJobVO; import com.cloud.async.dao.AsyncJobDao; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.event.EventTypes; -import com.cloud.event.EventUtils; import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotPolicyVO; import com.cloud.storage.SnapshotScheduleVO; @@ -235,8 +235,8 @@ public class SnapshotSchedulerImpl extends ManagerBase implements SnapshotSchedu tmpSnapshotScheduleVO = _snapshotScheduleDao.acquireInLockTable(snapshotScheId); - Long eventId = EventUtils.saveScheduledEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, - EventTypes.EVENT_SNAPSHOT_CREATE, "creating snapshot for volume Id:"+volumeId,0); + Long eventId = ActionEventUtils.onScheduledActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, + EventTypes.EVENT_SNAPSHOT_CREATE, "creating snapshot for volume Id:" + volumeId, 0); Map params = new HashMap(); params.put(ApiConstants.VOLUME_ID, "" + volumeId); diff --git a/server/src/com/cloud/template/HyervisorTemplateAdapter.java b/server/src/com/cloud/template/HyervisorTemplateAdapter.java index 732b153bb51..089f6508d7e 100755 --- a/server/src/com/cloud/template/HyervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HyervisorTemplateAdapter.java @@ -34,12 +34,10 @@ import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.storage.DeleteTemplateCommand; -import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; -import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.DataCenterVO; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.host.HostVO; @@ -55,6 +53,15 @@ import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.user.Account; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.log4j.Logger; + +import javax.ejb.Local; +import java.net.*; +import java.util.List; @Component @Local(value=TemplateAdapter.class) @@ -205,8 +212,7 @@ public class HyervisorTemplateAdapter extends TemplateAdapterBase implements Tem success = false; break; } - UsageEventVO usageEvent = new UsageEventVO(eventType, account.getId(), sZoneId, templateId, null); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(eventType, account.getId(), sZoneId, templateId, null, null, null); templateHostVO.setDestroyed(true); _tmpltHostDao.update(templateHostVO.getId(), templateHostVO); String installPath = templateHostVO.getInstallPath(); diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 0a464148960..f9cf277842d 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -46,13 +46,11 @@ import org.apache.cloudstack.acl.SecurityChecker.AccessType; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.downloadTemplateFromSwiftToSecondaryStorageCommand; -import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.to.SwiftTO; -import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; -import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobVO; import com.cloud.configuration.Config; @@ -65,7 +63,7 @@ import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; @@ -79,9 +77,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuruManager; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; -import com.cloud.storage.LaunchPermissionVO; -import com.cloud.storage.SnapshotVO; -import com.cloud.storage.Storage; +import com.cloud.storage.*; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StorageManager; @@ -92,39 +88,15 @@ import com.cloud.storage.StoragePoolVO; import com.cloud.storage.TemplateProfile; import com.cloud.storage.Upload; import com.cloud.storage.Upload.Type; -import com.cloud.storage.UploadVO; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStoragePoolVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.VMTemplateSwiftVO; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.VolumeVO; -import com.cloud.storage.dao.LaunchPermissionDao; -import com.cloud.storage.dao.SnapshotDao; -import com.cloud.storage.dao.StoragePoolDao; -import com.cloud.storage.dao.StoragePoolHostDao; -import com.cloud.storage.dao.UploadDao; -import com.cloud.storage.dao.VMTemplateDao; -import com.cloud.storage.dao.VMTemplateHostDao; -import com.cloud.storage.dao.VMTemplatePoolDao; -import com.cloud.storage.dao.VMTemplateS3Dao; -import com.cloud.storage.dao.VMTemplateSwiftDao; -import com.cloud.storage.dao.VMTemplateZoneDao; -import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.*; import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.upload.UploadMonitor; import com.cloud.template.TemplateAdapter.TemplateAdapterType; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.AccountService; -import com.cloud.user.AccountVO; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.UserContext; +import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserAccountDao; import com.cloud.user.dao.UserDao; @@ -133,14 +105,8 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.component.Manager; import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.GlobalLock; -import com.cloud.utils.db.JoinBuilder; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.*; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; @@ -825,8 +791,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, _tmpltDao.addTemplateToZone(template, dstZoneId); if(account.getId() != Account.ACCOUNT_ID_SYSTEM){ - UsageEventVO usageEvent = new UsageEventVO(copyEventType, account.getId(), dstZoneId, tmpltId, null, null, null, srcTmpltHost.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(copyEventType, account.getId(), dstZoneId, tmpltId, null, null, null, srcTmpltHost.getSize(), + template.getClass().getName(), template.getUuid()); } return true; } diff --git a/server/src/com/cloud/user/AccountManager.java b/server/src/com/cloud/user/AccountManager.java index 9ca4721187c..4b3a601b802 100755 --- a/server/src/com/cloud/user/AccountManager.java +++ b/server/src/com/cloud/user/AccountManager.java @@ -20,6 +20,10 @@ import java.util.List; import java.util.Map; import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; + import com.cloud.api.query.vo.ControlledViewEntity; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ResourceUnavailableException; @@ -47,7 +51,7 @@ public interface AccountManager extends AccountService { Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId); - Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details); + Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid, int regionId); UserVO createUser(long accountId, String userName, String password, String firstName, String lastName, String email, String timezone); @@ -102,5 +106,94 @@ public interface AccountManager extends AccountService { void buildACLSearchParameters(Account caller, Long id, String accountName, Long projectId, List permittedAccounts, Ternary domainIdRecursiveListProject, boolean listAll, boolean forProjectInvitation); - + + /** + * Deletes a user by userId + * + * @param accountId + * - id of the account do delete + * + * @return true if delete was successful, false otherwise + */ + boolean deleteUserAccount(long accountId); + + /** + * Updates an account + * + * @param cmd + * - the parameter containing accountId or account nameand domainId + * @return updated account object + */ + Account updateAccount(UpdateAccountCmd cmd); + + /** + * Disables an account by accountName and domainId + * + * @param accountName + * @param domainId + * @param accountId + * @param disabled + * account if success + * @return true if disable was successful, false otherwise + */ + Account disableAccount(String accountName, Long domainId, Long accountId) throws ConcurrentOperationException, ResourceUnavailableException; + + /** + * Enables an account by accountId + * + * @param accountName + * - the enableAccount command defining the accountId to be deleted. + * @param domainId + * TODO + * @param accountId + * @return account object + */ + Account enableAccount(String accountName, Long domainId, Long accountId); + + /** + * Deletes user by Id + * @param deleteUserCmd + * @return + */ + boolean deleteUser(DeleteUserCmd deleteUserCmd); + + /** + * Update a user by userId + * + * @param userId + * @return UserAccount object + */ + UserAccount updateUser(UpdateUserCmd cmd); + + /** + * Disables a user by userId + * + * @param userId + * - the userId + * @return UserAccount object + */ + UserAccount disableUser(long userId); + + /** + * Enables a user + * + * @param userId + * - the userId + * @return UserAccount object + */ + UserAccount enableUser(long userId); + + /** + * Locks an account by accountId. A locked account cannot access the API, but will still have running VMs/IP + * addresses + * allocated/etc. + * + * @param accountName + * - the LockAccount command defining the accountId to be locked. + * @param domainId + * TODO + * @param accountId + * @return account object + */ + Account lockAccount(String accountName, Long domainId, Long accountId); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 5512d3fb21e..4fc849e91f0 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -37,6 +37,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.SecurityChecker; @@ -52,6 +53,10 @@ import org.springframework.stereotype.Component; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.dao.UserAccountJoinDao; import com.cloud.api.query.vo.ControlledViewEntity; + + +import org.apache.cloudstack.region.RegionManager; + import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.ResourceLimit; @@ -64,7 +69,6 @@ import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.EventUtils; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.CloudAuthenticationException; import com.cloud.exception.ConcurrentOperationException; @@ -213,6 +217,8 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Inject private IPAddressDao _ipAddressDao; @Inject + private RegionManager _regionMgr; + private VpcManager _vpcMgr; @Inject private DomainRouterDao _routerDao; @@ -757,7 +763,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @DB @ActionEvent(eventType = EventTypes.EVENT_ACCOUNT_CREATE, eventDescription = "creating Account") public UserAccount createUserAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long domainId, String networkDomain, - Map details) { + Map details, String accountUUID, String userUUID, Integer regionId) { if (accountName == null) { accountName = userName; @@ -799,11 +805,12 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M } } + if(regionId == null){ Transaction txn = Transaction.currentTxn(); txn.start(); // create account - Account account = createAccount(accountName, accountType, domainId, networkDomain, details); + AccountVO account = createAccount(accountName, accountType, domainId, networkDomain, details, UUID.randomUUID().toString(), _regionMgr.getId()); long accountId = account.getId(); // create the first user for the account @@ -815,13 +822,38 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M String registrationToken = UUID.nameUUIDFromBytes(bytes).toString(); user.setRegistrationToken(registrationToken); } + txn.commit(); + //Propagate Add account to other Regions + _regionMgr.propagateAddAccount(userName, password, firstName, lastName, email, timezone, accountName, accountType, domainId, + networkDomain, details, account.getUuid(), user.getUuid()); + //check success + return _userAccountDao.findById(user.getId()); + } else { + // Account is propagated from another Region + Transaction txn = Transaction.currentTxn(); + txn.start(); + + // create account + AccountVO account = createAccount(accountName, accountType, domainId, networkDomain, details, accountUUID, regionId); + long accountId = account.getId(); + + // create the first user for the account + UserVO user = createUser(accountId, userName, password, firstName, lastName, email, timezone, userUUID, regionId); + + if (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { + // set registration token + byte[] bytes = (domainId + accountName + userName + System.currentTimeMillis()).getBytes(); + String registrationToken = UUID.nameUUIDFromBytes(bytes).toString(); + user.setRegistrationToken(registrationToken); + } txn.commit(); return _userAccountDao.findById(user.getId()); } + } @Override - public UserVO createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId) { + public UserVO createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId, String userUUID, Integer regionId) { // default domain to ROOT if not specified if (domainId == null) { @@ -849,9 +881,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) { throw new CloudRuntimeException("The user " + userName + " already exists in domain " + domainId); } - - UserVO user = createUser(account.getId(), userName, password, firstName, lastName, email, timeZone); - + UserVO user = null; + if(regionId == null){ + user = createUser(account.getId(), userName, password, firstName, lastName, email, timeZone); + //Propagate Add user to peer Regions + _regionMgr.propagateAddUser(userName, password, firstName, lastName, email, timeZone, accountName, domain.getUuid(), user.getUuid()); + } else { + user = createUser(account.getId(), userName, password, firstName, lastName, email, timeZone, userUUID, regionId); + } return user; } @@ -1158,7 +1195,6 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M throw new InvalidParameterValueException("The account id=" + accountId + " manages project(s) with ids " + projectIds + "and can't be removed"); } - return deleteAccount(account, callerUserId, caller); } @@ -1640,7 +1676,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Override @DB - public Account createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details) { + public AccountVO createAccount(String accountName, short accountType, Long domainId, String networkDomain, Map details, String uuid, int regionId) { // Validate domain Domain domain = _domainMgr.getDomain(domainId); if (domain == null) { @@ -1684,7 +1720,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M Transaction txn = Transaction.currentTxn(); txn.start(); - Account account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType)); + AccountVO account = _accountDao.persist(new AccountVO(accountName, domainId, networkDomain, accountType, uuid, regionId)); if (account == null) { throw new CloudRuntimeException("Failed to create account name " + accountName + " in domain id=" + domainId); @@ -1701,7 +1737,6 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M // Create default security group _networkGroupMgr.createDefaultSecurityGroup(accountId); - txn.commit(); return account; @@ -1714,6 +1749,17 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M s_logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone); } + UserVO user = _userDao.persist(new UserVO(accountId, userName, password, firstName, lastName, email, timezone, UUID.randomUUID().toString(), _regionMgr.getId())); + + return user; + } + + //ToDo Add events?? + public UserVO createUser(long accountId, String userName, String password, String firstName, String lastName, String email, String timezone, String uuid, int regionId) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating user: " + userName + ", accountId: " + accountId + " timezone:" + timezone); + } + String encodedPassword = null; for (Iterator en = _userAuthenticators.iterator(); en.hasNext();) { UserAuthenticator authenticator = en.next(); @@ -1726,7 +1772,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M throw new CloudRuntimeException("Failed to encode password"); } - UserVO user = _userDao.persist(new UserVO(accountId, userName, encodedPassword, firstName, lastName, email, timezone)); + UserVO user = _userDao.persist(new UserVO(accountId, userName, encodedPassword, firstName, lastName, email, timezone, uuid, regionId)); return user; } @@ -1735,7 +1781,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M public void logoutUser(Long userId) { UserAccount userAcct = _userAccountDao.findById(userId); if (userAcct != null) { - EventUtils.saveEvent(userId, userAcct.getAccountId(), userAcct.getDomainId(), EventTypes.EVENT_USER_LOGOUT, "user has logged out"); + ActionEventUtils.onActionEvent(userId, userAcct.getAccountId(), userAcct.getDomainId(), EventTypes.EVENT_USER_LOGOUT, "user has logged out"); } // else log some kind of error event? This likely means the user doesn't exist, or has been deleted... } @@ -1866,10 +1912,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M s_logger.debug("User: " + username + " in domain " + domainId + " has successfully logged in"); } if (NetUtils.isValidIp(loginIpAddress)) { - EventUtils.saveEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN, + ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN, "user has logged in from IP Address " + loginIpAddress); } else { - EventUtils.saveEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN, + ActionEventUtils.onActionEvent(user.getId(), user.getAccountId(), user.getDomainId(), EventTypes.EVENT_USER_LOGIN, "user has logged in. The IP Address cannot be determined"); } return user; @@ -1956,6 +2002,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M @Override @DB public String[] createApiKeyAndSecretKey(RegisterCmd cmd) { + //Send keys to other Regions Long userId = cmd.getId(); User user = getUserIncludingRemoved(userId); diff --git a/server/src/com/cloud/user/DomainManager.java b/server/src/com/cloud/user/DomainManager.java index dae724116f9..af102e20a5c 100644 --- a/server/src/com/cloud/user/DomainManager.java +++ b/server/src/com/cloud/user/DomainManager.java @@ -19,22 +19,15 @@ package com.cloud.user; import java.util.List; import java.util.Set; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; + import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; public interface DomainManager extends DomainService { Set getDomainChildrenIds(String parentDomainPath); - Domain createDomain(String name, Long parentId, Long ownerId, String networkDomain); - - /** - * find the domain by its path - * - * @param domainPath - * the path to use to lookup a domain - * @return domainVO the domain with the matching path, or null if no domain with the given path exists - */ - DomainVO findDomainByPath(String domainPath); + Domain createDomain(String name, Long parentId, Long ownerId, String networkDomain, String domainUUID, Integer regionId); Set getDomainParentIds(long domainId); @@ -43,5 +36,15 @@ public interface DomainManager extends DomainService { List findInactiveDomains(); boolean deleteDomain(DomainVO domain, Boolean cleanup); - + + boolean deleteDomain(long domainId, Boolean cleanup); + + /** + * update an existing domain + * + * @param cmd + * - the command containing domainId and new domainName + * @return Domain object if the command succeeded + */ + Domain updateDomain(UpdateDomainCmd cmd); } diff --git a/server/src/com/cloud/user/DomainManagerImpl.java b/server/src/com/cloud/user/DomainManagerImpl.java index e80da9f2d97..8ad9f5b160e 100644 --- a/server/src/com/cloud/user/DomainManagerImpl.java +++ b/server/src/com/cloud/user/DomainManagerImpl.java @@ -27,6 +27,8 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd; import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.region.RegionManager; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -81,6 +83,8 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom private ProjectDao _projectDao; @Inject private ProjectManager _projectMgr; + @Inject + private RegionManager _regionMgr; @Override public Domain getDomain(long domainId) { @@ -114,7 +118,7 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom @Override @ActionEvent(eventType = EventTypes.EVENT_DOMAIN_CREATE, eventDescription = "creating Domain") - public Domain createDomain(String name, Long parentId, String networkDomain) { + public Domain createDomain(String name, Long parentId, String networkDomain, String domainUUID, Integer regionId) { Account caller = UserContext.current().getCaller(); if (parentId == null) { @@ -132,13 +136,13 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom _accountMgr.checkAccess(caller, parentDomain); - return createDomain(name, parentId, caller.getId(), networkDomain); + return createDomain(name, parentId, caller.getId(), networkDomain, domainUUID, regionId); } @Override @DB - public Domain createDomain(String name, Long parentId, Long ownerId, String networkDomain) { + public Domain createDomain(String name, Long parentId, Long ownerId, String networkDomain, String domainUUID, Integer regionId) { // Verify network domain if (networkDomain != null) { if (!NetUtils.verifyDomainName(networkDomain)) { @@ -157,15 +161,28 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom throw new InvalidParameterValueException("Domain with name " + name + " already exists for the parent id=" + parentId); } + if(regionId == null){ Transaction txn = Transaction.currentTxn(); txn.start(); - DomainVO domain = _domainDao.create(new DomainVO(name, ownerId, parentId, networkDomain)); + DomainVO domain = _domainDao.create(new DomainVO(name, ownerId, parentId, networkDomain, _regionMgr.getId())); _resourceCountDao.createResourceCounts(domain.getId(), ResourceLimit.ResourceOwnerType.Domain); - txn.commit(); + //Propagate domain creation to peer Regions + _regionMgr.propagateAddDomain(name, parentId, networkDomain, domain.getUuid()); + return domain; + } else { + Transaction txn = Transaction.currentTxn(); + txn.start(); + DomainVO domain = _domainDao.create(new DomainVO(name, ownerId, parentId, networkDomain, domainUUID, regionId)); + _resourceCountDao.createResourceCounts(domain.getId(), ResourceLimit.ResourceOwnerType.Domain); + + txn.commit(); return domain; + + } + } @Override @@ -457,4 +474,97 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom return _domainDao.searchAndCount(sc, searchFilter); } + @Override + @ActionEvent(eventType = EventTypes.EVENT_DOMAIN_UPDATE, eventDescription = "updating Domain") + @DB + public DomainVO updateDomain(UpdateDomainCmd cmd) { + Long domainId = cmd.getId(); + String domainName = cmd.getDomainName(); + String networkDomain = cmd.getNetworkDomain(); + + // check if domain exists in the system + DomainVO domain = _domainDao.findById(domainId); + if (domain == null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find domain with specified domain id"); + ex.addProxyObject(domain, domainId, "domainId"); + throw ex; + } else if (domain.getParent() == null && domainName != null) { + // check if domain is ROOT domain - and deny to edit it with the new name + throw new InvalidParameterValueException("ROOT domain can not be edited with a new name"); + } + + // check permissions + Account caller = UserContext.current().getCaller(); + _accountMgr.checkAccess(caller, domain); + + // domain name is unique in the cloud + if (domainName != null) { + SearchCriteria sc = _domainDao.createSearchCriteria(); + sc.addAnd("name", SearchCriteria.Op.EQ, domainName); + List domains = _domainDao.search(sc, null); + + boolean sameDomain = (domains.size() == 1 && domains.get(0).getId() == domainId); + + if (!domains.isEmpty() && !sameDomain) { + InvalidParameterValueException ex = new InvalidParameterValueException("Failed to update specified domain id with name '" + domainName + "' since it already exists in the system"); + ex.addProxyObject(domain, domainId, "domainId"); + throw ex; + } + } + + // validate network domain + if (networkDomain != null && !networkDomain.isEmpty()) { + if (!NetUtils.verifyDomainName(networkDomain)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } + } + + Transaction txn = Transaction.currentTxn(); + + txn.start(); + + if (domainName != null) { + String updatedDomainPath = getUpdatedDomainPath(domain.getPath(), domainName); + updateDomainChildren(domain, updatedDomainPath); + domain.setName(domainName); + domain.setPath(updatedDomainPath); + } + + if (networkDomain != null) { + if (networkDomain.isEmpty()) { + domain.setNetworkDomain(null); + } else { + domain.setNetworkDomain(networkDomain); + } + } + _domainDao.update(domainId, domain); + + txn.commit(); + + return _domainDao.findById(domainId); + + } + + private String getUpdatedDomainPath(String oldPath, String newName) { + String[] tokenizedPath = oldPath.split("/"); + tokenizedPath[tokenizedPath.length - 1] = newName; + StringBuilder finalPath = new StringBuilder(); + for (String token : tokenizedPath) { + finalPath.append(token); + finalPath.append("/"); + } + return finalPath.toString(); + } + + private void updateDomainChildren(DomainVO domain, String updatedDomainPrefix) { + List domainChildren = _domainDao.findAllChildren(domain.getPath(), domain.getId()); + // for each child, update the path + for (DomainVO dom : domainChildren) { + dom.setPath(dom.getPath().replaceFirst(domain.getPath(), updatedDomainPrefix)); + _domainDao.update(dom.getId(), dom); + } + } + } diff --git a/server/src/com/cloud/user/dao/AccountDaoImpl.java b/server/src/com/cloud/user/dao/AccountDaoImpl.java index c8bf46a7362..892fdcd548d 100755 --- a/server/src/com/cloud/user/dao/AccountDaoImpl.java +++ b/server/src/com/cloud/user/dao/AccountDaoImpl.java @@ -263,4 +263,5 @@ public class AccountDaoImpl extends GenericDaoBase implements A } } } + } diff --git a/server/src/com/cloud/user/dao/UserAccountDaoImpl.java b/server/src/com/cloud/user/dao/UserAccountDaoImpl.java index fa87d8682bc..8bb822a75b2 100644 --- a/server/src/com/cloud/user/dao/UserAccountDaoImpl.java +++ b/server/src/com/cloud/user/dao/UserAccountDaoImpl.java @@ -65,4 +65,5 @@ public class UserAccountDaoImpl extends GenericDaoBase impl sc.setParameters("apiKey",apiKey); return findOneBy(sc); } + } diff --git a/server/src/com/cloud/user/dao/UserDaoImpl.java b/server/src/com/cloud/user/dao/UserDaoImpl.java index bbef07ec097..4124a6a2d06 100644 --- a/server/src/com/cloud/user/dao/UserDaoImpl.java +++ b/server/src/com/cloud/user/dao/UserDaoImpl.java @@ -127,4 +127,5 @@ public class UserDaoImpl extends GenericDaoBase implements UserDao sc.setParameters("username", username); return listBy(sc); } + } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ad358ebaed1..ee06a974f62 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -113,7 +113,7 @@ import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.CloudException; @@ -353,8 +353,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject protected LoadBalancingRulesManager _lbMgr; @Inject - protected UsageEventDao _usageEventDao; - @Inject protected SSHKeyPairDao _sshKeyPairDao; @Inject protected UserVmDetailsDao _vmDetailsDao; @@ -390,6 +388,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use VpcManager _vpcMgr; @Inject protected GuestOSCategoryDao _guestOSCategoryDao; + @Inject + UsageEventDao _usageEventDao; protected ScheduledExecutorService _executor = null; protected int _expungeInterval; @@ -1664,12 +1664,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use offeringId = offering.getId(); } } - UsageEventVO usageEvent = new UsageEventVO( - EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), - volume.getDataCenterId(), volume.getId(), - volume.getName(), offeringId, templateId, - volume.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), offeringId, templateId, + volume.getSize(), Volume.class.getName(), volume.getUuid()); } } @@ -1984,10 +1981,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // check permissions _accountMgr.checkAccess(caller, null, true, snapshot); - if (snapshot.getStatus() != Snapshot.Status.BackedUp) { - throw new InvalidParameterValueException("Snapshot id=" - + snapshotId + " is not in " + Snapshot.Status.BackedUp - + " state yet and can't be used for template creation"); + if (snapshot.getState() != Snapshot.State.BackedUp) { + throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for template creation"); } /* @@ -2302,14 +2297,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use templateHostVO.setPhysicalSize(answer.getphysicalSize()); _templateHostDao.persist(templateHostVO); - UsageEventVO usageEvent = new UsageEventVO( - EventTypes.EVENT_TEMPLATE_CREATE, - privateTemplate.getAccountId(), - secondaryStorageHost.getDataCenterId(), - privateTemplate.getId(), privateTemplate.getName(), - null, privateTemplate.getSourceTemplateId(), - templateHostVO.getSize()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_TEMPLATE_CREATE, privateTemplate.getAccountId(), + secondaryStorageHost.getDataCenterId(), privateTemplate.getId(), + privateTemplate.getName(), null, privateTemplate.getSourceTemplateId(), + templateHostVO.getSize(), VirtualMachineTemplate.class.getName(), privateTemplate.getUuid()); txn.commit(); } } finally { @@ -3396,12 +3387,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } UserContext.current().setEventDetails("Vm Id: " + vm.getId()); - txn = Transaction.currentTxn(); - txn.start(); - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_CREATE, - accountId, zone.getId(), vm.getId(), vm.getHostName(), - offering.getId(), template.getId(), hypervisorType.toString()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(), + vm.getHostName(), offering.getId(), template.getId(), hypervisorType.toString(), + VirtualMachine.class.getName(), vm.getUuid()); _resourceLimitMgr.incrementResourceCount(accountId, ResourceType.user_vm); @@ -3613,12 +3601,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use for (NicVO nic : nics) { NetworkVO network = _networkDao.findById(nic.getNetworkId()); long isDefault = (nic.isDefaultNic()) ? 1 : 0; - UsageEventVO usageEvent = new UsageEventVO( - EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, - vm.getAccountId(), vm.getDataCenterId(), - vm.getId(), vm.getHostName(), - network.getNetworkOfferingId(), null, isDefault); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_ASSIGN, vm.getAccountId(), + vm.getDataCenterId(), vm.getId(), vm.getHostName(), network.getNetworkOfferingId(), + null, isDefault, VirtualMachine.class.getName(), vm.getUuid()); if (network.getTrafficType() == TrafficType.Guest) { originalIp = nic.getIp4Address(); guestNic = nic; @@ -3932,11 +3917,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List volumes = _volsDao.findByInstance(vmId); for (VolumeVO volume : volumes) { if (volume.getVolumeType().equals(Volume.Type.ROOT)) { - UsageEventVO usageEvent = new UsageEventVO( - EventTypes.EVENT_VOLUME_DELETE, - volume.getAccountId(), volume.getDataCenterId(), - volume.getId(), volume.getName()); - _usageEventDao.persist(usageEvent); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), Volume.class.getName(), + volume.getUuid()); } } @@ -4466,11 +4449,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use Transaction txn = Transaction.currentTxn(); txn.start(); - // generate destroy vm event for usage - _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VM_DESTROY, vm - .getAccountId(), vm.getDataCenterId(), vm.getId(), vm - .getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), - vm.getHypervisorType().toString())); + //generate destroy vm event for usage + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_DESTROY, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), + vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(), + VirtualMachine.class.getName(), vm.getUuid()); // update resource counts _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.user_vm); @@ -4483,36 +4465,28 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use // OS 2: update volume List volumes = _volsDao.findByInstance(cmd.getVmId()); for (VolumeVO volume : volumes) { - _usageEventDao - .persist(new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, - volume.getAccountId(), volume.getDataCenterId(), - volume.getId(), volume.getName())); - _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), - ResourceType.volume); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), Volume.class.getName(), volume.getUuid()); + _resourceLimitMgr.decrementResourceCount(oldAccount.getAccountId(), ResourceType.volume); volume.setAccountId(newAccount.getAccountId()); _volsDao.persist(volume); - _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), - ResourceType.volume); - _usageEventDao.persist(new UsageEventVO( - EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.volume); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), - volume.getDiskOfferingId(), volume.getTemplateId(), volume - .getSize())); - // snapshots: mark these removed in db - List snapshots = _snapshotDao - .listByVolumeIdIncludingRemoved(volume.getId()); - for (SnapshotVO snapshot : snapshots) { + volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), + volume.getUuid()); + //snapshots: mark these removed in db + List snapshots = _snapshotDao.listByVolumeIdIncludingRemoved(volume.getId()); + for (SnapshotVO snapshot: snapshots){ _snapshotDao.remove(snapshot.getId()); } } - _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), - ResourceType.user_vm); - // generate usage events to account for this change - _usageEventDao.persist(new UsageEventVO(EventTypes.EVENT_VM_CREATE, vm - .getAccountId(), vm.getDataCenterId(), vm.getId(), vm - .getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), - vm.getHypervisorType().toString())); + _resourceLimitMgr.incrementResourceCount(newAccount.getAccountId(), ResourceType.user_vm); + //generate usage events to account for this change + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, vm.getAccountId(), vm.getDataCenterId(), vm.getId(), + vm.getHostName(), vm.getServiceOfferingId(), vm.getTemplateId(), vm.getHypervisorType().toString(), + VirtualMachine.class.getName(), vm.getUuid()); txn.commit(); diff --git a/server/src/com/cloud/vm/UserVmStateListener.java b/server/src/com/cloud/vm/UserVmStateListener.java index 9b475de1227..18f85670948 100644 --- a/server/src/com/cloud/vm/UserVmStateListener.java +++ b/server/src/com/cloud/vm/UserVmStateListener.java @@ -16,23 +16,37 @@ // under the License. package com.cloud.vm; -import java.util.List; - +import com.cloud.event.EventCategory; import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.UsageEventDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.Network; +import com.cloud.server.ManagementServer; import com.cloud.utils.fsm.StateListener; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.NicDao; +import org.apache.log4j.Logger; + +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; + public class UserVmStateListener implements StateListener { - protected UsageEventDao _usageEventDao; - protected NetworkDao _networkDao; - protected NicDao _nicDao; + @Inject protected UsageEventDao _usageEventDao; + @Inject protected NetworkDao _networkDao; + @Inject protected NicDao _nicDao; + private static final Logger s_logger = Logger.getLogger(UserVmStateListener.class); + + // get the event bus provider if configured + @Inject protected org.apache.cloudstack.framework.events.EventBus _eventBus = null; public UserVmStateListener(UsageEventDao usageEventDao, NetworkDao networkDao, NicDao nicDao) { this._usageEventDao = usageEventDao; @@ -42,6 +56,7 @@ public class UserVmStateListener implements StateListener nics = _nicDao.listByVmId(vo.getId()); for (NicVO nic : nics) { NetworkVO network = _networkDao.findById(nic.getNetworkId()); - usageEvent = new UsageEventVO(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vo.getAccountId(), vo.getDataCenterId(), vo.getId(), null, network.getNetworkOfferingId(), null, 0L); - _usageEventDao.persist(usageEvent); + UsageEventUtils.saveUsageEvent(EventTypes.EVENT_NETWORK_OFFERING_REMOVE, vo.getAccountId(), vo.getDataCenterId(), vo.getId(), null, network.getNetworkOfferingId(), null, 0L); } } else if (VirtualMachine.State.isVmDestroyed(oldState, event, newState)) { - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VM_DESTROY, vo.getAccountId(), vo.getDataCenterId(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(), + UsageEventUtils.saveUsageEvent(EventTypes.EVENT_VM_DESTROY, vo.getAccountId(), vo.getDataCenterId(), vo.getId(), vo.getHostName(), vo.getServiceOfferingId(), vo.getTemplateId(), vo.getHypervisorType().toString()); - _usageEventDao.persist(usageEvent); } return true; } + + private void pubishOnEventBus(String event, String status, VirtualMachine vo, VirtualMachine.State oldState, VirtualMachine.State newState) { + + if (_eventBus == null) { + return; // no provider is configured to provide events bus, so just return + } + + String resourceName = getEntityFromClassName(Network.class.getName()); + org.apache.cloudstack.framework.events.Event eventMsg = new org.apache.cloudstack.framework.events.Event( + ManagementServer.Name, + EventCategory.RESOURCE_STATE_CHANGE_EVENT.getName(), + event, + resourceName, + vo.getUuid()); + Map eventDescription = new HashMap(); + eventDescription.put("resource", resourceName); + eventDescription.put("id", vo.getUuid()); + eventDescription.put("old-state", oldState.name()); + eventDescription.put("new-state", newState.name()); + eventMsg.setDescription(eventDescription); + try { + _eventBus.publish(eventMsg); + } catch (org.apache.cloudstack.framework.events.EventBusException e) { + s_logger.warn("Failed to publish state change event on the the event bus."); + } + + } + + private String getEntityFromClassName(String entityClassName) { + int index = entityClassName.lastIndexOf("."); + String entityName = entityClassName; + if (index != -1) { + entityName = entityClassName.substring(index+1); + } + return entityName; + } } diff --git a/server/src/org/apache/cloudstack/region/RegionAccount.java b/server/src/org/apache/cloudstack/region/RegionAccount.java new file mode 100644 index 00000000000..dba31019b32 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionAccount.java @@ -0,0 +1,287 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import com.cloud.user.AccountVO; + +public class RegionAccount extends AccountVO { + String accountUuid; + String domainUuid; + String domain; + String receivedbytes; + String sentbytes; + String vmlimit; + String vmtotal; + String vmavailable; + String iplimit; + String iptotal; + String ipavailable; + String volumelimit; + String volumetotal; + String volumeavailable; + String snapshotlimit; + String snapshottotal; + String snapshotavailable; + String templatelimit; + String templatetotal; + String templateavailable; + String vmstopped; + String vmrunning; + String projectlimit; + String projecttotal; + String projectavailable; + String networklimit; + String networktotal; + String networkavailable; + RegionUser user; + + public RegionAccount() { + } + + public String getAccountuuid() { + return accountUuid; + } + + public void setAccountuuid(String accountUuid) { + this.accountUuid = accountUuid; + } + + public String getDomainUuid() { + return domainUuid; + } + + public void setDomainUuid(String domainUuid) { + this.domainUuid = domainUuid; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getReceivedbytes() { + return receivedbytes; + } + + public void setReceivedbytes(String receivedbytes) { + this.receivedbytes = receivedbytes; + } + + public String getSentbytes() { + return sentbytes; + } + + public void setSentbytes(String sentbytes) { + this.sentbytes = sentbytes; + } + + public String getVmlimit() { + return vmlimit; + } + + public void setVmlimit(String vmlimit) { + this.vmlimit = vmlimit; + } + + public String getVmtotal() { + return vmtotal; + } + + public void setVmtotal(String vmtotal) { + this.vmtotal = vmtotal; + } + + public String getVmavailable() { + return vmavailable; + } + + public void setVmavailable(String vmavailable) { + this.vmavailable = vmavailable; + } + + public String getIplimit() { + return iplimit; + } + + public void setIplimit(String iplimit) { + this.iplimit = iplimit; + } + + public String getIptotal() { + return iptotal; + } + + public void setIptotal(String iptotal) { + this.iptotal = iptotal; + } + + public String getIpavailable() { + return ipavailable; + } + + public void setIpavailable(String ipavailable) { + this.ipavailable = ipavailable; + } + + public String getVolumelimit() { + return volumelimit; + } + + public void setVolumelimit(String volumelimit) { + this.volumelimit = volumelimit; + } + + public String getVolumetotal() { + return volumetotal; + } + + public void setVolumetotal(String volumetotal) { + this.volumetotal = volumetotal; + } + + public String getVolumeavailable() { + return volumeavailable; + } + + public void setVolumeavailable(String volumeavailable) { + this.volumeavailable = volumeavailable; + } + + public String getSnapshotlimit() { + return snapshotlimit; + } + + public void setSnapshotlimit(String snapshotlimit) { + this.snapshotlimit = snapshotlimit; + } + + public String getSnapshottotal() { + return snapshottotal; + } + + public void setSnapshottotal(String snapshottotal) { + this.snapshottotal = snapshottotal; + } + + public String getSnapshotavailable() { + return snapshotavailable; + } + + public void setSnapshotavailable(String snapshotavailable) { + this.snapshotavailable = snapshotavailable; + } + + public String getTemplatelimit() { + return templatelimit; + } + + public void setTemplatelimit(String templatelimit) { + this.templatelimit = templatelimit; + } + + public String getTemplatetotal() { + return templatetotal; + } + + public void setTemplatetotal(String templatetotal) { + this.templatetotal = templatetotal; + } + + public String getTemplateavailable() { + return templateavailable; + } + + public void setTemplateavailable(String templateavailable) { + this.templateavailable = templateavailable; + } + + public String getVmstopped() { + return vmstopped; + } + + public void setVmstopped(String vmstopped) { + this.vmstopped = vmstopped; + } + + public String getVmrunning() { + return vmrunning; + } + + public void setVmrunning(String vmrunning) { + this.vmrunning = vmrunning; + } + + public String getProjectlimit() { + return projectlimit; + } + + public void setProjectlimit(String projectlimit) { + this.projectlimit = projectlimit; + } + + public String getProjecttotal() { + return projecttotal; + } + + public void setProjecttotal(String projecttotal) { + this.projecttotal = projecttotal; + } + + public String getProjectavailable() { + return projectavailable; + } + + public void setProjectavailable(String projectavailable) { + this.projectavailable = projectavailable; + } + + public String getNetworklimit() { + return networklimit; + } + + public void setNetworklimit(String networklimit) { + this.networklimit = networklimit; + } + + public String getNetworktotal() { + return networktotal; + } + + public void setNetworktotal(String networktotal) { + this.networktotal = networktotal; + } + + public String getNetworkavailable() { + return networkavailable; + } + + public void setNetworkavailable(String networkavailable) { + this.networkavailable = networkavailable; + } + + public RegionUser getUser() { + return user; + } + + public void setUser(RegionUser user) { + this.user = user; + } + +} diff --git a/server/src/org/apache/cloudstack/region/RegionDomain.java b/server/src/org/apache/cloudstack/region/RegionDomain.java new file mode 100644 index 00000000000..df46198976f --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionDomain.java @@ -0,0 +1,61 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import com.cloud.domain.DomainVO; + +public class RegionDomain extends DomainVO { + String accountUuid; + String parentUuid; + String parentdomainname; + Boolean haschild; + + public RegionDomain() { + } + + public String getAccountuuid() { + return accountUuid; + } + + public void setAccountuuid(String accountUuid) { + this.accountUuid = accountUuid; + } + + public String getParentUuid() { + return parentUuid; + } + + public void setParentUuid(String parentUuid) { + this.parentUuid = parentUuid; + } + + public String getParentdomainname() { + return parentdomainname; + } + + public void setParentdomainname(String parentdomainname) { + this.parentdomainname = parentdomainname; + } + + public Boolean getHaschild() { + return haschild; + } + + public void setHaschild(Boolean haschild) { + this.haschild = haschild; + } +} diff --git a/server/src/org/apache/cloudstack/region/RegionManager.java b/server/src/org/apache/cloudstack/region/RegionManager.java new file mode 100644 index 00000000000..56bdb9baedf --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionManager.java @@ -0,0 +1,216 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.List; +import java.util.Map; + +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; + +import com.cloud.domain.Domain; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.UserAccount; + +public interface RegionManager { + + /** + * Propagates Account details to peer Regions + * @param userName + * @param password + * @param firstName + * @param lastName + * @param email + * @param timezone + * @param accountName + * @param accountType + * @param domainId + * @param networkDomain + * @param details + * @param accountUUID + * @param userUUID + * @return + */ + public boolean propagateAddAccount(String userName, String password, String firstName, String lastName, String email, String timezone, String accountName, short accountType, Long domainId, String networkDomain, + Map details, String accountUUID, String userUUID); + + /** + * Returns the Id of local Region + * @return + */ + public int getId(); + + /** + * Propagates User details to peer Regions + * @param userName + * @param password + * @param firstName + * @param lastName + * @param email + * @param timeZone + * @param accountName + * @param domainUUId + * @param userUUID + */ + public void propagateAddUser(String userName, String password, + String firstName, String lastName, String email, String timeZone, + String accountName, String domainUUId, String userUUID); + + /** + * Propagates Domain details to peer Regions + * @param name + * @param parentId + * @param networkDomain + * @param uuid + */ + public void propagateAddDomain(String name, Long parentId, String networkDomain, String uuid); + + + /** + * Adds a peer Region to the local Region + * @param id + * @param name + * @param endPoint + * @param apiKey + * @param secretKey + * @return Returns added Region object + */ + Region addRegion(int id, String name, String endPoint, String apiKey, String secretKey); + + /** + * Update details of the Region with specified Id + * @param id + * @param name + * @param endPoint + * + * @param apiKey + * @param secretKey + * @return Returns update Region object + */ + Region updateRegion(int id, String name, String endPoint, String apiKey, String secretKey); + + /** + * @param id + * @return True if region is successfully removed + */ + boolean removeRegion(int id); + + /** List all Regions or by Id/Name + * @param id + * @param name + * @return List of Regions + */ + List listRegions(Integer id, String name); + + /** + * Deletes a user by userId and propagates the change to peer Regions + * + * @param accountId + * - id of the account do delete + * + * @return true if delete was successful, false otherwise + */ + boolean deleteUserAccount(long accountId); + + /** + * Updates an account + * isPopagate falg is set to true if sent from peer Region + * + * @param cmd + * - the parameter containing accountId or account nameand domainId + * @return updated account object + */ + Account updateAccount(UpdateAccountCmd cmd); + + /** + * Disables an account by accountName and domainId or accountId + * @param accountName + * @param domainId + * @param id + * @param lockRequested + * @return + * @throws ConcurrentOperationException + * @throws ResourceUnavailableException + */ + Account disableAccount(String accountName, Long domainId, Long id, Boolean lockRequested) throws ConcurrentOperationException, ResourceUnavailableException; + + /** + * Enables an account by accountId + * + * @param accountName + * - the enableAccount command defining the accountId to be deleted. + * @param domainId + * TODO + * @param accountId + * @return account object + */ + Account enableAccount(String accountName, Long domainId, Long accountId); + + /** + * Deletes user by Id + * @param deleteUserCmd + * @return + */ + boolean deleteUser(DeleteUserCmd deleteUserCmd); + + /** + * update an existing domain + * + * @param cmd + * - the command containing domainId and new domainName + * @return Domain object if the command succeeded + */ + Domain updateDomain(UpdateDomainCmd updateDomainCmd); + + /** + * Deletes domain by Id + * @param id + * @param cleanup + * @return true if delete was successful, false otherwise + */ + boolean deleteDomain(Long id, Boolean cleanup); + + /** + * Update a user by userId + * + * @param userId + * @return UserAccount object + */ + UserAccount updateUser(UpdateUserCmd updateUserCmd); + + /** + * Disables a user by userId + * + * @param userId + * - the userId + * @return UserAccount object + */ + UserAccount disableUser(Long id); + + /** + * Enables a user + * + * @param userId + * - the userId + * @return UserAccount object + */ + UserAccount enableUser(long userId); +} diff --git a/server/src/org/apache/cloudstack/region/RegionManagerImpl.java b/server/src/org/apache/cloudstack/region/RegionManagerImpl.java new file mode 100755 index 00000000000..190c69c5b91 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionManagerImpl.java @@ -0,0 +1,877 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.cloudstack.region.dao.RegionSyncDao; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.log4j.Logger; + +import com.cloud.domain.Domain; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.DomainManager; +import com.cloud.user.UserAccount; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserAccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.component.Manager; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.uuididentity.dao.IdentityDao; + +@Local(value = { RegionManager.class }) +public class RegionManagerImpl extends ManagerBase implements RegionManager, Manager{ + public static final Logger s_logger = Logger.getLogger(RegionManagerImpl.class); + + @Inject + RegionDao _regionDao; + @Inject + AccountDao _accountDao; + @Inject + private AccountManager _accountMgr; + @Inject + private UserDao _userDao; + @Inject + private DomainDao _domainDao; + @Inject + private DomainManager _domainMgr; + @Inject + private UserAccountDao _userAccountDao; + @Inject + private IdentityDao _identityDao; + @Inject + private RegionSyncDao _regionSyncDao; + + private String _name; + private int _id; + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + _name = name; + _id = _regionDao.getRegionId(); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + public int getId() { + return _id; + } + + /* + * Propagates Account creation to peer Regions + * Adds an entry in region_sync table on failure + */ + @Override + public boolean propagateAddAccount(String userName, String password, String firstName, String lastName, String email, String timezone, + String accountName, short accountType, Long domainId, String networkDomain, Map details, String accountUUID, String userUUID) { + String command = "createAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.USERNAME, userName)); + params.add(new NameValuePair(ApiConstants.PASSWORD, password)); + params.add(new NameValuePair(ApiConstants.FIRSTNAME, firstName)); + params.add(new NameValuePair(ApiConstants.LASTNAME, lastName)); + params.add(new NameValuePair(ApiConstants.EMAIL, email)); + params.add(new NameValuePair(ApiConstants.TIMEZONE, timezone)); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + params.add(new NameValuePair(ApiConstants.ACCOUNT_TYPE, ""+accountType)); + //ToDo: use domain UUID + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, ((domainId != null) ? domainId.toString() : ""))); + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, networkDomain)); + params.add(new NameValuePair(ApiConstants.ACCOUNT_DETAILS, (details != null) ? details.toString() : "")); + params.add(new NameValuePair(ApiConstants.ACCOUNT_ID, accountUUID)); + params.add(new NameValuePair(ApiConstants.USER_ID, userUUID)); + params.add(new NameValuePair(ApiConstants.REGION_ID, ""+getId())); + + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + s_logger.debug("Adding account :"+accountName+" to Region: "+region.getId()); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully added account :"+accountName+" to Region: "+region.getId()); + } else { + // api call failed. Add entry in region_sync table + addRegionSyncItem(region.getId(), command, params); + s_logger.error("Error while Adding account :"+accountName+" to Region: "+region.getId()); + } + } + return true; + } + + /* + * Propagates User creation to peer Regions + * Adds an entry in region_sync table on failure + */ + @Override + public void propagateAddUser(String userName, String password, + String firstName, String lastName, String email, String timezone, + String accountName, String domainUUId, String userUUID) { + + String command = "createUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.USERNAME, userName)); + params.add(new NameValuePair(ApiConstants.PASSWORD, password)); + params.add(new NameValuePair(ApiConstants.FIRSTNAME, firstName)); + params.add(new NameValuePair(ApiConstants.LASTNAME, lastName)); + params.add(new NameValuePair(ApiConstants.EMAIL, email)); + params.add(new NameValuePair(ApiConstants.TIMEZONE, timezone)); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domainUUId)); + params.add(new NameValuePair(ApiConstants.USER_ID, userUUID)); + params.add(new NameValuePair(ApiConstants.REGION_ID, ""+getId())); + + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + s_logger.debug("Adding account :"+accountName+" to Region: "+region.getId()); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully added user :"+userName+" to Region: "+region.getId()); + } else { + // api call failed. Add entry in region_sync table + addRegionSyncItem(region.getId(), command, params); + s_logger.error("Error while Adding user :"+userName+" to Region: "+region.getId()); + } + } + return; + } + + /* + * Propagates Domain creation details to peer Regions + * Adds an entry in region_sync table on failure + */ + @Override + public void propagateAddDomain(String name, Long parentId, String networkDomain, String uuid) { + + String command = "createDomain"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.NAME, name)); + if(parentId != null){ + DomainVO domain = _domainDao.findById(parentId); + if(domain != null){ + params.add(new NameValuePair(ApiConstants.PARENT_DOMAIN_ID, domain.getUuid())); + } + } + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, networkDomain)); + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, uuid)); + params.add(new NameValuePair(ApiConstants.REGION_ID, ""+getId())); + + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + s_logger.debug("Adding domain :"+name+" to Region: "+region.getId()); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully added domain :"+name+" to Region: "+region.getId()); + } else { + // api call failed. Add entry in region_sync table + addRegionSyncItem(region.getId(), command, params); + s_logger.error("Error while Adding domain :"+name+" to Region: "+region.getId()); + } + } + return; + } + + /** + * Adds an entry to region_sync table + * Entry contains region Id along with failed api + * @param regionId + * @param command + * @param params + */ + private void addRegionSyncItem(int regionId, String command, List params){ + String api = RegionsApiUtil.buildParams(command, params); + RegionSyncVO sync = new RegionSyncVO(regionId, api); + if(_regionSyncDao.persist(sync) == null){ + s_logger.error("Failed to add Region Sync Item. RegionId: "+regionId + "API command: "+api); + } + } + + /** + * {@inheritDoc} + */ + @Override + public Region addRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + //Region Id should be unique + if( _regionDao.findById(id) != null ){ + throw new InvalidParameterValueException("Region with id: "+id+" already exists"); + } + //Region Name should be unique + if( _regionDao.findByName(name) != null ){ + throw new InvalidParameterValueException("Region with name: "+name+" already exists"); + } + RegionVO region = new RegionVO(id, name, endPoint, apiKey, secretKey); + return _regionDao.persist(region); + } + + /** + * {@inheritDoc} + */ + @Override + public Region updateRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + RegionVO region = _regionDao.findById(id); + + if(region == null){ + throw new InvalidParameterValueException("Region with id: "+id+" does not exist"); + } + + //Ensure region name is unique + if(name != null){ + RegionVO region1 = _regionDao.findByName(name); + if(region1 != null && id != region1.getId()){ + throw new InvalidParameterValueException("Region with name: "+name+" already exists"); + } + } + + if(name != null){ + region.setName(name); + } + + if(endPoint != null){ + region.setEndPoint(endPoint); + } + + if(apiKey != null){ + region.setApiKey(apiKey); + } + + if(secretKey != null){ + region.setSecretKey(secretKey); + } + + _regionDao.update(id, region); + return _regionDao.findById(id); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean removeRegion(int id) { + RegionVO region = _regionDao.findById(id); + if(region == null){ + throw new InvalidParameterValueException("Failed to delete Region: " + id + ", Region not found"); + } + return _regionDao.remove(id); + } + + /** + * {@inheritDoc} + */ + @Override + public List listRegions(Integer id, String name) { + List regions = new ArrayList(); + if(id != null){ + RegionVO region = _regionDao.findById(id); + if(region != null){ + regions.add(region); + } + return regions; + } + if(name != null){ + RegionVO region = _regionDao.findByName(name); + if(region != null){ + regions.add(region); + } + return regions; + } + return _regionDao.listAll(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUserAccount(long accountId) { + AccountVO account = _accountDao.findById(accountId); + if(account == null){ + throw new InvalidParameterValueException("The specified account does not exist in the system"); + } + String accountUUID = account.getUuid(); + int regionId = account.getRegionId(); + + String command = "deleteAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, accountUUID)); + + if(getId() == regionId){ + if(_accountMgr.deleteUserAccount(accountId)){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted account :"+accountUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while deleting account :"+accountUUID+" in Region: "+region.getId()); + } + } + return true; + } else { + return false; + } + } else { + //First delete in the Region where account is created + Region region = _regionDao.findById(regionId); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted account :"+accountUUID+" in Region: "+region.getId()); + return true; + } else { + s_logger.error("Error while deleting account :"+accountUUID+" in Region: "+region.getId()); + return false; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Account updateAccount(UpdateAccountCmd cmd) { + Long accountId = cmd.getId(); + Long domainId = cmd.getDomainId(); + DomainVO domain = _domainDao.findById(domainId); + String accountName = cmd.getAccountName(); + String newAccountName = cmd.getNewName(); + String networkDomain = cmd.getNetworkDomain(); + //ToDo send details + Map details = cmd.getDetails(); + + Account account = null; + if (accountId != null) { + account = _accountDao.findById(accountId); + } else { + account = _accountDao.findEnabledAccount(accountName, domainId); + } + + // Check if account exists + if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + s_logger.error("Unable to find account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + throw new InvalidParameterValueException("Unable to find account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + } + + String command = "updateAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.NEW_NAME, newAccountName)); + params.add(new NameValuePair(ApiConstants.ID, account.getUuid())); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domain.getUuid())); + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, networkDomain)); + params.add(new NameValuePair(ApiConstants.NEW_NAME, newAccountName)); + if(details != null){ + params.add(new NameValuePair(ApiConstants.ACCOUNT_DETAILS, details.toString())); + } + int regionId = account.getRegionId(); + if(getId() == regionId){ + Account updatedAccount = _accountMgr.updateAccount(cmd); + if(updatedAccount != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully updated account :"+account.getUuid()+" in Region: "+region.getId()); + } else { + s_logger.error("Error while updating account :"+account.getUuid()+" in Region: "+region.getId()); + } + } + } + return updatedAccount; + } else { + //First update in the Region where account is created + Region region = _regionDao.findById(regionId); + RegionAccount updatedAccount = RegionsApiUtil.makeAccountAPICall(region, command, params); + if (updatedAccount != null) { + Long id = _identityDao.getIdentityId("account", updatedAccount.getUuid()); + updatedAccount.setId(id); + Long domainID = _identityDao.getIdentityId("domain", updatedAccount.getDomainUuid()); + updatedAccount.setDomainId(domainID); + s_logger.debug("Successfully updated account :"+account.getUuid()+" in source Region: "+region.getId()); + return updatedAccount; + } else { + throw new CloudRuntimeException("Error while updating account :"+account.getUuid()+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Account disableAccount(String accountName, Long domainId, Long accountId, Boolean lockRequested) throws ConcurrentOperationException, ResourceUnavailableException { + Account account = null; + if (accountId != null) { + account = _accountDao.findById(accountId); + } else { + account = _accountDao.findActiveAccount(accountName, domainId); + } + + if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + throw new InvalidParameterValueException("Unable to find active account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + } + + String accountUUID = account.getUuid(); + + String command = "disableAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.LOCK, lockRequested.toString())); + params.add(new NameValuePair(ApiConstants.ID, accountUUID)); + DomainVO domain = _domainDao.findById(domainId); + if(domain != null){ + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domain.getUuid())); + } + + int regionId = account.getRegionId(); + if(getId() == regionId){ + Account retAccount = null; + if(lockRequested){ + retAccount = _accountMgr.lockAccount(accountName, domainId, accountId); + } else { + retAccount = _accountMgr.disableAccount(accountName, domainId, accountId); + } + if(retAccount != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully disabled account :"+accountUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while disabling account :"+accountUUID+" in Region: "+region.getId()); + } + } + } + return retAccount; + } else { + //First disable account in the Region where account is created + Region region = _regionDao.findById(regionId); + Account retAccount = RegionsApiUtil.makeAccountAPICall(region, command, params); + if (retAccount != null) { + s_logger.debug("Successfully disabled account :"+accountUUID+" in source Region: "+region.getId()); + return retAccount; + } else { + throw new CloudRuntimeException("Error while disabling account :"+accountUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Account enableAccount(String accountName, Long domainId, Long accountId) { + // Check if account exists + Account account = null; + if (accountId != null) { + account = _accountDao.findById(accountId); + } else { + account = _accountDao.findActiveAccount(accountName, domainId); + } + + if (account == null || account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + throw new InvalidParameterValueException("Unable to find account by accountId: " + accountId + " OR by name: " + accountName + " in domain " + domainId); + } + + String accountUUID = account.getUuid(); + + String command = "enableAccount"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, accountUUID)); + params.add(new NameValuePair(ApiConstants.ACCOUNT, accountName)); + DomainVO domain = _domainDao.findById(domainId); + if(domain != null){ + params.add(new NameValuePair(ApiConstants.DOMAIN_ID, domain.getUuid())); + } + + int regionId = account.getRegionId(); + if(getId() == regionId){ + Account retAccount = _accountMgr.enableAccount(accountName, domainId, accountId); + if(retAccount != null){ + List regions = _regionDao.listAll(); + + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully enabled account :"+accountUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while enabling account :"+accountUUID+" in Region: "+region.getId()); + } + } + } + return retAccount; + } else { + //First disable account in the Region where account is created + Region region = _regionDao.findById(regionId); + Account retAccount = RegionsApiUtil.makeAccountAPICall(region, command, params); + if (retAccount != null) { + s_logger.debug("Successfully enabled account :"+accountUUID+" in source Region: "+region.getId()); + return retAccount; + } else { + throw new CloudRuntimeException("Error while enabling account :"+accountUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUser(DeleteUserCmd cmd) { + long id = cmd.getId(); + + UserVO user = _userDao.findById(id); + + if (user == null) { + throw new InvalidParameterValueException("The specified user doesn't exist in the system"); + } + + String userUUID = user.getUuid(); + int regionId = user.getRegionId(); + + String command = "deleteUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, userUUID)); + + if(getId() == regionId){ + if(_accountMgr.deleteUser(cmd)){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted user :"+userUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while deleting account :"+userUUID+" in Region: "+region.getId()); + } + } + return true; + } else { + return false; + } + } else { + //First delete in the Region where account is created + Region region = _regionDao.findById(regionId); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted user :"+userUUID+" in source Region: "+region.getId()); + return true; + } else { + s_logger.error("Error while deleting user :"+userUUID+" in source Region: "+region.getId()); + return false; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public Domain updateDomain(UpdateDomainCmd cmd) { + long id = cmd.getId(); + DomainVO domain = _domainDao.findById(id); + if(domain == null){ + throw new InvalidParameterValueException("The specified domain doesn't exist in the system"); + } + + String domainUUID = domain.getUuid(); + + String command = "updateDomain"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, domainUUID)); + params.add(new NameValuePair(ApiConstants.NAME, cmd.getDomainName())); + params.add(new NameValuePair(ApiConstants.NETWORK_DOMAIN, cmd.getNetworkDomain())); + + int regionId = domain.getRegionId(); + if(getId() == regionId){ + Domain updatedDomain = _domainMgr.updateDomain(cmd); + if(updatedDomain != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully updated updatedDomain :"+domainUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while updating updatedDomain :"+domainUUID+" in Region: "+region.getId()); + } + } + } + return updatedDomain; + } else { + //First update in the Region where domain was created + Region region = _regionDao.findById(regionId); + RegionDomain updatedDomain = RegionsApiUtil.makeDomainAPICall(region, command, params); + if (updatedDomain != null) { + Long parentId = _identityDao.getIdentityId("domain", updatedDomain.getParentUuid()); + updatedDomain.setParent(parentId); + s_logger.debug("Successfully updated user :"+domainUUID+" in source Region: "+region.getId()); + return (DomainVO)updatedDomain; + } else { + throw new CloudRuntimeException("Error while updating user :"+domainUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteDomain(Long id, Boolean cleanup) { + DomainVO domain = _domainDao.findById(id); + if(domain == null){ + throw new InvalidParameterValueException("The specified domain doesn't exist in the system"); + } + + String domainUUID = domain.getUuid(); + + String command = "deleteDomain"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, domainUUID)); + params.add(new NameValuePair(ApiConstants.CLEANUP, cleanup.toString())); + + int regionId = domain.getRegionId(); + if(getId() == regionId){ + if(_domainMgr.deleteDomain(id, cleanup)){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted domain :"+domainUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while deleting domain :"+domainUUID+" in Region: "+region.getId()); + } + } + return true; + } else { + return false; + } + } else { + //First delete in the Region where domain is created + Region region = _regionDao.findById(regionId); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully deleted domain :"+domainUUID+" in Region: "+region.getId()); + return true; + } else { + s_logger.error("Error while deleting domain :"+domainUUID+" in Region: "+region.getId()); + return false; + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount updateUser(UpdateUserCmd cmd) { + long id = cmd.getId(); + + UserVO user = _userDao.findById(id); + if (user == null) { + throw new InvalidParameterValueException("The specified user doesn't exist in the system"); + } + + String userUUID = user.getUuid(); + + String command = "updateUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, userUUID)); + params.add(new NameValuePair(ApiConstants.API_KEY, cmd.getApiKey())); + params.add(new NameValuePair(ApiConstants.EMAIL, cmd.getEmail())); + params.add(new NameValuePair(ApiConstants.FIRSTNAME, cmd.getFirstname())); + params.add(new NameValuePair(ApiConstants.LASTNAME, cmd.getLastname())); + params.add(new NameValuePair(ApiConstants.PASSWORD, cmd.getPassword())); + params.add(new NameValuePair(ApiConstants.SECRET_KEY, cmd.getSecretKey())); + params.add(new NameValuePair(ApiConstants.TIMEZONE, cmd.getTimezone())); + params.add(new NameValuePair(ApiConstants.USERNAME, cmd.getUsername())); + + int regionId = user.getRegionId(); + if(getId() == regionId){ + UserAccount updateUser = _accountMgr.updateUser(cmd); + if(updateUser != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully updated user :"+userUUID+" in Region: "+region.getId()); + } else { + s_logger.error("Error while updating user :"+userUUID+" in Region: "+region.getId()); + } + } + } + return updateUser; + } else { + //First update in the Region where user was created + Region region = _regionDao.findById(regionId); + UserAccount updateUser = RegionsApiUtil.makeUserAccountAPICall(region, command, params); + if (updateUser != null) { + s_logger.debug("Successfully updated user :"+userUUID+" in source Region: "+region.getId()); + return updateUser; + } else { + throw new CloudRuntimeException("Error while updating user :"+userUUID+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount disableUser(Long userId) { + UserVO user = _userDao.findById(userId); + if (user == null || user.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find active user by id " + userId); + } + + int regionId = user.getRegionId(); + + String command = "disableUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, user.getUuid())); + + if(getId() == regionId){ + UserAccount disabledUser = _accountMgr.disableUser(userId); + if(disabledUser != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully disabled user :"+user.getUuid()+" in Region: "+region.getId()); + } else { + s_logger.error("Error while disabling user :"+user.getUuid()+" in Region: "+region.getId()); + } + } + } + return disabledUser; + } else { + //First disable in the Region where user was created + Region region = _regionDao.findById(regionId); + UserAccount disabledUser = RegionsApiUtil.makeUserAccountAPICall(region, command, params); + if (disabledUser != null) { + s_logger.debug("Successfully disabled user :"+user.getUuid()+" in source Region: "+region.getId()); + return disabledUser; + } else { + throw new CloudRuntimeException("Error while disabling user :"+user.getUuid()+" in source Region: "+region.getId()); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount enableUser(long userId) { + UserVO user = _userDao.findById(userId); + if (user == null || user.getRemoved() != null) { + throw new InvalidParameterValueException("Unable to find active user by id " + userId); + } + + int regionId = user.getRegionId(); + + String command = "enableUser"; + List params = new ArrayList(); + params.add(new NameValuePair(ApiConstants.ID, user.getUuid())); + + if(getId() == regionId){ + UserAccount enabledUser = _accountMgr.enableUser(userId); + if(enabledUser != null){ + List regions = _regionDao.listAll(); + for (Region region : regions){ + if(region.getId() == getId()){ + continue; + } + params.add(new NameValuePair(ApiConstants.IS_PROPAGATE, "true")); + if (RegionsApiUtil.makeAPICall(region, command, params)) { + s_logger.debug("Successfully enabled user :"+user.getUuid()+" in Region: "+region.getId()); + } else { + s_logger.error("Error while disabling user :"+user.getUuid()+" in Region: "+region.getId()); + } + } + } + return enabledUser; + } else { + //First enable in the Region where user was created + Region region = _regionDao.findById(regionId); + UserAccount enabledUser = RegionsApiUtil.makeUserAccountAPICall(region, command, params); + if (enabledUser != null) { + s_logger.debug("Successfully enabled user :"+user.getUuid()+" in source Region: "+region.getId()); + return enabledUser; + } else { + throw new CloudRuntimeException("Error while enabling user :"+user.getUuid()+" in source Region: "+region.getId()); + } + } + } + +} diff --git a/server/src/org/apache/cloudstack/region/RegionServiceImpl.java b/server/src/org/apache/cloudstack/region/RegionServiceImpl.java new file mode 100755 index 00000000000..f10f638127f --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionServiceImpl.java @@ -0,0 +1,299 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.command.admin.account.DeleteAccountCmd; +import org.apache.cloudstack.api.command.admin.account.DisableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.EnableAccountCmd; +import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd; +import org.apache.cloudstack.api.command.admin.domain.DeleteDomainCmd; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; +import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; +import org.apache.cloudstack.api.command.admin.user.DisableUserCmd; +import org.apache.cloudstack.api.command.admin.user.EnableUserCmd; +import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; +import org.apache.cloudstack.api.command.user.region.ListRegionsCmd; +import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.log4j.Logger; + +import com.cloud.domain.Domain; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainManager; +import com.cloud.user.UserAccount; +import com.cloud.user.UserContext; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.component.Manager; +import com.cloud.utils.component.ManagerBase; + +@Local(value = { RegionService.class }) +public class RegionServiceImpl extends ManagerBase implements RegionService, Manager { + public static final Logger s_logger = Logger.getLogger(RegionServiceImpl.class); + + @Inject + private RegionDao _regionDao; + @Inject + private AccountDao _accountDao; + @Inject + private UserDao _userDao; + @Inject + private DomainDao _domainDao; + @Inject + private RegionManager _regionMgr; + @Inject + private AccountManager _accountMgr; + @Inject + private DomainManager _domainMgr; + + private String _name; + + @Override + public boolean configure(final String name, final Map params) throws ConfigurationException { + _name = name; + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + /** + * {@inheritDoc} + */ + @Override + public Region addRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + //Check for valid Name + //Check valid end_point url + return _regionMgr.addRegion(id, name, endPoint, apiKey, secretKey); + } + + /** + * {@inheritDoc} + */ + @Override + public Region updateRegion(int id, String name, String endPoint, String apiKey, String secretKey) { + //Check for valid Name + //Check valid end_point url + return _regionMgr.updateRegion(id, name, endPoint, apiKey, secretKey); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean removeRegion(int id) { + return _regionMgr.removeRegion(id); + } + + /** + * {@inheritDoc} + */ + @Override + public List listRegions(ListRegionsCmd cmd) { + return _regionMgr.listRegions(cmd.getId(), cmd.getName()); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUserAccount(DeleteAccountCmd cmd) { + boolean result = false; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.deleteUserAccount(cmd.getId()); + } else { + result = _regionMgr.deleteUserAccount(cmd.getId()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Account updateAccount(UpdateAccountCmd cmd) { + Account result = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.updateAccount(cmd); + } else { + result = _regionMgr.updateAccount(cmd); + } + + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Account disableAccount(DisableAccountCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException { + Account result = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + if(cmd.getLockRequested()) + result = _accountMgr.lockAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + else + result = _accountMgr.disableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + } else { + result = _regionMgr.disableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId(), cmd.getLockRequested()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Account enableAccount(EnableAccountCmd cmd) { + Account result = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.enableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + } else { + result = _regionMgr.enableAccount(cmd.getAccountName(), cmd.getDomainId(), cmd.getId()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteUser(DeleteUserCmd cmd) { + boolean result = false; + if(checkIsPropagate(cmd.getIsPropagate())){ + result = _accountMgr.deleteUser(cmd); + } else { + result = _regionMgr.deleteUser(cmd); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public Domain updateDomain(UpdateDomainCmd cmd) { + Domain domain = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + domain = _domainMgr.updateDomain(cmd); + } else { + domain = _regionMgr.updateDomain(cmd); + } + return domain; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deleteDomain(DeleteDomainCmd cmd) { + boolean result = false; + if(checkIsPropagate(cmd.isPropagate())){ + result = _domainMgr.deleteDomain(cmd.getId(), cmd.getCleanup()); + } else { + result = _regionMgr.deleteDomain(cmd.getId(), cmd.getCleanup()); + } + return result; + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount updateUser(UpdateUserCmd cmd){ + UserAccount user = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + user = _accountMgr.updateUser(cmd); + } else { + user = _regionMgr.updateUser(cmd); + } + return user; + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount disableUser(DisableUserCmd cmd) { + UserAccount user = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + user = _accountMgr.disableUser(cmd.getId()); + } else { + user = _regionMgr.disableUser(cmd.getId()); + } + return user; + } + + /** + * {@inheritDoc} + */ + @Override + public UserAccount enableUser(EnableUserCmd cmd) { + UserAccount user = null; + if(checkIsPropagate(cmd.getIsPropagate())){ + user = _accountMgr.enableUser(cmd.getId()); + } else { + user = _regionMgr.enableUser(cmd.getId()); + } + return user; + } + + private boolean isRootAdmin(short accountType) { + return (accountType == Account.ACCOUNT_TYPE_ADMIN); + } + + /** + * Check isPopagate flag, Only ROOT Admin can use this param + * @param isPopagate + * @return + */ + private boolean checkIsPropagate(Boolean isPopagate){ + if(isPopagate == null || !isPopagate){ + return false; + } + // Only Admin can use isPopagate flag + UserContext ctx = UserContext.current(); + Account caller = ctx.getCaller(); + if(!isRootAdmin(caller.getType())){ + throw new PermissionDeniedException("isPropagate param cannot be used by non ROOT Admin"); + } + return true; + } + +} diff --git a/server/src/org/apache/cloudstack/region/RegionSyncVO.java b/server/src/org/apache/cloudstack/region/RegionSyncVO.java new file mode 100644 index 00000000000..271f8e3a987 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionSyncVO.java @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +import com.cloud.utils.db.GenericDao; + + +@Entity +@Table(name="region_sync") +public class RegionSyncVO implements RegionSync { + + @Id + @Column(name="id") + private long id; + + @Column(name="region_id") + private int regionId; + + @Column(name="api") + private String api; + + @Column(name=GenericDao.CREATED_COLUMN) + private Date createDate; + + @Column(name="processed") + boolean processed; + + public RegionSyncVO() { + } + + public RegionSyncVO(int regionId, String api) { + this.regionId = regionId; + this.api = api; + } + + public int getRegionId() { + return regionId; + } + + public void setRegionId(int regionId) { + this.regionId = regionId; + } + + public String getApi() { + return api; + } + + public void setApi(String api) { + this.api = api; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public boolean isProcessed() { + return processed; + } + + public void setProcessed(boolean processed) { + this.processed = processed; + } + + public long getId() { + return id; + } + +} diff --git a/server/src/org/apache/cloudstack/region/RegionUser.java b/server/src/org/apache/cloudstack/region/RegionUser.java new file mode 100644 index 00000000000..298638e4811 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionUser.java @@ -0,0 +1,76 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import com.cloud.user.UserVO; + +public class RegionUser extends UserVO { + String accountUuid; + String created; + String account; + String accounttype; + String domainid; + String domain; + + public RegionUser() { + } + + public String getAccountuuid() { + return accountUuid; + } + + public void setAccountuuid(String accountUuid) { + this.accountUuid = accountUuid; + } + + public void setCreated(String created) { + this.created = created; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getAccounttype() { + return accounttype; + } + + public void setAccounttype(String accounttype) { + this.accounttype = accounttype; + } + + public String getDomainid() { + return domainid; + } + + public void setDomainid(String domainid) { + this.domainid = domainid; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + +} diff --git a/server/src/org/apache/cloudstack/region/RegionVO.java b/server/src/org/apache/cloudstack/region/RegionVO.java new file mode 100644 index 00000000000..0c36db2caff --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionVO.java @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + + +@Entity +@Table(name="region") +public class RegionVO implements Region{ + + @Id + @Column(name="id") + private int id; + + @Column(name="name") + private String name; + + @Column(name="end_point") + private String endPoint; + + @Column(name="api_key") + private String apiKey; + + @Column(name="secret_key") + private String secretKey; + + public RegionVO() { + } + + public RegionVO(int id, String name, String endPoint, String apiKey, String secretKey) { + this.id = id; + this.name = name; + this.endPoint = endPoint; + this.apiKey = apiKey; + this.secretKey = secretKey; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEndPoint() { + return endPoint; + } + + public void setEndPoint(String endPoint) { + this.endPoint = endPoint; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getSecretKey() { + return secretKey; + } + + public void setSecretKey(String secretKey) { + this.secretKey = secretKey; + } + + +} diff --git a/server/src/org/apache/cloudstack/region/RegionsApiUtil.java b/server/src/org/apache/cloudstack/region/RegionsApiUtil.java new file mode 100644 index 00000000000..c7625db5534 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/RegionsApiUtil.java @@ -0,0 +1,306 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.log4j.Logger; + +import com.cloud.domain.DomainVO; +import com.cloud.user.UserAccount; +import com.cloud.user.UserAccountVO; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; + +/** + * Utility class for making API calls between peer Regions + * + */ +public class RegionsApiUtil { + public static final Logger s_logger = Logger.getLogger(RegionsApiUtil.class); + + /** + * Makes an api call using region service end_point, api command and params + * @param region + * @param command + * @param params + * @return True, if api is successful + */ + protected static boolean makeAPICall(Region region, String command, List params){ + try { + String apiParams = buildParams(command, params); + String url = buildUrl(apiParams, region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + return true; + } else { + return false; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return false; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return false; + } + } + + /** + * Makes an api call using region service end_point, api command and params + * Returns Account object on success + * @param region + * @param command + * @param params + * @return + */ + protected static RegionAccount makeAccountAPICall(Region region, String command, List params){ + try { + String url = buildUrl(buildParams(command, params), region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + InputStream is = method.getResponseBodyAsStream(); + //Translate response to Account object + XStream xstream = new XStream(new DomDriver()); + xstream.alias("account", RegionAccount.class); + xstream.alias("user", RegionUser.class); + xstream.aliasField("id", RegionAccount.class, "uuid"); + xstream.aliasField("name", RegionAccount.class, "accountName"); + xstream.aliasField("accounttype", RegionAccount.class, "type"); + xstream.aliasField("domainid", RegionAccount.class, "domainUuid"); + xstream.aliasField("networkdomain", RegionAccount.class, "networkDomain"); + xstream.aliasField("id", RegionUser.class, "uuid"); + xstream.aliasField("accountId", RegionUser.class, "accountUuid"); + ObjectInputStream in = xstream.createObjectInputStream(is); + return (RegionAccount)in.readObject(); + } else { + return null; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return null; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return null; + } catch (ClassNotFoundException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * Makes an api call using region service end_point, api command and params + * Returns Domain object on success + * @param region + * @param command + * @param params + * @return + */ + protected static RegionDomain makeDomainAPICall(Region region, String command, List params){ + try { + String url = buildUrl(buildParams(command, params), region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + InputStream is = method.getResponseBodyAsStream(); + XStream xstream = new XStream(new DomDriver()); + //Translate response to Domain object + xstream.alias("domain", RegionDomain.class); + xstream.aliasField("id", RegionDomain.class, "uuid"); + xstream.aliasField("parentdomainid", RegionDomain.class, "parentUuid"); + xstream.aliasField("networkdomain", DomainVO.class, "networkDomain"); + ObjectInputStream in = xstream.createObjectInputStream(is); + return (RegionDomain)in.readObject(); + } else { + return null; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return null; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return null; + } catch (ClassNotFoundException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * Makes an api call using region service end_point, api command and params + * Returns UserAccount object on success + * @param region + * @param command + * @param params + * @return + */ + protected static UserAccount makeUserAccountAPICall(Region region, String command, List params){ + try { + String url = buildUrl(buildParams(command, params), region); + HttpClient client = new HttpClient(); + HttpMethod method = new GetMethod(url); + if( client.executeMethod(method) == 200){ + InputStream is = method.getResponseBodyAsStream(); + XStream xstream = new XStream(new DomDriver()); + xstream.alias("useraccount", UserAccountVO.class); + xstream.aliasField("id", UserAccountVO.class, "uuid"); + ObjectInputStream in = xstream.createObjectInputStream(is); + return (UserAccountVO)in.readObject(); + } else { + return null; + } + } catch (HttpException e) { + s_logger.error(e.getMessage()); + return null; + } catch (IOException e) { + s_logger.error(e.getMessage()); + return null; + } catch (ClassNotFoundException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * Builds parameters string with command and encoded param values + * @param command + * @param params + * @return + */ + protected static String buildParams(String command, List params) { + StringBuffer paramString = new StringBuffer("command="+command); + Iterator iter = params.iterator(); + try { + while(iter.hasNext()){ + NameValuePair param = iter.next(); + if(param.getValue() != null && !(param.getValue().isEmpty())){ + paramString.append("&"+param.getName()+"="+URLEncoder.encode(param.getValue(), "UTF-8")); + } + } + } + catch (UnsupportedEncodingException e) { + s_logger.error(e.getMessage()); + return null; + } + return paramString.toString(); + } + + /** + * Build URL for api call using region end_point + * Parameters are sorted and signed using secret_key + * @param apiParams + * @param region + * @return + */ + private static String buildUrl(String apiParams, Region region) { + + String apiKey = region.getApiKey(); + String secretKey = region.getSecretKey(); + + + if (apiKey == null || secretKey == null) { + return region.getEndPoint() +"?"+ apiParams; + } + + String encodedApiKey; + try { + encodedApiKey = URLEncoder.encode(apiKey, "UTF-8"); + + List sortedParams = new ArrayList(); + sortedParams.add("apikey=" + encodedApiKey.toLowerCase()); + StringTokenizer st = new StringTokenizer(apiParams, "&"); + String url = null; + boolean first = true; + while (st.hasMoreTokens()) { + String paramValue = st.nextToken(); + String param = paramValue.substring(0, paramValue.indexOf("=")); + String value = paramValue.substring(paramValue.indexOf("=") + 1, paramValue.length()); + if (first) { + url = param + "=" + value; + first = false; + } else { + url = url + "&" + param + "=" + value; + } + sortedParams.add(param.toLowerCase() + "=" + value.toLowerCase()); + } + Collections.sort(sortedParams); + + + //Construct the sorted URL and sign and URL encode the sorted URL with your secret key + String sortedUrl = null; + first = true; + for (String param : sortedParams) { + if (first) { + sortedUrl = param; + first = false; + } else { + sortedUrl = sortedUrl + "&" + param; + } + } + String encodedSignature = signRequest(sortedUrl, secretKey); + + String finalUrl = region.getEndPoint() +"?"+apiParams+ "&apiKey=" + apiKey + "&signature=" + encodedSignature; + + return finalUrl; + + } catch (UnsupportedEncodingException e) { + s_logger.error(e.getMessage()); + return null; + } + } + + /** + * 1. Signs a string with a secret key using SHA-1 2. Base64 encode the result 3. URL encode the final result + * + * @param request + * @param key + * @return + */ + private static String signRequest(String request, String key) { + try { + Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacSHA1"); + mac.init(keySpec); + mac.update(request.getBytes()); + byte[] encryptedBytes = mac.doFinal(); + return URLEncoder.encode(Base64.encodeBase64String(encryptedBytes), "UTF-8"); + } catch (Exception ex) { + s_logger.error(ex.getMessage()); + return null; + } + } + +} \ No newline at end of file diff --git a/server/src/org/apache/cloudstack/region/dao/RegionDao.java b/server/src/org/apache/cloudstack/region/dao/RegionDao.java new file mode 100644 index 00000000000..91b51d3763e --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionDao.java @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import org.apache.cloudstack.region.RegionVO; + +import com.cloud.utils.db.GenericDao; + +public interface RegionDao extends GenericDao { + + RegionVO findByName(String name); + +} diff --git a/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java b/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java new file mode 100644 index 00000000000..8f50f939e41 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionDaoImpl.java @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import javax.ejb.Local; + +import org.apache.cloudstack.region.RegionVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +@Component +@Local(value={RegionDao.class}) +public class RegionDaoImpl extends GenericDaoBase implements RegionDao { + private static final Logger s_logger = Logger.getLogger(RegionDaoImpl.class); + protected SearchBuilder NameSearch; + protected SearchBuilder AllFieldsSearch; + + public RegionDaoImpl(){ + NameSearch = createSearchBuilder(); + NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); + NameSearch.done(); + } + + @Override + public RegionVO findByName(String name) { + SearchCriteria sc = NameSearch.create(); + sc.setParameters("name", name); + return findOneBy(sc); + } +} diff --git a/server/src/org/apache/cloudstack/region/dao/RegionSyncDao.java b/server/src/org/apache/cloudstack/region/dao/RegionSyncDao.java new file mode 100644 index 00000000000..df287e51e32 --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionSyncDao.java @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import org.apache.cloudstack.region.RegionSyncVO; + +import com.cloud.utils.db.GenericDao; + +public interface RegionSyncDao extends GenericDao { +} diff --git a/server/src/org/apache/cloudstack/region/dao/RegionSyncDaoImpl.java b/server/src/org/apache/cloudstack/region/dao/RegionSyncDaoImpl.java new file mode 100644 index 00000000000..9cd9b0dd71b --- /dev/null +++ b/server/src/org/apache/cloudstack/region/dao/RegionSyncDaoImpl.java @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.region.dao; + +import javax.ejb.Local; + +import org.apache.cloudstack.region.RegionSyncVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.utils.db.GenericDaoBase; + +@Component +@Local(value={RegionSyncDao.class}) +public class RegionSyncDaoImpl extends GenericDaoBase implements RegionSyncDao { + private static final Logger s_logger = Logger.getLogger(RegionSyncDaoImpl.class); + + public RegionSyncDaoImpl(){ + + } +} diff --git a/server/test/com/cloud/async/TestAsyncJobManager.java b/server/test/com/cloud/async/TestAsyncJobManager.java index 7cb24ddc388..e3233939bc5 100644 --- a/server/test/com/cloud/async/TestAsyncJobManager.java +++ b/server/test/com/cloud/async/TestAsyncJobManager.java @@ -228,25 +228,25 @@ public class TestAsyncJobManager extends TestCase { public void testDomain() { DomainDao domainDao = new DomainDaoImpl(); - DomainVO domain1 = new DomainVO("d1", 2L, 1L, null); + DomainVO domain1 = new DomainVO("d1", 2L, 1L, null, 1); domainDao.create(domain1); - DomainVO domain2 = new DomainVO("d2", 2L, 1L, null); + DomainVO domain2 = new DomainVO("d2", 2L, 1L, null, 1); domainDao.create(domain2); - DomainVO domain3 = new DomainVO("d3", 2L, 1L, null); + DomainVO domain3 = new DomainVO("d3", 2L, 1L, null, 1); domainDao.create(domain3); - DomainVO domain11 = new DomainVO("d11", 2L, domain1.getId(), null); + DomainVO domain11 = new DomainVO("d11", 2L, domain1.getId(), null, 1); domainDao.create(domain11); domainDao.remove(domain11.getId()); - DomainVO domain12 = new DomainVO("d12", 2L, domain1.getId(), null); + DomainVO domain12 = new DomainVO("d12", 2L, domain1.getId(), null, 1); domainDao.create(domain12); domainDao.remove(domain3.getId()); - DomainVO domain4 = new DomainVO("d4", 2L, 1L, null); + DomainVO domain4 = new DomainVO("d4", 2L, 1L, null, 1); domainDao.create(domain4); } } diff --git a/server/test/com/cloud/snapshot/SnapshotDaoTest.java b/server/test/com/cloud/snapshot/SnapshotDaoTest.java index c84778dadd7..099b21a503e 100644 --- a/server/test/com/cloud/snapshot/SnapshotDaoTest.java +++ b/server/test/com/cloud/snapshot/SnapshotDaoTest.java @@ -35,6 +35,7 @@ import com.cloud.utils.component.ComponentContext; import junit.framework.Assert; import junit.framework.TestCase; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:/SnapshotDaoTestContext.xml") public class SnapshotDaoTest extends TestCase { @@ -47,9 +48,9 @@ public class SnapshotDaoTest extends TestCase { @Test public void testListBy() { - List snapshots = dao.listByInstanceId(3, Snapshot.Status.BackedUp); + List snapshots = dao.listByInstanceId(3, Snapshot.State.BackedUp); for(SnapshotVO snapshot : snapshots) { - Assert.assertTrue(snapshot.getStatus() == Snapshot.Status.BackedUp); + Assert.assertTrue(snapshot.getState() == Snapshot.State.BackedUp); } } } diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java index 1893d67d91c..5632070d6d6 100644 --- a/server/test/com/cloud/user/MockAccountManagerImpl.java +++ b/server/test/com/cloud/user/MockAccountManagerImpl.java @@ -210,12 +210,6 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco return false; } - @Override - public UserVO createUser(String userName, String password, String firstName, String lastName, String email, String timeZone, String accountName, Long domainId) { - // TODO Auto-generated method stub - return null; - } - @Override public Long checkAccessAndSpecifyAuthority(Account caller, Long zoneId) { // TODO Auto-generated method stub @@ -284,23 +278,6 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco return true; } - - @Override - public UserAccount createUserAccount(String userName, String password, - String firstName, String lastName, String email, String timezone, - String accountName, short accountType, Long domainId, - String networkDomain, Map details) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Account createAccount(String accountName, short accountType, - Long domainId, String networkDomain, Map details) { - // TODO Auto-generated method stub - return null; - } - @Override public boolean enableAccount(long accountId) { // TODO Auto-generated method stub @@ -347,6 +324,31 @@ public class MockAccountManagerImpl extends ManagerBase implements Manager, Acco return null; } + @Override + public UserAccount createUserAccount(String userName, String password, + String firstName, String lastName, String email, String timezone, + String accountName, short accountType, Long domainId, + String networkDomain, Map details, + String accountUUID, String userUUID, Integer regionId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public User createUser(String userName, String password, String firstName, + String lastName, String email, String timeZone, String accountName, + Long domainId, String userUUID, Integer regionId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Account createAccount(String accountName, short accountType, + Long domainId, String networkDomain, Map details, String uuid, + int regionId) { + // TODO Auto-generated method stub + return null; + } @Override public RoleType getRoleType(Account account) { return null; diff --git a/server/test/com/cloud/user/MockDomainManagerImpl.java b/server/test/com/cloud/user/MockDomainManagerImpl.java index d249c8013d2..b791f4cf8a1 100644 --- a/server/test/com/cloud/user/MockDomainManagerImpl.java +++ b/server/test/com/cloud/user/MockDomainManagerImpl.java @@ -26,6 +26,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd; import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd; import org.springframework.stereotype.Component; +import org.apache.cloudstack.api.command.admin.domain.UpdateDomainCmd; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; @@ -38,12 +39,6 @@ import com.cloud.utils.component.ManagerBase; @Local(value = { DomainManager.class, DomainService.class }) public class MockDomainManagerImpl extends ManagerBase implements DomainManager, DomainService { - @Override - public Domain createDomain(String name, Long parentId, String networkDomain) { - // TODO Auto-generated method stub - return null; - } - @Override public Domain getDomain(long id) { // TODO Auto-generated method stub @@ -88,13 +83,6 @@ public class MockDomainManagerImpl extends ManagerBase implements DomainManager, return null; } - @Override - public Domain createDomain(String name, Long parentId, Long ownerId, - String networkDomain) { - // TODO Auto-generated method stub - return null; - } - @Override public DomainVO findDomainByPath(String domainPath) { // TODO Auto-generated method stub @@ -149,4 +137,24 @@ public class MockDomainManagerImpl extends ManagerBase implements DomainManager, return null; } + @Override + public Domain createDomain(String name, Long parentId, + String networkDomain, String domainUUID, Integer regionId) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Domain updateDomain(UpdateDomainCmd cmd) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Domain createDomain(String name, Long parentId, Long ownerId, + String networkDomain, String domainUUID, Integer regionId) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java index e0660518e9c..645550664cf 100644 --- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -326,8 +326,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public Long getDefaultPageSize() { - // TODO Auto-generated method stub - return null; + return 500L; } /* (non-Javadoc) diff --git a/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java b/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java index de1bbb9b588..a4832915f51 100644 --- a/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java +++ b/server/test/com/cloud/vpc/dao/MockNetworkDaoImpl.java @@ -16,12 +16,7 @@ // under the License. package com.cloud.vpc.dao; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; - +import com.cloud.network.Network; import com.cloud.network.Network.GuestType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.dao.NetworkAccountVO; @@ -31,6 +26,11 @@ import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; +import javax.ejb.Local; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + @Local(value = NetworkDao.class) @DB(txn = false) public class MockNetworkDaoImpl extends GenericDaoBase implements NetworkDao{ @@ -342,6 +342,11 @@ public class MockNetworkDaoImpl extends GenericDaoBase implemen return 0; } + @Override + public boolean updateState(Network.State currentState, Network.Event event, Network.State nextState, Network vo, Object data) { + return true; + } + /* (non-Javadoc) * @see com.cloud.network.dao.NetworkDao#listNetworksByAccount(long, long, com.cloud.network.Network.GuestType, boolean) */ diff --git a/server/test/org/apache/cloudstack/region/RegionManagerTest.java b/server/test/org/apache/cloudstack/region/RegionManagerTest.java new file mode 100644 index 00000000000..330f0b49d22 --- /dev/null +++ b/server/test/org/apache/cloudstack/region/RegionManagerTest.java @@ -0,0 +1,74 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.region; + + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.cloudstack.api.command.admin.domain.DeleteDomainCmd; +import org.apache.cloudstack.region.dao.RegionDao; +import org.apache.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.user.dao.AccountDao; + + + +public class RegionManagerTest extends TestCase { + private static final Logger s_logger = Logger.getLogger(RegionManagerTest.class); + + @Before + @Override + protected void setUp() { + + } + + @Test + public void testUniqueName() { + RegionManagerImpl regionMgr = new RegionManagerImpl(); + RegionDao regionDao = Mockito.mock(RegionDao.class); + RegionVO region = new RegionVO(2, "APAC", "", null, null); + Mockito.when(regionDao.findByName(Mockito.anyString())).thenReturn(region); + regionMgr._regionDao = regionDao; + try { + regionMgr.addRegion(2, "APAC", "", null, null); + } catch (InvalidParameterValueException e){ + Assert.assertEquals("Region with name: APAC already exists", e.getMessage()); + } + } + + @Test + public void testUserDelete() { + RegionManagerImpl regionMgr = new RegionManagerImpl(); + AccountDao accountDao = Mockito.mock(AccountDao.class); + Mockito.when(accountDao.findById(Mockito.anyLong())).thenReturn(null); + regionMgr._accountDao = accountDao; + try { + regionMgr.deleteUserAccount(5); + } catch (InvalidParameterValueException e){ + Assert.assertEquals("The specified account does not exist in the system", e.getMessage()); + } + } + +} diff --git a/server/test/resources/VpcApiUnitTestContext.xml b/server/test/resources/VpcApiUnitTestContext.xml new file mode 100644 index 00000000000..d9330229383 --- /dev/null +++ b/server/test/resources/VpcApiUnitTestContext.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 55afa0f152b..c15b9964f0a 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -141,6 +141,7 @@ DROP TABLE IF EXISTS `cloud`.`op_dc_storage_network_ip_address`; DROP TABLE IF EXISTS `cloud`.`cluster_vsm_map`; DROP TABLE IF EXISTS `cloud`.`virtual_supervisor_module`; DROP TABLE IF EXISTS `cloud`.`port_profile`; +DROP TABLE IF EXISTS `cloud`.`region`; DROP TABLE IF EXISTS `cloud`.`s2s_customer_gateway`; DROP TABLE IF EXISTS `cloud`.`s2s_vpn_gateway`; DROP TABLE IF EXISTS `cloud`.`s2s_vpn_connection`; @@ -708,7 +709,7 @@ CREATE TABLE `cloud`.`op_dc_vnet_alloc` ( PRIMARY KEY (`id`), UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id__account_id`(`vnet`, `data_center_id`, `account_id`), INDEX `i_op_dc_vnet_alloc__dc_taken`(`data_center_id`, `taken`), - UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id`(`vnet`, `data_center_id`), + UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id`(`vnet`, `physical_network_id`, `data_center_id`), CONSTRAINT `fk_op_dc_vnet_alloc__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, CONSTRAINT `fk_op_dc_vnet_alloc__physical_network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -947,6 +948,7 @@ CREATE TABLE `cloud`.`user` ( `timezone` varchar(30) default NULL, `registration_token` varchar(255) default NULL, `is_registered` tinyint NOT NULL DEFAULT 0 COMMENT '1: yes, 0: no', + `region_id` int unsigned, `incorrect_login_attempts` integer unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `i_user__removed`(`removed`), @@ -1298,6 +1300,7 @@ CREATE TABLE `cloud`.`domain` ( `state` char(32) NOT NULL default 'Active' COMMENT 'state of the domain', `network_domain` varchar(255), `type` varchar(255) NOT NULL DEFAULT 'Normal' COMMENT 'type of the domain - can be Normal or Project', + `region_id` int unsigned, PRIMARY KEY (`id`), UNIQUE (parent, name, removed), INDEX `i_domain__path`(`path`), @@ -1316,6 +1319,7 @@ CREATE TABLE `cloud`.`account` ( `cleanup_needed` tinyint(1) NOT NULL default '0', `network_domain` varchar(255), `default_zone_id` bigint unsigned, + `region_id` int unsigned, PRIMARY KEY (`id`), INDEX i_account__removed(`removed`), CONSTRAINT `fk_account__default_zone_id` FOREIGN KEY `fk_account__default_zone_id`(`default_zone_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, @@ -2299,6 +2303,15 @@ CREATE TABLE `cloud`.`netscaler_pod_ref` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`region` ( + `id` int unsigned NOT NULL UNIQUE, + `name` varchar(255) NOT NULL UNIQUE, + `end_point` varchar(255) NOT NULL, + `api_key` varchar(255), + `secret_key` varchar(255), + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE `cloud`.`vpc` ( `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', `uuid` varchar(40) NOT NULL, @@ -2585,6 +2598,15 @@ CREATE TABLE `cloud`.`autoscale_vmgroup_policy_map` ( INDEX `i_autoscale_vmgroup_policy_map__vmgroup_id`(`vmgroup_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE `cloud`.`region_sync` ( + `id` bigint unsigned NOT NULL auto_increment, + `region_id` int unsigned NOT NULL, + `api` varchar(1024) NOT NULL, + `created` datetime NOT NULL COMMENT 'date created', + `processed` tinyint NOT NULL default '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (1, UUID(), 'snmp','Linux User CPU - percentage', '1.3.6.1.4.1.2021.11.9.0', now()); INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (2, UUID(), 'snmp','Linux System CPU - percentage', '1.3.6.1.4.1.2021.11.10.0', now()); INSERT INTO `cloud`.`counter` (id, uuid, source, name, value,created) VALUES (3, UUID(), 'snmp','Linux CPU Idle - percentage', '1.3.6.1.4.1.2021.11.11.0', now()); diff --git a/setup/db/db/schema-40to410.sql b/setup/db/db/schema-40to410.sql index ed4946e54dd..304e12c1eda 100644 --- a/setup/db/db/schema-40to410.sql +++ b/setup/db/db/schema-40to410.sql @@ -1264,3 +1264,7 @@ CREATE VIEW `cloud`.`data_center_view` AS `cloud`.`domain` ON data_center.domain_id = domain.id; INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'management-server', 'direct.agent.pool.size', '500', 'Default size for DirectAgentPool'); + +ALTER TABLE `cloud`.`op_dc_vnet_alloc` DROP INDEX i_op_dc_vnet_alloc__vnet__data_center_id; + +ALTER TABLE `cloud`.`op_dc_vnet_alloc` ADD CONSTRAINT UNIQUE `i_op_dc_vnet_alloc__vnet__data_center_id`(`vnet`, `physical_network_id`, `data_center_id`); diff --git a/tools/whisker/LICENSE b/tools/whisker/LICENSE index 7efac5c566a..025cb33136b 100644 --- a/tools/whisker/LICENSE +++ b/tools/whisker/LICENSE @@ -748,7 +748,7 @@ Within the deps/awsapi-lib directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. ¤ + computer software" (as that term is defined at 48 C.F.R. � 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -1138,7 +1138,7 @@ Within the deps/awsapi-lib directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. ¤ + computer software" (as that term is defined at 48 C.F.R. � 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -1526,7 +1526,7 @@ Within the deps/awsapi-lib directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. ¤ + computer software" (as that term is defined at 48 C.F.R. � 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -1867,7 +1867,9 @@ Within the deps/awsapi-lib directory slf4j-api-1.5.11.jar from https://github.com/qos-ch/slf4j slf4j-jdk14-1.5.11.jar from https://github.com/qos-ch/slf4j - licensed under the Mozilla Public License, Version 1.0 http://www.mozilla.org/MPL/1.1/ (as follows) + + licensed under the Mozilla Public License, Version 1.1 http://www.mozilla.org/MPL/1.1/ (as follows) + MOZILLA PUBLIC LICENSE @@ -2344,6 +2346,486 @@ Within the deps/awsapi-lib directory from Shigeru Chiba http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/ javassist-3.9.0.GA.jar from http://sourceforge.net/projects/jboss/files/Javassist/ + + licensed under the Mozilla Public License, Version 1.1 http://www.mozilla.org/MPL/1.1/ (as follows) + + Copyright (c) 2007-2012 VMware, Inc. All Rights Reserved. + + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + + 1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + + 2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + + 3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + + 4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + + 5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + + 6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + + 7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + + 8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + + 9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + + 10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + + 11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + + 12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + + 13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + + EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (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.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is RabbitMQ. + + The Initial Developer of the Original Code is VMware, Ltd.. + Portions created by VMware, Ltd. are Copyright (C) + 2007-2012 VMware, Inc.. All Rights Reserved. + + Contributor(s): . + + Alternatively, the contents of this file may be used under the terms + of the GNU General Public License Version 2 license (the "[GPL] License"), in which case the + provisions of [GPL] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [GPL] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [GPL] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [GPL] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + + + from VMware, Inc http://www.vmware.com/ + rabbitmq-client.jar from http://www.rabbitmq.com/java-client.html + + Within the patches/systemvm/debian/config/etc directory placed in the public domain by Adiscon GmbH http://www.adiscon.com/ @@ -2980,7 +3462,7 @@ Within the target/jar directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. ¤ + computer software" (as that term is defined at 48 C.F.R. � 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -3369,7 +3851,7 @@ Within the target/jar directory The Covered Software is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial - computer software" (as that term is defined at 48 C.F.R. ¤ + computer software" (as that term is defined at 48 C.F.R. � 252.227-7014(a)(1)) and "commercial computer software documentation" as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 @@ -3895,7 +4377,7 @@ Within the target/jar directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) - Copyright (C) 2008 Tóth István + Copyright (C) 2008 T�th Istv�n 2008-2012 Daniel Veillard 2009-2011 Bryan Kearney @@ -4026,7 +4508,7 @@ Within the ui/lib directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) - Copyright (c) 2006 - 2011 Jörn Zaefferer + Copyright (c) 2006 - 2011 J�rn Zaefferer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -4221,7 +4703,7 @@ Within the ui/lib/jquery-ui directory Within the ui/lib/qunit directory licensed under the MIT License http://www.opensource.org/licenses/mit-license.php (as follows) - Copyright (c) 2012 John Resig, Jörn Zaefferer + Copyright (c) 2012 John Resig, J�rn Zaefferer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/tools/whisker/descriptor-for-packaging.xml b/tools/whisker/descriptor-for-packaging.xml index 0144dbc055b..29a8284686b 100644 --- a/tools/whisker/descriptor-for-packaging.xml +++ b/tools/whisker/descriptor-for-packaging.xml @@ -2423,6 +2423,10 @@ Innovation Centre, 2006 (http://www.it-innovation.soton.ac.uk). id='adiscon.com' name='Adiscon GmbH' url='http://www.adiscon.com/' /> + Copyright (c) 2013 The Apache Software Foundation @@ -2948,5 +2952,19 @@ Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. + + Copyright (c) 2007-2012 VMware, Inc. All Rights Reserved. + + PROJECTRabbitMQ + INITIAL_DEVELOPERVMware, Ltd. + INITIAL_DEVELOPER_COPYRIGHT2007-2012 VMware, Inc. + CONTRIBUTORS + ALT_LIC_NAMEGNU General Public License Version 2 + ALT_LIC_SHORTGPL + + + + + diff --git a/utils/conf/db.properties b/utils/conf/db.properties index 1dcfcdd135c..e1b5fe9a2c1 100644 --- a/utils/conf/db.properties +++ b/utils/conf/db.properties @@ -20,6 +20,7 @@ # in which the management server(Tomcat) is running cluster.node.IP=127.0.0.1 cluster.servlet.port=9090 +region.id=1 # CloudStack database settings db.cloud.username=cloud diff --git a/utils/src/com/cloud/utils/db/GenericDao.java b/utils/src/com/cloud/utils/db/GenericDao.java index 31a25fd7088..c0a9029bf3c 100755 --- a/utils/src/com/cloud/utils/db/GenericDao.java +++ b/utils/src/com/cloud/utils/db/GenericDao.java @@ -268,6 +268,8 @@ public interface GenericDao { * @return */ Class getEntityBeanType(); + + public int getRegionId(); /** * @param sc diff --git a/utils/src/com/cloud/utils/db/GenericDaoBase.java b/utils/src/com/cloud/utils/db/GenericDaoBase.java index 623c349e8c5..cf30474fbbf 100755 --- a/utils/src/com/cloud/utils/db/GenericDaoBase.java +++ b/utils/src/com/cloud/utils/db/GenericDaoBase.java @@ -1800,6 +1800,11 @@ public abstract class GenericDaoBase extends Compone return sc; } + @Override + public int getRegionId(){ + return Transaction.s_region_id; + } + public Integer getCount(SearchCriteria sc) { String clause = sc != null ? sc.getWhereClause() : null; if (clause != null && clause.length() == 0) { diff --git a/utils/src/com/cloud/utils/db/Transaction.java b/utils/src/com/cloud/utils/db/Transaction.java index 6884fb13d81..73f5bb100ea 100755 --- a/utils/src/com/cloud/utils/db/Transaction.java +++ b/utils/src/com/cloud/utils/db/Transaction.java @@ -83,6 +83,7 @@ public class Transaction { public static final short AWSAPI_DB = 2; public static final short SIMULATOR_DB = 3; public static final short CONNECTED_DB = -1; + public static int s_region_id; private static AtomicLong s_id = new AtomicLong(); private static final TransactionMBeanImpl s_mbean = new TransactionMBeanImpl(); @@ -1066,6 +1067,12 @@ public class Transaction { System.setProperty("javax.net.ssl.trustStorePassword", dbProps.getProperty("db.cloud.trustStorePassword")); } + String regionId = dbProps.getProperty("region.id"); + if(regionId == null){ + s_region_id = 1; + } else { + s_region_id = Integer.parseInt(regionId); + } final GenericObjectPool cloudConnectionPool = new GenericObjectPool(null, cloudMaxActive, GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION, cloudMaxWait, cloudMaxIdle, cloudTestOnBorrow, false, cloudTimeBtwEvictionRunsMillis, 1, cloudMinEvcitableIdleTimeMillis, cloudTestWhileIdle);