From 8bbc8ee0ec1c9d36178bbc5ce9e42d3fb282cfcf Mon Sep 17 00:00:00 2001 From: Deepak Garg Date: Mon, 16 Jul 2012 19:37:10 +0530 Subject: [PATCH] Added csurl as param in CreateAutoScaleVmProfileCmd --- .../cloud/agent/api/to/LoadBalancerTO.java | 30 +- api/src/com/cloud/api/ApiConstants.java | 41 +- .../commands/CreateAutoScaleVmProfileCmd.java | 13 +- .../cloud/network/as/AutoScaleVmProfile.java | 2 + .../cloud/network/lb/LoadBalancingRule.java | 134 +- server/src/com/cloud/api/ApiServer.java | 2238 ++++++++--------- .../network/as/AutoScaleManagerImpl.java | 146 +- .../network/as/AutoScaleVmProfileVO.java | 14 +- .../lb/LoadBalancingRulesManagerImpl.java | 59 +- setup/db/create-schema.sql | 1 + 10 files changed, 1287 insertions(+), 1391 deletions(-) diff --git a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java index 0cc9c496eee..2244278aeb8 100644 --- a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java @@ -12,7 +12,6 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.agent.api.to; - import java.util.ArrayList; import java.util.List; @@ -29,7 +28,6 @@ import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; import com.cloud.utils.Pair; - public class LoadBalancerTO { Long id; String srcIp; @@ -43,7 +41,7 @@ public class LoadBalancerTO { private AutoScaleVmGroupTO autoScaleVmGroupTO; final static int MAX_STICKINESS_POLICIES = 1; - public LoadBalancerTO (Long id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, List destinations) { + public LoadBalancerTO(Long id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, List destinations) { this.id = id; this.srcIp = srcIp; this.srcPort = srcPort; @@ -59,10 +57,10 @@ public class LoadBalancerTO { } } - public LoadBalancerTO (Long id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, List arg_destinations, List stickinessPolicies) { + public LoadBalancerTO(Long id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, List arg_destinations, List stickinessPolicies) { this(id, srcIp, srcPort, protocol, algorithm, revoked, alreadyAdded, arg_destinations); this.stickinessPolicies = null; - if (stickinessPolicies != null && stickinessPolicies.size()>0) { + if (stickinessPolicies != null && stickinessPolicies.size() > 0) { this.stickinessPolicies = new StickinessPolicyTO[MAX_STICKINESS_POLICIES]; int index = 0; for (LbStickinessPolicy stickinesspolicy : stickinessPolicies) { @@ -80,7 +78,6 @@ public class LoadBalancerTO { } } - protected LoadBalancerTO() { } @@ -155,6 +152,7 @@ public class LoadBalancerTO { int destPort; boolean revoked; boolean alreadyAdded; + public DestinationTO(String destIp, int destPort, boolean revoked, boolean alreadyAdded) { this.destIp = destIp; this.destPort = destPort; @@ -206,7 +204,7 @@ public class LoadBalancerTO { } } - public static class ConditionTO{ + public static class ConditionTO { private final long threshold; private final String relationalOperator; private final CounterTO counter; @@ -273,7 +271,6 @@ public class LoadBalancerTO { } } - public static class AutoScaleVmProfileTO { private final Long zoneId; private final Long domainId; @@ -287,7 +284,7 @@ public class LoadBalancerTO { private final String autoScaleUserApiKey; private final String autoScaleUserSecretKey; - public AutoScaleVmProfileTO(Long zoneId, Long domainId, String cloudStackApiUrl, String autoScaleUserApiKey, String autoScaleUserSecretKey,Long serviceOfferingId, Long templateId, + public AutoScaleVmProfileTO(Long zoneId, Long domainId, String cloudStackApiUrl, String autoScaleUserApiKey, String autoScaleUserSecretKey, Long serviceOfferingId, Long templateId, String otherDeployParams, String snmpCommunity, Integer snmpPort, Integer destroyVmGraceperiod) { this.zoneId = zoneId; this.domainId = domainId; @@ -301,36 +298,47 @@ public class LoadBalancerTO { this.autoScaleUserApiKey = autoScaleUserApiKey; this.autoScaleUserSecretKey = autoScaleUserSecretKey; } + public Long getZoneId() { return zoneId; } + public Long getDomainId() { return domainId; } + public Long getServiceOfferingId() { return serviceOfferingId; } + public Long getTemplateId() { return templateId; } + public String getOtherDeployParams() { return otherDeployParams; } + public String getSnmpCommunity() { return snmpCommunity; } + public Integer getSnmpPort() { return snmpPort; } + public Integer getDestroyVmGraceperiod() { return destroyVmGraceperiod; } + public String getCloudStackApiUrl() { return cloudStackApiUrl; } + public String getAutoScaleUserApiKey() { return autoScaleUserApiKey; } + public String getAutoScaleUserSecretKey() { return autoScaleUserSecretKey; } @@ -407,13 +415,13 @@ public class LoadBalancerTO { LbAutoScaleVmProfile lbAutoScaleVmProfile = lbAutoScaleVmGroup.getProfile(); AutoScaleVmProfile autoScaleVmProfile = lbAutoScaleVmProfile.getProfile(); AutoScaleVmProfileTO autoScaleVmProfileTO = new AutoScaleVmProfileTO(autoScaleVmProfile.getZoneId(), autoScaleVmProfile.getDomainId(), - lbAutoScaleVmProfile.getAutoScaleUserApiKey(), lbAutoScaleVmProfile.getAutoScaleUserSecretKey(), lbAutoScaleVmProfile.getCloudStackApiUrl(), + lbAutoScaleVmProfile.getAutoScaleUserApiKey(), lbAutoScaleVmProfile.getAutoScaleUserSecretKey(), autoScaleVmProfile.getCsUrl(), autoScaleVmProfile.getServiceOfferingId(), autoScaleVmProfile.getTemplateId(), autoScaleVmProfile.getOtherDeployParams(), autoScaleVmProfile.getSnmpCommunity(), autoScaleVmProfile.getSnmpPort(), autoScaleVmProfile.getDestroyVmGraceperiod()); AutoScaleVmGroup autoScaleVmGroup = lbAutoScaleVmGroup.getVmGroup(); autoScaleVmGroupTO = new AutoScaleVmGroupTO(autoScaleVmGroup.getMinMembers(), autoScaleVmGroup.getMaxMembers(), autoScaleVmGroup.getMemberPort(), - autoScaleVmGroup.getInterval(),autoScalePolicyTOs, autoScaleVmProfileTO, autoScaleVmGroup.getState()); + autoScaleVmGroup.getInterval(), autoScalePolicyTOs, autoScaleVmProfileTO, autoScaleVmGroup.getState()); } } diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 12336cb988a..687f7dc23e4 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -27,10 +27,10 @@ public class ApiConstants { public static final String BIND_DN = "binddn"; public static final String BIND_PASSWORD = "bindpass"; public static final String CATEGORY = "category"; - public static final String CERTIFICATE = "certificate"; - public static final String PRIVATE_KEY = "privatekey"; - public static final String DOMAIN_SUFFIX = "domainsuffix"; - public static final String DNS_SEARCH_ORDER = "dnssearchorder"; + public static final String CERTIFICATE = "certificate"; + public static final String PRIVATE_KEY = "privatekey"; + public static final String DOMAIN_SUFFIX = "domainsuffix"; + public static final String DNS_SEARCH_ORDER = "dnssearchorder"; public static final String CIDR = "cidr"; public static final String CIDR_LIST = "cidrlist"; public static final String CLEANUP = "cleanup"; @@ -100,7 +100,7 @@ public class ApiConstants { public static final String JOB_STATUS = "jobstatus"; public static final String LASTNAME = "lastname"; public static final String LEVEL = "level"; - public static final String LIMIT_CPU_USE = "limitcpuuse"; + public static final String LIMIT_CPU_USE = "limitcpuuse"; public static final String LOCK = "lock"; public static final String LUN = "lun"; public static final String LBID = "lbruleid"; @@ -132,9 +132,9 @@ public class ApiConstants { public static final String PORTAL = "portal"; public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid"; public static final String PRIVATE_INTERFACE = "privateinterface"; - public static final String PRIVATE_IP = "privateip"; + public static final String PRIVATE_IP = "privateip"; public static final String PRIVATE_PORT = "privateport"; - public static final String PRIVATE_START_PORT = "privateport"; + public static final String PRIVATE_START_PORT = "privateport"; public static final String PRIVATE_END_PORT = "privateendport"; public static final String PRIVATE_ZONE = "privatezone"; public static final String PROTOCOL = "protocol"; @@ -142,7 +142,7 @@ public class ApiConstants { public static final String PUBLIC_IP_ID = "publicipid"; public static final String PUBLIC_IP = "publicip"; public static final String PUBLIC_PORT = "publicport"; - public static final String PUBLIC_START_PORT = "publicport"; + public static final String PUBLIC_START_PORT = "publicport"; public static final String PUBLIC_END_PORT = "publicendport"; public static final String PUBLIC_ZONE = "publiczone"; public static final String RECEIVED_BYTES = "receivedbytes"; @@ -166,7 +166,7 @@ public class ApiConstants { public static final String SNAPSHOT_ID = "snapshotid"; public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid"; public static final String SNAPSHOT_TYPE = "snapshottype"; - public static final String SOURCE_ZONE_ID = "sourcezoneid"; + public static final String SOURCE_ZONE_ID = "sourcezoneid"; public static final String START_DATE = "startdate"; public static final String START_IP = "startip"; public static final String START_PORT = "startport"; @@ -237,13 +237,13 @@ public class ApiConstants { public static final String PRIVATE_NETWORK_ID = "privatenetworkid"; public static final String ALLOCATION_STATE = "allocationstate"; public static final String MANAGED_STATE = "managedstate"; - public static final String STORAGE_ID="storageid"; + public static final String STORAGE_ID = "storageid"; public static final String PING_STORAGE_SERVER_IP = "pingstorageserverip"; public static final String PING_DIR = "pingdir"; public static final String TFTP_DIR = "tftpdir"; public static final String PING_CIFS_USERNAME = "pingcifsusername"; public static final String PING_CIFS_PASSWORD = "pingcifspassword"; - public static final String CHECKSUM="checksum"; + public static final String CHECKSUM = "checksum"; public static final String NETWORK_DEVICE_TYPE = "networkdevicetype"; public static final String NETWORK_DEVICE_PARAMETER_LIST = "networkdeviceparameterlist"; public static final String ZONE_TOKEN = "zonetoken"; @@ -259,8 +259,8 @@ public class ApiConstants { public static final String IP_NETWORK_LIST = "iptonetworklist"; public static final String PARAM_LIST = "param"; public static final String FOR_LOAD_BALANCING = "forloadbalancing"; - public static final String KEYBOARD="keyboard"; - public static final String OPEN_FIREWALL="openfirewall"; + public static final String KEYBOARD = "keyboard"; + public static final String OPEN_FIREWALL = "openfirewall"; public static final String TEMPLATE_TAG = "templatetag"; public static final String HYPERVISOR_VERSION = "hypervisorversion"; public static final String MAX_GUESTS_LIMIT = "maxguestslimit"; @@ -296,8 +296,8 @@ public class ApiConstants { public static final String SERVICE_LIST = "servicelist"; public static final String CAN_ENABLE_INDIVIDUAL_SERVICE = "canenableindividualservice"; public static final String SUPPORTED_SERVICES = "supportedservices"; - public static final String NSP_ID= "nspid"; - public static final String ACL_TYPE= "acltype"; + public static final String NSP_ID = "nspid"; + public static final String ACL_TYPE = "acltype"; public static final String SUBDOMAIN_ACCESS = "subdomainaccess"; public static final String LOAD_BALANCER_DEVICE_ID = "lbdeviceid"; public static final String LOAD_BALANCER_DEVICE_NAME = "lbdevicename"; @@ -386,6 +386,7 @@ public class ApiConstants { public static final String AUTOSCALE_VM_DESTROY_TIME = "destroyvmgraceperiod"; public static final String VMPROFILE_ID = "vmprofileid"; public static final String VMGROUP_ID = "vmgroupid"; + public static final String CS_URL = "csurl"; public static final String SCALEUP_POLICY_IDS = "scaleuppolicyids"; public static final String SCALEDOWN_POLICY_IDS = "scaledownpolicyids"; public static final String INTERVAL = "interval"; @@ -394,20 +395,20 @@ public class ApiConstants { public static final String CONDITION_ID = "conditionid"; public static final String CONDITION_IDS = "conditionids"; public static final String AUTOSCALE_USER_ID = "autoscaleuserid"; - + public enum HostDetails { all, capacity, events, stats, min; } - + public enum VMDetails { all, group, nics, stats, secgrp, tmpl, servoff, iso, volume, min; } - + public enum LDAPParams { hostname, port, usessl, queryfilter, searchbase, dn, passwd, truststore, truststorepass; - + @Override - public String toString(){ + public String toString() { return "ldap." + name(); } } diff --git a/api/src/com/cloud/api/commands/CreateAutoScaleVmProfileCmd.java b/api/src/com/cloud/api/commands/CreateAutoScaleVmProfileCmd.java index 1ef99b8c534..bb1ef6baf46 100644 --- a/api/src/com/cloud/api/commands/CreateAutoScaleVmProfileCmd.java +++ b/api/src/com/cloud/api/commands/CreateAutoScaleVmProfileCmd.java @@ -72,6 +72,9 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.AUTOSCALE_USER_ID, type = CommandType.LONG, description = "the ID of the user used to launch and destroy the VMs") private Long autoscaleUserId; + @Parameter(name = ApiConstants.CS_URL, type = CommandType.STRING, description = "the URL including port of the CloudStack Management Server example: http://server.cloud.com:8080") + private String csUrl; + private Map otherDeployParamMap; // /////////////////////////////////////////////////// @@ -117,8 +120,12 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd { return otherDeployParams; } + public String getCsUrl() { + return csUrl; + } + public Long getAutoscaleUserId() { - if(autoscaleUserId != null) { + if (autoscaleUserId != null) { return autoscaleUserId; } else { return UserContext.current().getCaller().getId(); @@ -130,11 +137,11 @@ public class CreateAutoScaleVmProfileCmd extends BaseAsyncCreateCmd { } public long getAccountId() { - if(accountId != null) { + if (accountId != null) { return accountId; } Account account = null; - if(autoscaleUserId != null) { + if (autoscaleUserId != null) { User user = _entityMgr.findById(User.class, autoscaleUserId); account = _entityMgr.findById(Account.class, user.getAccountId()); } else { diff --git a/api/src/com/cloud/network/as/AutoScaleVmProfile.java b/api/src/com/cloud/network/as/AutoScaleVmProfile.java index 02719ee2059..20cbdd8107e 100644 --- a/api/src/com/cloud/network/as/AutoScaleVmProfile.java +++ b/api/src/com/cloud/network/as/AutoScaleVmProfile.java @@ -35,4 +35,6 @@ public interface AutoScaleVmProfile extends ControlledEntity { public Integer getDestroyVmGraceperiod(); public long getAutoScaleUserId(); + + public String getCsUrl(); } diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index c0208c2352b..75be298e957 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -23,7 +23,7 @@ import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LoadBalancer; import com.cloud.utils.Pair; -public class LoadBalancingRule implements FirewallRule, LoadBalancer{ +public class LoadBalancingRule implements FirewallRule, LoadBalancer { private final LoadBalancer lb; private final List destinations; private final List stickinessPolicies; @@ -127,11 +127,13 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ return stickinessPolicies; } - public interface Destination { String getIpAddress(); + int getDestinationPortStart(); + int getDestinationPortEnd(); + boolean isRevoked(); } @@ -182,10 +184,12 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ public String getIpAddress() { return ip; } + @Override public int getDestinationPortStart() { return portStart; } + @Override public int getDestinationPortEnd() { return portEnd; @@ -243,17 +247,19 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ this.autoScaleVmGroup = autoScaleVmGroup; } - public static class LbCondition { private final Condition condition; private final Counter counter; + public LbCondition(Counter counter, Condition condition) { this.condition = condition; this.counter = counter; } + public Condition getCondition() { return condition; } + public Counter getCounter() { return counter; } @@ -263,14 +269,17 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ private final List conditions; private final AutoScalePolicy policy; private boolean revoked; + public LbAutoScalePolicy(AutoScalePolicy policy, List conditions) { this.policy = policy; this.conditions = conditions; } + public List getConditions() { return conditions; } + public AutoScalePolicy getPolicy() { return policy; } @@ -278,6 +287,7 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ public boolean isRevoked() { return revoked; } + public void setRevoked(boolean revoked) { this.revoked = revoked; } @@ -285,25 +295,23 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ public static class LbAutoScaleVmProfile { AutoScaleVmProfile profile; - private final String cloudStackApiUrl; private final String autoScaleUserApiKey; private final String autoScaleUserSecretKey; - public LbAutoScaleVmProfile(AutoScaleVmProfile profile, String cloudStackApiUrl, String autoScaleUserApiKey, String autoScaleUserSecretKey) { + public LbAutoScaleVmProfile(AutoScaleVmProfile profile, String autoScaleUserApiKey, String autoScaleUserSecretKey) { this.profile = profile; - this.cloudStackApiUrl = cloudStackApiUrl; this.autoScaleUserApiKey = autoScaleUserApiKey; this.autoScaleUserSecretKey = autoScaleUserSecretKey; } + public AutoScaleVmProfile getProfile() { return profile; } - public String getCloudStackApiUrl() { - return cloudStackApiUrl; - } + public String getAutoScaleUserApiKey() { return autoScaleUserApiKey; } + public String getAutoScaleUserSecretKey() { return autoScaleUserSecretKey; } @@ -332,112 +340,4 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ return profile; } } - //public static class LbCounter{ - //private String name; - //private String source; - //private String value; - // - //public LbCounter(String name, String source, String value) - //{ - // this.name = name; - // this.source = source; - // this.value = value; - //} - // - //public String getName() { - // return name; - //} - //public String getSource() { - // return source; - //} - //public String getValue() { - // return value; - //} - //} - // - //public static class LbCondition{ - //private long threshold; - //private String relationalOperator; - //private LbCounter counter; - //public LbCondition(int threshold, String relationalOperator, LbCounter counter) - //{ - // this.threshold = threshold; - // this.relationalOperator = relationalOperator; - // this.counter = counter; - //} - //public long getThreshold() { - // return threshold; - //} - //public String getRelationalOperator() { - // return relationalOperator; - //} - //public LbCounter getCounter() { - // return counter; - //} - //} - // - //public static class AutoScaleVmGroup { - //private int minMembers; - //private int maxMembers; - //private List scaleUpPolicies; - //private List scaleDownPolicies; - //private List profile; - //private boolean revoked; - // - //public boolean isRevoked() { - // return revoked; - //} - // - //public void setRevoked(boolean revoked) { - // this.revoked = revoked; - //} - //} - // - //public static class AutoScaleVmProfile { - //private Long zoneId; - //private long domainId; - //private long accountId; - //private Long serviceOfferingId; - //private Long templateId; - //private String otherDeployParams; - //private String snmpCommunity; - //private Integer snmpPort; - // - //} - // - //public static class AutoscalePolicy { - //private int interval; - // - //private int duration; - //private int quietTime; - //private String action; - //private List conditions; - // - //public AutoscalePolicy(int interval, int duration, int quietTime, String action, List conditions) { - // this.interval = interval; - // this.duration = duration; - // this.quietTime = quietTime; - // this.conditions = conditions; - //} - // - //public int getInterval() { - // return interval; - //} - // - //public int getDuration() { - // return duration; - //} - // - //public int getQuietTime() { - // return quietTime; - //} - // - //public String getAction() { - // return action; - //} - // - //public List getConditions() { - // return conditions; - //} - //} } diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 5586aace2ef..a840fac90ab 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -1,1137 +1,1101 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 -package com.cloud.api; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.net.UnknownHostException; -import java.security.SecureRandom; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.TimeZone; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.http.ConnectionClosedException; -import org.apache.http.HttpException; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.HttpServerConnection; -import org.apache.http.HttpStatus; -import org.apache.http.entity.BasicHttpEntity; -import org.apache.http.impl.DefaultHttpResponseFactory; -import org.apache.http.impl.DefaultHttpServerConnection; -import org.apache.http.impl.NoConnectionReuseStrategy; -import org.apache.http.impl.SocketHttpServerConnection; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.CoreConnectionPNames; -import org.apache.http.params.CoreProtocolPNames; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.BasicHttpProcessor; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.HttpRequestHandler; -import org.apache.http.protocol.HttpRequestHandlerRegistry; -import org.apache.http.protocol.HttpService; -import org.apache.http.protocol.ResponseConnControl; -import org.apache.http.protocol.ResponseContent; -import org.apache.http.protocol.ResponseDate; -import org.apache.http.protocol.ResponseServer; -import org.apache.log4j.Logger; - -import com.cloud.api.response.ApiResponseSerializer; -import com.cloud.api.response.ExceptionResponse; -import com.cloud.api.response.ListResponse; -import com.cloud.async.AsyncJob; -import com.cloud.async.AsyncJobManager; -import com.cloud.async.AsyncJobVO; -import com.cloud.cluster.StackMaid; -import com.cloud.configuration.Config; -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.CloudAuthenticationException; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.server.ManagementServer; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.DomainManager; -import com.cloud.user.User; -import com.cloud.user.UserAccount; -import com.cloud.user.UserContext; -import com.cloud.user.UserVO; -import com.cloud.utils.IdentityProxy; -import com.cloud.utils.Pair; -import com.cloud.utils.PropertiesUtil; -import com.cloud.utils.component.ComponentLocator; -import com.cloud.utils.component.PluggableService; -import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.encoding.Base64; -import com.cloud.utils.exception.CSExceptionErrorCode; -import com.cloud.uuididentity.dao.IdentityDao; - -public class ApiServer implements HttpRequestHandler { - private static final Logger s_logger = Logger.getLogger(ApiServer.class.getName()); - private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName()); - - public static final short ADMIN_COMMAND = 1; - public static final short DOMAIN_ADMIN_COMMAND = 4; - public static final short RESOURCE_DOMAIN_ADMIN_COMMAND = 2; - public static final short USER_COMMAND = 8; - public static boolean encodeApiResponse = false; - public static String jsonContentType = "text/javascript"; - private Properties _apiCommands = null; - private ApiDispatcher _dispatcher; - private AccountManager _accountMgr = null; - private DomainManager _domainMgr = null; - private AsyncJobManager _asyncMgr = null; - private Account _systemAccount = null; - private User _systemUser = null; - private String serverIpAddress = null; - private String serverPort = null; - - private static int _workerCount = 0; - - private static ApiServer s_instance = null; - private static List s_userCommands = null; - private static List s_resellerCommands = null; // AKA domain-admin - private static List s_adminCommands = null; - private static List s_resourceDomainAdminCommands = null; - private static List s_allCommands = null; - private static List s_pluggableServiceCommands = null; - private static final DateFormat _dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); - - private static ExecutorService _executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(), new NamedThreadFactory("ApiServer")); - - static { - s_userCommands = new ArrayList(); - s_resellerCommands = new ArrayList(); - s_adminCommands = new ArrayList(); - s_resourceDomainAdminCommands = new ArrayList(); - s_allCommands = new ArrayList(); - s_pluggableServiceCommands = new ArrayList(); - } - - private ApiServer() { - } - - public static void initApiServer(String[] apiConfig) { - if (s_instance == null) { - s_instance = new ApiServer(); - s_instance.init(apiConfig); - } - } - - public static ApiServer getInstance() { - // initApiServer(); - return s_instance; - } - - public Properties get_apiCommands() { - return _apiCommands; - } - - public String getServerIpAddress() { - return serverIpAddress; - } - - public String getServerPort() { - return serverPort; - } - - public static boolean isPluggableServiceCommand(String cmdClassName) { - if (s_pluggableServiceCommands != null) { - if (s_pluggableServiceCommands.contains(cmdClassName)) { - return true; - } - } - return false; - } - - private String[] getPluggableServicesApiConfigs() { - List pluggableServicesApiConfigs = new ArrayList(); - - ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name); - List services = locator.getAllPluggableServices(); - for (PluggableService service : services) { - pluggableServicesApiConfigs.add(service.getPropertiesFile()); - } - return pluggableServicesApiConfigs.toArray(new String[0]); - } - - private void processConfigFiles(String[] apiConfig, boolean pluggableServicesConfig) { - try { - if (_apiCommands == null) { - _apiCommands = new Properties(); - } - Properties preProcessedCommands = new Properties(); - if (apiConfig != null) { - for (String configFile : apiConfig) { - File commandsFile = PropertiesUtil.findConfigFile(configFile); - if (commandsFile != null) { - try { - preProcessedCommands.load(new FileInputStream(commandsFile)); - } catch (FileNotFoundException fnfex) { - // in case of a file within a jar in classpath, try to open stream using url - InputStream stream = PropertiesUtil.openStreamFromURL(configFile); - if (stream != null) { - preProcessedCommands.load(stream); - } else { - s_logger.error("Unable to find properites file", fnfex); - } - } - } - } - for (Object key : preProcessedCommands.keySet()) { - String preProcessedCommand = preProcessedCommands.getProperty((String) key); - String[] commandParts = preProcessedCommand.split(";"); - _apiCommands.put(key, commandParts[0]); - - if (pluggableServicesConfig) { - s_pluggableServiceCommands.add(commandParts[0]); - } - - if (commandParts.length > 1) { - try { - short cmdPermissions = Short.parseShort(commandParts[1]); - if ((cmdPermissions & ADMIN_COMMAND) != 0) { - s_adminCommands.add((String) key); - } - if ((cmdPermissions & RESOURCE_DOMAIN_ADMIN_COMMAND) != 0) { - s_resourceDomainAdminCommands.add((String) key); - } - if ((cmdPermissions & DOMAIN_ADMIN_COMMAND) != 0) { - s_resellerCommands.add((String) key); - } - if ((cmdPermissions & USER_COMMAND) != 0) { - s_userCommands.add((String) key); - } - } catch (NumberFormatException nfe) { - s_logger.info("Malformed command.properties permissions value, key = " + key + ", value = " + preProcessedCommand); - } - } - } - - s_allCommands.addAll(s_adminCommands); - s_allCommands.addAll(s_resourceDomainAdminCommands); - s_allCommands.addAll(s_userCommands); - s_allCommands.addAll(s_resellerCommands); - } - } catch (FileNotFoundException fnfex) { - s_logger.error("Unable to find properites file", fnfex); - } catch (IOException ioex) { - s_logger.error("Exception loading properties file", ioex); - } - } - - public void init(String[] apiConfig) { - BaseCmd.setComponents(new ApiResponseHelper()); - BaseListCmd.configure(); - processConfigFiles(apiConfig, false); - - // get commands for all pluggable services - String[] pluggableServicesApiConfigs = getPluggableServicesApiConfigs(); - processConfigFiles(pluggableServicesApiConfigs, true); - - ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name); - _accountMgr = locator.getManager(AccountManager.class); - _asyncMgr = locator.getManager(AsyncJobManager.class); - _systemAccount = _accountMgr.getSystemAccount(); - _systemUser = _accountMgr.getSystemUser(); - _dispatcher = ApiDispatcher.getInstance(); - _domainMgr = locator.getManager(DomainManager.class); - - Integer apiPort = null; // api port, null by default - ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); - SearchCriteria sc = configDao.createSearchCriteria(); - sc.addAnd("name", SearchCriteria.Op.EQ, "integration.api.port"); - List values = configDao.search(sc, null); - if ((values != null) && (values.size() > 0)) { - ConfigurationVO apiPortConfig = values.get(0); - if (apiPortConfig.getValue() != null) { - apiPort = Integer.parseInt(apiPortConfig.getValue()); - } - } - - encodeApiResponse = Boolean.valueOf(configDao.getValue(Config.EncodeApiResponse.key())); - - String jsonType = configDao.getValue(Config.JavaScriptDefaultContentType.key()); - if (jsonType != null) { - jsonContentType = jsonType; - } - - if (apiPort != null) { - ListenerThread listenerThread = new ListenerThread(this, apiPort); - - serverIpAddress = listenerThread.getServerIpAddress(); - serverPort = listenerThread.getServerPort(); - listenerThread.start(); - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { - // get some information for the access log... - StringBuffer sb = new StringBuffer(); - HttpServerConnection connObj = (HttpServerConnection) context.getAttribute("http.connection"); - if (connObj instanceof SocketHttpServerConnection) { - InetAddress remoteAddr = ((SocketHttpServerConnection) connObj).getRemoteAddress(); - sb.append(remoteAddr.toString() + " -- "); - } - sb.append(request.getRequestLine()); - - try { - String uri = request.getRequestLine().getUri(); - int requestParamsStartIndex = uri.indexOf('?'); - if (requestParamsStartIndex >= 0) { - uri = uri.substring(requestParamsStartIndex + 1); - } - - String[] paramArray = uri.split("&"); - if (paramArray.length < 1) { - s_logger.info("no parameters received for request: " + uri + ", aborting..."); - return; - } - - Map parameterMap = new HashMap(); - - String responseType = BaseCmd.RESPONSE_TYPE_XML; - for (String paramEntry : paramArray) { - String[] paramValue = paramEntry.split("="); - if (paramValue.length != 2) { - s_logger.info("malformed parameter: " + paramEntry + ", skipping"); - continue; - } - if ("response".equalsIgnoreCase(paramValue[0])) { - responseType = paramValue[1]; - } else { - // according to the servlet spec, the parameter map should be in the form (name=String, - // value=String[]), so - // parameter values will be stored in an array - parameterMap.put(/* name */paramValue[0], /* value */new String[] { paramValue[1] }); - } - } - try { - // always trust commands from API port, user context will always be UID_SYSTEM/ACCOUNT_ID_SYSTEM - UserContext.registerContext(_systemUser.getId(), _systemAccount, null, true); - sb.insert(0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); - String responseText = handleRequest(parameterMap, true, responseType, sb); - sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); - - writeResponse(response, responseText, HttpStatus.SC_OK, responseType, null); - } catch (ServerApiException se) { - String responseText = getSerializedApiError(se.getErrorCode(), se.getDescription(), parameterMap, responseType, se); - writeResponse(response, responseText, se.getErrorCode(), responseType, se.getDescription()); - sb.append(" " + se.getErrorCode() + " " + se.getDescription()); - } catch (RuntimeException e) { - // log runtime exception like NullPointerException to help identify the source easier - s_logger.error("Unhandled exception, ", e); - throw e; - } - } finally { - s_accessLogger.info(sb.toString()); - UserContext.unregisterContext(); - } - } - - @SuppressWarnings("rawtypes") - public String handleRequest(Map params, boolean decode, String responseType, StringBuffer auditTrailSb) throws ServerApiException { - String response = null; - String[] command = null; - try { - command = (String[]) params.get("command"); - if (command == null) { - s_logger.error("invalid request, no command sent"); - if (s_logger.isTraceEnabled()) { - s_logger.trace("dumping request parameters"); - for (Object key : params.keySet()) { - String keyStr = (String) key; - String[] value = (String[]) params.get(key); - s_logger.trace(" key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0])); - } - } - throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent"); - } else { - Map paramMap = new HashMap(); - Set keys = params.keySet(); - Iterator keysIter = keys.iterator(); - while (keysIter.hasNext()) { - String key = (String) keysIter.next(); - if ("command".equalsIgnoreCase(key)) { - continue; - } - String[] value = (String[]) params.get(key); - - String decodedValue = null; - if (decode) { - try { - decodedValue = URLDecoder.decode(value[0], "UTF-8"); - } catch (UnsupportedEncodingException usex) { - s_logger.warn(key + " could not be decoded, value = " + value[0]); - throw new ServerApiException(BaseCmd.PARAM_ERROR, key + " could not be decoded, received value " + value[0]); - } catch (IllegalArgumentException iae) { - s_logger.warn(key + " could not be decoded, value = " + value[0]); - throw new ServerApiException(BaseCmd.PARAM_ERROR, key + " could not be decoded, received value " + value[0] + " which contains illegal characters eg.%"); - } - } else { - decodedValue = value[0]; - } - paramMap.put(key, decodedValue); - } - String cmdClassName = _apiCommands.getProperty(command[0]); - if (cmdClassName != null) { - Class cmdClass = Class.forName(cmdClassName); - BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance(); - cmdObj.setFullUrlParams(paramMap); - cmdObj.setResponseType(responseType); - // This is where the command is either serialized, or directly dispatched - response = queueCommand(cmdObj, paramMap); - buildAuditTrail(auditTrailSb, command[0], response); - } else { - if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) { - String errorString = "Unknown API command: " + ((command == null) ? "null" : command[0]); - s_logger.warn(errorString); - auditTrailSb.append(" " + errorString); - throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, errorString); - } - } - } - } catch (Exception ex) { - if (ex instanceof InvalidParameterValueException) { - InvalidParameterValueException ref = (InvalidParameterValueException)ex; - ServerApiException e = new ServerApiException(BaseCmd.PARAM_ERROR, ex.getMessage()); - // copy over the IdentityProxy information as well and throw the serverapiexception. - ArrayList idList = ref.getIdProxyList(); - if (idList != null) { - // Iterate through entire arraylist and copy over each proxy id. - for (int i = 0 ; i < idList.size(); i++) { - IdentityProxy obj = idList.get(i); - e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName()); - } - } - // Also copy over the cserror code and the function/layer in which it was thrown. - e.setCSErrorCode(ref.getCSErrorCode()); - throw e; - } else if (ex instanceof PermissionDeniedException) { - PermissionDeniedException ref = (PermissionDeniedException)ex; - ServerApiException e = new ServerApiException(BaseCmd.ACCOUNT_ERROR, ex.getMessage()); - // copy over the IdentityProxy information as well and throw the serverapiexception. - ArrayList idList = ref.getIdProxyList(); - if (idList != null) { - // Iterate through entire arraylist and copy over each proxy id. - for (int i = 0 ; i < idList.size(); i++) { - IdentityProxy obj = idList.get(i); - e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName()); - } - } - e.setCSErrorCode(ref.getCSErrorCode()); - throw e; - } else if (ex instanceof ServerApiException) { - throw (ServerApiException) ex; - } else { - s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command[0]), ex); - ServerApiException e = new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal server error, unable to execute request."); - e.setCSErrorCode(CSExceptionErrorCode.getCSErrCode("ServerApiException")); - throw e; - } - } - return response; - } - - private String queueCommand(BaseCmd cmdObj, Map params) { - UserContext ctx = UserContext.current(); - Long callerUserId = ctx.getCallerUserId(); - Account caller = ctx.getCaller(); - if (cmdObj instanceof BaseAsyncCmd) { - Long objectId = null; - String objectEntityTable = null; - if (cmdObj instanceof BaseAsyncCreateCmd) { - BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd) cmdObj; - _dispatcher.dispatchCreateCmd(createCmd, params); - objectId = createCmd.getEntityId(); - objectEntityTable = createCmd.getEntityTable(); - params.put("id", objectId.toString()); - } else { - ApiDispatcher.setupParameters(cmdObj, params); - ApiDispatcher.plugService(cmdObj); - } - - BaseAsyncCmd asyncCmd = (BaseAsyncCmd) cmdObj; - - if (callerUserId != null) { - params.put("ctxUserId", callerUserId.toString()); - } - if (caller != null) { - params.put("ctxAccountId", String.valueOf(caller.getId())); - } - - long startEventId = ctx.getStartEventId(); - asyncCmd.setStartEventId(startEventId); - - // save the scheduled event - Long eventId = EventUtils.saveScheduledEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, - asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), asyncCmd.getEventDescription(), - startEventId); - if (startEventId == 0) { - // There was no create event before, set current event id as start eventId - startEventId = eventId; - } - - params.put("ctxStartEventId", String.valueOf(startEventId)); - - ctx.setAccountId(asyncCmd.getEntityOwnerId()); - - AsyncJobVO job = new AsyncJobVO(); - job.setInstanceId((objectId == null) ? asyncCmd.getInstanceId() : objectId); - job.setInstanceType(asyncCmd.getInstanceType()); - job.setUserId(callerUserId); - job.setAccountId(caller.getId()); - - job.setCmd(cmdObj.getClass().getName()); - job.setCmdInfo(ApiGsonHelper.getBuilder().create().toJson(params)); - - long jobId = _asyncMgr.submitAsyncJob(job); - - if (jobId == 0L) { - String errorMsg = "Unable to schedule async job for command " + job.getCmd(); - s_logger.warn(errorMsg); - throw new ServerApiException(BaseCmd.INTERNAL_ERROR, errorMsg); - } - - if (objectId != null) { - SerializationContext.current().setUuidTranslation(true); - return ((BaseAsyncCreateCmd) asyncCmd).getResponse(jobId, objectId, objectEntityTable); - } - - SerializationContext.current().setUuidTranslation(true); - return ApiResponseSerializer.toSerializedString(asyncCmd.getResponse(jobId), asyncCmd.getResponseType()); - } else { - _dispatcher.dispatch(cmdObj, params); - - // if the command is of the listXXXCommand, we will need to also return the - // the job id and status if possible - if (cmdObj instanceof BaseListCmd) { - buildAsyncListResponse((BaseListCmd) cmdObj, caller); - } - - SerializationContext.current().setUuidTranslation(true); - return ApiResponseSerializer.toSerializedString((ResponseObject) cmdObj.getResponseObject(), cmdObj.getResponseType()); - } - } - - private void buildAsyncListResponse(BaseListCmd command, Account account) { - List responses = ((ListResponse) command.getResponseObject()).getResponses(); - if (responses != null && responses.size() > 0) { - List jobs = null; - - // list all jobs for ROOT admin - if (account.getType() == Account.ACCOUNT_TYPE_ADMIN) { - jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType(), null); - } else { - jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType(), account.getId()); - } - - if (jobs.size() == 0) { - return; - } - - // Using maps might possibly be more efficient if the set is large enough but for now, we'll just do a - // comparison of two lists. Either way, there shouldn't be too many async jobs active for the account. - for (AsyncJob job : jobs) { - if (job.getInstanceId() == null) { - continue; - } - for (ResponseObject response : responses) { - if (response.getObjectId() != null && job.getInstanceId().longValue() == response.getObjectId().longValue()) { - response.setJobId(job.getId()); - response.setJobStatus(job.getStatus()); - } - } - } - } - } - - private void buildAuditTrail(StringBuffer auditTrailSb, String command, String result) { - if (result == null) { - return; - } - auditTrailSb.append(" " + HttpServletResponse.SC_OK + " "); - auditTrailSb.append(result); - /* - * if (command.equals("queryAsyncJobResult")){ //For this command we need to also log job status and job - * resultcode for - * (Pair pair : resultValues){ String key = pair.first(); if (key.equals("jobstatus")){ - * auditTrailSb.append(" "); auditTrailSb.append(key); auditTrailSb.append("="); - * auditTrailSb.append(pair.second()); - * }else if (key.equals("jobresultcode")){ auditTrailSb.append(" "); auditTrailSb.append(key); - * auditTrailSb.append("="); - * auditTrailSb.append(pair.second()); } } }else { for (Pair pair : resultValues){ if - * (pair.first().equals("jobid")){ // Its an async job so report the jobid auditTrailSb.append(" "); - * auditTrailSb.append(pair.first()); auditTrailSb.append("="); auditTrailSb.append(pair.second()); } } } - */ - } - - private static boolean isCommandAvailable(String commandName) { - boolean isCommandAvailable = false; - isCommandAvailable = s_allCommands.contains(commandName); - return isCommandAvailable; - } - - public boolean verifyRequest(Map requestParameters, Long userId) throws ServerApiException { - try { - String apiKey = null; - String secretKey = null; - String signature = null; - String unsignedRequest = null; - - String[] command = (String[]) requestParameters.get("command"); - if (command == null) { - s_logger.info("missing command, ignoring request..."); - return false; - } - - String commandName = command[0]; - - // if userId not null, that mean that user is logged in - if (userId != null) { - Long accountId = ApiDBUtils.findUserById(userId).getAccountId(); - Account userAccount = _accountMgr.getAccount(accountId); - short accountType = userAccount.getType(); - - if (!isCommandAvailable(accountType, commandName)) { - s_logger.warn("The given command:" + commandName + " does not exist"); - throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist"); - } - return true; - } else { - // check against every available command to see if the command exists or not - if (!isCommandAvailable(commandName) && !commandName.equals("login") && !commandName.equals("logout")) { - s_logger.warn("The given command:" + commandName + " does not exist"); - throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist"); - } - } - - // - build a request string with sorted params, make sure it's all lowercase - // - sign the request, verify the signature is the same - List parameterNames = new ArrayList(); - - for (Object paramNameObj : requestParameters.keySet()) { - parameterNames.add((String) paramNameObj); // put the name in a list that we'll sort later - } - - Collections.sort(parameterNames); - - String signatureVersion = null; - String expires = null; - - for (String paramName : parameterNames) { - // parameters come as name/value pairs in the form String/String[] - String paramValue = ((String[]) requestParameters.get(paramName))[0]; - - if ("signature".equalsIgnoreCase(paramName)) { - signature = paramValue; - } else { - if ("apikey".equalsIgnoreCase(paramName)) { - apiKey = paramValue; - } - else if ("signatureversion".equalsIgnoreCase(paramName)) { - signatureVersion = paramValue; - } else if ("expires".equalsIgnoreCase(paramName)) { - expires = paramValue; - } - - if (unsignedRequest == null) { - unsignedRequest = paramName + "=" + URLEncoder.encode(paramValue, "UTF-8").replaceAll("\\+", "%20"); - } else { - unsignedRequest = unsignedRequest + "&" + paramName + "=" + URLEncoder.encode(paramValue, "UTF-8").replaceAll("\\+", "%20"); - } - } - } - - // if api/secret key are passed to the parameters - if ((signature == null) || (apiKey == null)) { - if (s_logger.isDebugEnabled()) { - s_logger.info("expired session, missing signature, or missing apiKey -- ignoring request...sig: " + signature + ", apiKey: " + apiKey); - } - return false; // no signature, bad request - } - - Date expiresTS = null; - if ("3".equals(signatureVersion)) { - // New signature authentication. Check for expire parameter and its validity - if (expires == null) { - s_logger.info("missing Expires parameter -- ignoring request...sig: " + signature + ", apiKey: " + apiKey); - return false; - } - synchronized (_dateFormat) { - try { - expiresTS = _dateFormat.parse(expires); - } catch (ParseException pe) { - s_logger.info("Incorrect date format for Expires parameter", pe); - return false; - } - } - Date now = new Date(System.currentTimeMillis()); - if (expiresTS.before(now)) { - s_logger.info("Request expired -- ignoring ...sig: " + signature + ", apiKey: " + apiKey); - return false; - } - } - - Transaction txn = Transaction.open(Transaction.CLOUD_DB); - txn.close(); - User user = null; - // verify there is a user with this api key - Pair userAcctPair = _accountMgr.findUserByApiKey(apiKey); - if (userAcctPair == null) { - s_logger.info("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey); - return false; - } - - user = userAcctPair.first(); - Account account = userAcctPair.second(); - - if (user.getState() != Account.State.enabled || !account.getState().equals(Account.State.enabled)) { - s_logger.info("disabled or locked user accessing the api, userid = " + user.getId() + "; name = " + user.getUsername() + "; state: " + user.getState() + "; accountState: " - + account.getState()); - return false; - } - - UserContext.updateContext(user.getId(), account, null); - - if (!isCommandAvailable(account.getType(), commandName)) { - s_logger.warn("The given command:" + commandName + " does not exist"); - throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command:" + commandName + " does not exist"); - } - - // verify secret key exists - secretKey = user.getSecretKey(); - if (secretKey == null) { - s_logger.info("User does not have a secret key associated with the account -- ignoring request, username: " + user.getUsername()); - return false; - } - - unsignedRequest = unsignedRequest.toLowerCase(); - - Mac mac = Mac.getInstance("HmacSHA1"); - SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"); - mac.init(keySpec); - mac.update(unsignedRequest.getBytes()); - byte[] encryptedBytes = mac.doFinal(); - String computedSignature = Base64.encodeBytes(encryptedBytes); - boolean equalSig = signature.equals(computedSignature); - if (!equalSig) { - s_logger.info("User signature: " + signature + " is not equaled to computed signature: " + computedSignature); - } - return equalSig; - } catch (Exception ex) { - if (ex instanceof ServerApiException && ((ServerApiException) ex).getErrorCode() == BaseCmd.UNSUPPORTED_ACTION_ERROR) { - throw (ServerApiException) ex; - } - s_logger.error("unable to verifty request signature", ex); - } - return false; - } - - public Long fetchDomainId(String domainUUID){ - ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name); - IdentityDao identityDao = locator.getDao(IdentityDao.class); - try{ - Long domainId = identityDao.getIdentityId("domain", domainUUID); - return domainId; - }catch(InvalidParameterValueException ex){ - return null; - } - } - - public void loginUser(HttpSession session, String username, String password, Long domainId, String domainPath, String loginIpAddress ,Map requestParameters) throws CloudAuthenticationException { - // We will always use domainId first. If that does not exist, we will use domain name. If THAT doesn't exist - // we will default to ROOT - if (domainId == null) { - if (domainPath == null || domainPath.trim().length() == 0) { - domainId = DomainVO.ROOT_DOMAIN; - } else { - Domain domainObj = _domainMgr.findDomainByPath(domainPath); - if (domainObj != null) { - domainId = domainObj.getId(); - } else { // if an unknown path is passed in, fail the login call - throw new CloudAuthenticationException("Unable to find the domain from the path " + domainPath); - } - } - } - - UserAccount userAcct = _accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); - if (userAcct != null) { - String timezone = userAcct.getTimezone(); - float offsetInHrs = 0f; - if (timezone != null) { - TimeZone t = TimeZone.getTimeZone(timezone); - s_logger.info("Current user logged in under " + timezone + " timezone"); - - java.util.Date date = new java.util.Date(); - long longDate = date.getTime(); - float offsetInMs = (t.getOffset(longDate)); - offsetInHrs = offsetInMs / (1000 * 60 * 60); - s_logger.info("Timezone offset from UTC is: " + offsetInHrs); - } - - Account account = _accountMgr.getAccount(userAcct.getAccountId()); - - // set the userId and account object for everyone - session.setAttribute("userid", userAcct.getId()); - UserVO user = (UserVO) _accountMgr.getActiveUser(userAcct.getId()); - if(user.getUuid() != null){ - session.setAttribute("user_UUID", user.getUuid()); - } - - session.setAttribute("username", userAcct.getUsername()); - session.setAttribute("firstname", userAcct.getFirstname()); - session.setAttribute("lastname", userAcct.getLastname()); - session.setAttribute("accountobj", account); - session.setAttribute("account", account.getAccountName()); - - session.setAttribute("domainid", account.getDomainId()); - DomainVO domain = (DomainVO) _domainMgr.getDomain(account.getDomainId()); - if(domain.getUuid() != null){ - session.setAttribute("domain_UUID", domain.getUuid()); - } - - session.setAttribute("type", Short.valueOf(account.getType()).toString()); - session.setAttribute("registrationtoken", userAcct.getRegistrationToken()); - session.setAttribute("registered", new Boolean(userAcct.isRegistered()).toString()); - - if (timezone != null) { - session.setAttribute("timezone", timezone); - session.setAttribute("timezoneoffset", Float.valueOf(offsetInHrs).toString()); - } - - // (bug 5483) generate a session key that the user must submit on every request to prevent CSRF, add that - // to the login response so that session-based authenticators know to send the key back - SecureRandom sesssionKeyRandom = new SecureRandom(); - byte sessionKeyBytes[] = new byte[20]; - sesssionKeyRandom.nextBytes(sessionKeyBytes); - String sessionKey = Base64.encodeBytes(sessionKeyBytes); - session.setAttribute("sessionkey", sessionKey); - - return; - } - throw new CloudAuthenticationException("Failed to authenticate user " + username + " in domain " + domainId + "; please provide valid credentials"); - } - - public void logoutUser(long userId) { - _accountMgr.logoutUser(Long.valueOf(userId)); - return; - } - - public boolean verifyUser(Long userId) { - User user = _accountMgr.getUserIncludingRemoved(userId); - Account account = null; - if (user != null) { - account = _accountMgr.getAccount(user.getAccountId()); - } - - if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled) || (account == null) || !account.getState().equals(Account.State.enabled)) { - s_logger.warn("Deleted/Disabled/Locked user with id=" + userId + " attempting to access public API"); - return false; - } - return true; - } - - public static boolean isCommandAvailable(short accountType, String commandName) { - boolean isCommandAvailable = false; - switch (accountType) { - case Account.ACCOUNT_TYPE_ADMIN: - isCommandAvailable = s_adminCommands.contains(commandName); - break; - case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: - isCommandAvailable = s_resellerCommands.contains(commandName); - break; - case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: - isCommandAvailable = s_resourceDomainAdminCommands.contains(commandName); - break; - case Account.ACCOUNT_TYPE_NORMAL: - isCommandAvailable = s_userCommands.contains(commandName); - break; - } - return isCommandAvailable; - } - - // FIXME: rather than isError, we might was to pass in the status code to give more flexibility - private void writeResponse(HttpResponse resp, final String responseText, final int statusCode, String responseType, String reasonPhrase) { - try { - resp.setStatusCode(statusCode); - resp.setReasonPhrase(reasonPhrase); - - BasicHttpEntity body = new BasicHttpEntity(); - if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { - // JSON response - body.setContentType(jsonContentType); - if (responseText == null) { - body.setContent(new ByteArrayInputStream("{ \"error\" : { \"description\" : \"Internal Server Error\" } }".getBytes("UTF-8"))); - } - } else { - body.setContentType("text/xml"); - if (responseText == null) { - body.setContent(new ByteArrayInputStream("Internal Server Error".getBytes("UTF-8"))); - } - } - - if (responseText != null) { - body.setContent(new ByteArrayInputStream(responseText.getBytes("UTF-8"))); - } - resp.setEntity(body); - } catch (Exception ex) { - s_logger.error("error!", ex); - } - } - - // FIXME: the following two threads are copied from - // http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore/src/examples/org/apache/http/examples/ElementalHttpServer.java - // we have to cite a license if we are using this code directly, so we need to add the appropriate citation or - // modify the - // code to be very specific to our needs - static class ListenerThread extends Thread { - private HttpService _httpService = null; - private ServerSocket _serverSocket = null; - private HttpParams _params = null; - - public ListenerThread(ApiServer requestHandler, int port) { - try { - _serverSocket = new ServerSocket(port); - } catch (IOException ioex) { - s_logger.error("error initializing api server", ioex); - return; - } - - _params = new BasicHttpParams(); - _params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 30000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) - .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) - .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); - - // Set up the HTTP protocol processor - BasicHttpProcessor httpproc = new BasicHttpProcessor(); - httpproc.addInterceptor(new ResponseDate()); - httpproc.addInterceptor(new ResponseServer()); - httpproc.addInterceptor(new ResponseContent()); - httpproc.addInterceptor(new ResponseConnControl()); - - // Set up request handlers - HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); - reqistry.register("*", requestHandler); - - // Set up the HTTP service - _httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory()); - _httpService.setParams(_params); - _httpService.setHandlerResolver(reqistry); - } - - public String getServerIpAddress() { - String hostName; - InetAddress addrs[] = null; - try { - hostName = InetAddress.getLocalHost().getHostName(); - addrs = InetAddress.getAllByName(hostName); - } catch (UnknownHostException e) { - e.printStackTrace(); - } - String myIp = "UNKNOWN"; - for (InetAddress addr : addrs) { - if (!addr.isLoopbackAddress() && addr.isSiteLocalAddress()) { - myIp = addr.getHostAddress(); - break; - } - } - return myIp; - } - - public String getServerPort() { - return _serverSocket.getLocalPort() + ""; - } - - @Override - public void run() { - s_logger.info("ApiServer listening on port " + _serverSocket.getLocalPort()); - while (!Thread.interrupted()) { - try { - // Set up HTTP connection - Socket socket = _serverSocket.accept(); - DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); - conn.bind(socket, _params); - - // Execute a new worker task to handle the request - _executor.execute(new WorkerTask(_httpService, conn, _workerCount++)); - } catch (InterruptedIOException ex) { - break; - } catch (IOException e) { - s_logger.error("I/O error initializing connection thread", e); - break; - } - } - } - } - - static class WorkerTask implements Runnable { - private final HttpService _httpService; - private final HttpServerConnection _conn; - - public WorkerTask(final HttpService httpService, final HttpServerConnection conn, final int count) { - _httpService = httpService; - _conn = conn; - } - - @Override - public void run() { - HttpContext context = new BasicHttpContext(null); - try { - while (!Thread.interrupted() && _conn.isOpen()) { - try { - _httpService.handleRequest(_conn, context); - _conn.close(); - } finally { - StackMaid.current().exitCleanup(); - } - } - } catch (ConnectionClosedException ex) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("ApiServer: Client closed connection"); - } - } catch (IOException ex) { - if (s_logger.isTraceEnabled()) { - s_logger.trace("ApiServer: IOException - " + ex); - } - } catch (HttpException ex) { - s_logger.warn("ApiServer: Unrecoverable HTTP protocol violation" + ex); - } finally { - try { - _conn.shutdown(); - } catch (IOException ignore) { - } - } - } - } - - public String getSerializedApiError(int errorCode, String errorText, Map apiCommandParams, String responseType, Exception ex) { - String responseName = null; - String cmdClassName = null; - - String responseText = null; - - try { - if (errorCode == BaseCmd.UNSUPPORTED_ACTION_ERROR || apiCommandParams == null || apiCommandParams.isEmpty()) { - responseName = "errorresponse"; - } else { - Object cmdObj = apiCommandParams.get("command"); - // cmd name can be null when "command" parameter is missing in the request - if (cmdObj != null) { - String cmdName = ((String[]) cmdObj)[0]; - cmdClassName = _apiCommands.getProperty(cmdName); - if (cmdClassName != null) { - Class claz = Class.forName(cmdClassName); - responseName = ((BaseCmd) claz.newInstance()).getCommandName(); - } else { - responseName = "errorresponse"; - } - } - } - ExceptionResponse apiResponse = new ExceptionResponse(); - apiResponse.setErrorCode(errorCode); - apiResponse.setErrorText(errorText); - apiResponse.setResponseName(responseName); - // Also copy over the IdentityProxy object List into this new apiResponse, from - // the exception caught. When invoked from handle(), the exception here can - // be either ServerApiException, PermissionDeniedException or InvalidParameterValue - // Exception. When invoked from ApiServlet's processRequest(), this can be - // a standard exception like NumberFormatException. We'll leave the standard ones alone. - if (ex != null) { - if (ex instanceof ServerApiException || ex instanceof PermissionDeniedException - || ex instanceof InvalidParameterValueException) { - // Cast the exception appropriately and retrieve the IdentityProxy - if (ex instanceof ServerApiException) { - ServerApiException ref = (ServerApiException) ex; - ArrayList idList = ref.getIdProxyList(); - if (idList != null) { - for (int i=0; i < idList.size(); i++) { - IdentityProxy id = idList.get(i); - apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName()); - } - } - // Also copy over the cserror code and the function/layer in which it was thrown. - apiResponse.setCSErrorCode(ref.getCSErrorCode()); - } else if (ex instanceof PermissionDeniedException) { - PermissionDeniedException ref = (PermissionDeniedException) ex; - ArrayList idList = ref.getIdProxyList(); - if (idList != null) { - for (int i=0; i < idList.size(); i++) { - IdentityProxy id = idList.get(i); - apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName()); - } - } - // Also copy over the cserror code and the function/layer in which it was thrown. - apiResponse.setCSErrorCode(ref.getCSErrorCode()); - } else if (ex instanceof InvalidParameterValueException) { - InvalidParameterValueException ref = (InvalidParameterValueException) ex; - ArrayList idList = ref.getIdProxyList(); - if (idList != null) { - for (int i=0; i < idList.size(); i++) { - IdentityProxy id = idList.get(i); - apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName()); - } - } - // Also copy over the cserror code and the function/layer in which it was thrown. - apiResponse.setCSErrorCode(ref.getCSErrorCode()); - } - } - } - SerializationContext.current().setUuidTranslation(true); - responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType); - - } catch (Exception e) { - s_logger.error("Exception responding to http request", e); - } - return responseText; - } -} +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.api; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.security.SecureRandom; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TimeZone; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.http.ConnectionClosedException; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.HttpServerConnection; +import org.apache.http.HttpStatus; +import org.apache.http.entity.BasicHttpEntity; +import org.apache.http.impl.DefaultHttpResponseFactory; +import org.apache.http.impl.DefaultHttpServerConnection; +import org.apache.http.impl.NoConnectionReuseStrategy; +import org.apache.http.impl.SocketHttpServerConnection; +import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.CoreProtocolPNames; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.BasicHttpProcessor; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.http.protocol.HttpRequestHandlerRegistry; +import org.apache.http.protocol.HttpService; +import org.apache.http.protocol.ResponseConnControl; +import org.apache.http.protocol.ResponseContent; +import org.apache.http.protocol.ResponseDate; +import org.apache.http.protocol.ResponseServer; +import org.apache.log4j.Logger; + +import com.cloud.api.response.ApiResponseSerializer; +import com.cloud.api.response.ExceptionResponse; +import com.cloud.api.response.ListResponse; +import com.cloud.async.AsyncJob; +import com.cloud.async.AsyncJobManager; +import com.cloud.async.AsyncJobVO; +import com.cloud.cluster.StackMaid; +import com.cloud.configuration.Config; +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.CloudAuthenticationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.server.ManagementServer; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.DomainManager; +import com.cloud.user.User; +import com.cloud.user.UserAccount; +import com.cloud.user.UserContext; +import com.cloud.user.UserVO; +import com.cloud.utils.IdentityProxy; +import com.cloud.utils.Pair; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.component.PluggableService; +import com.cloud.utils.concurrency.NamedThreadFactory; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.encoding.Base64; +import com.cloud.uuididentity.dao.IdentityDao; +import com.cloud.utils.exception.CSExceptionErrorCode; + + +public class ApiServer implements HttpRequestHandler { + private static final Logger s_logger = Logger.getLogger(ApiServer.class.getName()); + private static final Logger s_accessLogger = Logger.getLogger("apiserver." + ApiServer.class.getName()); + + public static final short ADMIN_COMMAND = 1; + public static final short DOMAIN_ADMIN_COMMAND = 4; + public static final short RESOURCE_DOMAIN_ADMIN_COMMAND = 2; + public static final short USER_COMMAND = 8; + public static boolean encodeApiResponse = false; + public static String jsonContentType = "text/javascript"; + private Properties _apiCommands = null; + private ApiDispatcher _dispatcher; + private AccountManager _accountMgr = null; + private DomainManager _domainMgr = null; + private AsyncJobManager _asyncMgr = null; + private Account _systemAccount = null; + private User _systemUser = null; + + private static int _workerCount = 0; + + private static ApiServer s_instance = null; + private static List s_userCommands = null; + private static List s_resellerCommands = null; // AKA domain-admin + private static List s_adminCommands = null; + private static List s_resourceDomainAdminCommands = null; + private static List s_allCommands = null; + private static List s_pluggableServiceCommands = null; + private static final DateFormat _dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); + + private static ExecutorService _executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(), new NamedThreadFactory("ApiServer")); + + static { + s_userCommands = new ArrayList(); + s_resellerCommands = new ArrayList(); + s_adminCommands = new ArrayList(); + s_resourceDomainAdminCommands = new ArrayList(); + s_allCommands = new ArrayList(); + s_pluggableServiceCommands = new ArrayList(); + } + + private ApiServer() { + } + + public static void initApiServer(String[] apiConfig) { + if (s_instance == null) { + s_instance = new ApiServer(); + s_instance.init(apiConfig); + } + } + + public static ApiServer getInstance() { + // initApiServer(); + return s_instance; + } + + public Properties get_apiCommands() { + return _apiCommands; + } + + public static boolean isPluggableServiceCommand(String cmdClassName) { + if (s_pluggableServiceCommands != null) { + if (s_pluggableServiceCommands.contains(cmdClassName)) { + return true; + } + } + return false; + } + + private String[] getPluggableServicesApiConfigs() { + List pluggableServicesApiConfigs = new ArrayList(); + + ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name); + List services = locator.getAllPluggableServices(); + for (PluggableService service : services) { + pluggableServicesApiConfigs.add(service.getPropertiesFile()); + } + return pluggableServicesApiConfigs.toArray(new String[0]); + } + + private void processConfigFiles(String[] apiConfig, boolean pluggableServicesConfig) { + try { + if (_apiCommands == null) { + _apiCommands = new Properties(); + } + Properties preProcessedCommands = new Properties(); + if (apiConfig != null) { + for (String configFile : apiConfig) { + File commandsFile = PropertiesUtil.findConfigFile(configFile); + if (commandsFile != null) { + try { + preProcessedCommands.load(new FileInputStream(commandsFile)); + } catch (FileNotFoundException fnfex) { + // in case of a file within a jar in classpath, try to open stream using url + InputStream stream = PropertiesUtil.openStreamFromURL(configFile); + if (stream != null) { + preProcessedCommands.load(stream); + } else { + s_logger.error("Unable to find properites file", fnfex); + } + } + } + } + for (Object key : preProcessedCommands.keySet()) { + String preProcessedCommand = preProcessedCommands.getProperty((String) key); + String[] commandParts = preProcessedCommand.split(";"); + _apiCommands.put(key, commandParts[0]); + + if (pluggableServicesConfig) { + s_pluggableServiceCommands.add(commandParts[0]); + } + + if (commandParts.length > 1) { + try { + short cmdPermissions = Short.parseShort(commandParts[1]); + if ((cmdPermissions & ADMIN_COMMAND) != 0) { + s_adminCommands.add((String) key); + } + if ((cmdPermissions & RESOURCE_DOMAIN_ADMIN_COMMAND) != 0) { + s_resourceDomainAdminCommands.add((String) key); + } + if ((cmdPermissions & DOMAIN_ADMIN_COMMAND) != 0) { + s_resellerCommands.add((String) key); + } + if ((cmdPermissions & USER_COMMAND) != 0) { + s_userCommands.add((String) key); + } + } catch (NumberFormatException nfe) { + s_logger.info("Malformed command.properties permissions value, key = " + key + ", value = " + preProcessedCommand); + } + } + } + + s_allCommands.addAll(s_adminCommands); + s_allCommands.addAll(s_resourceDomainAdminCommands); + s_allCommands.addAll(s_userCommands); + s_allCommands.addAll(s_resellerCommands); + } + } catch (FileNotFoundException fnfex) { + s_logger.error("Unable to find properites file", fnfex); + } catch (IOException ioex) { + s_logger.error("Exception loading properties file", ioex); + } + } + + public void init(String[] apiConfig) { + BaseCmd.setComponents(new ApiResponseHelper()); + BaseListCmd.configure(); + processConfigFiles(apiConfig, false); + + // get commands for all pluggable services + String[] pluggableServicesApiConfigs = getPluggableServicesApiConfigs(); + processConfigFiles(pluggableServicesApiConfigs, true); + + ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name); + _accountMgr = locator.getManager(AccountManager.class); + _asyncMgr = locator.getManager(AsyncJobManager.class); + _systemAccount = _accountMgr.getSystemAccount(); + _systemUser = _accountMgr.getSystemUser(); + _dispatcher = ApiDispatcher.getInstance(); + _domainMgr = locator.getManager(DomainManager.class); + + Integer apiPort = null; // api port, null by default + ConfigurationDao configDao = locator.getDao(ConfigurationDao.class); + SearchCriteria sc = configDao.createSearchCriteria(); + sc.addAnd("name", SearchCriteria.Op.EQ, "integration.api.port"); + List values = configDao.search(sc, null); + if ((values != null) && (values.size() > 0)) { + ConfigurationVO apiPortConfig = values.get(0); + if (apiPortConfig.getValue() != null) { + apiPort = Integer.parseInt(apiPortConfig.getValue()); + } + } + + encodeApiResponse = Boolean.valueOf(configDao.getValue(Config.EncodeApiResponse.key())); + + String jsonType = configDao.getValue(Config.JavaScriptDefaultContentType.key()); + if (jsonType != null) { + jsonContentType = jsonType; + } + + if (apiPort != null) { + ListenerThread listenerThread = new ListenerThread(this, apiPort); + listenerThread.start(); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + // get some information for the access log... + StringBuffer sb = new StringBuffer(); + HttpServerConnection connObj = (HttpServerConnection) context.getAttribute("http.connection"); + if (connObj instanceof SocketHttpServerConnection) { + InetAddress remoteAddr = ((SocketHttpServerConnection) connObj).getRemoteAddress(); + sb.append(remoteAddr.toString() + " -- "); + } + sb.append(request.getRequestLine()); + + try { + String uri = request.getRequestLine().getUri(); + int requestParamsStartIndex = uri.indexOf('?'); + if (requestParamsStartIndex >= 0) { + uri = uri.substring(requestParamsStartIndex + 1); + } + + String[] paramArray = uri.split("&"); + if (paramArray.length < 1) { + s_logger.info("no parameters received for request: " + uri + ", aborting..."); + return; + } + + Map parameterMap = new HashMap(); + + String responseType = BaseCmd.RESPONSE_TYPE_XML; + for (String paramEntry : paramArray) { + String[] paramValue = paramEntry.split("="); + if (paramValue.length != 2) { + s_logger.info("malformed parameter: " + paramEntry + ", skipping"); + continue; + } + if ("response".equalsIgnoreCase(paramValue[0])) { + responseType = paramValue[1]; + } else { + // according to the servlet spec, the parameter map should be in the form (name=String, + // value=String[]), so + // parameter values will be stored in an array + parameterMap.put(/* name */paramValue[0], /* value */new String[] { paramValue[1] }); + } + } + try { + // always trust commands from API port, user context will always be UID_SYSTEM/ACCOUNT_ID_SYSTEM + UserContext.registerContext(_systemUser.getId(), _systemAccount, null, true); + sb.insert(0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); + String responseText = handleRequest(parameterMap, true, responseType, sb); + sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); + + writeResponse(response, responseText, HttpStatus.SC_OK, responseType, null); + } catch (ServerApiException se) { + String responseText = getSerializedApiError(se.getErrorCode(), se.getDescription(), parameterMap, responseType, se); + writeResponse(response, responseText, se.getErrorCode(), responseType, se.getDescription()); + sb.append(" " + se.getErrorCode() + " " + se.getDescription()); + } catch (RuntimeException e) { + // log runtime exception like NullPointerException to help identify the source easier + s_logger.error("Unhandled exception, ", e); + throw e; + } + } finally { + s_accessLogger.info(sb.toString()); + UserContext.unregisterContext(); + } + } + + @SuppressWarnings("rawtypes") + public String handleRequest(Map params, boolean decode, String responseType, StringBuffer auditTrailSb) throws ServerApiException { + String response = null; + String[] command = null; + try { + command = (String[]) params.get("command"); + if (command == null) { + s_logger.error("invalid request, no command sent"); + if (s_logger.isTraceEnabled()) { + s_logger.trace("dumping request parameters"); + for (Object key : params.keySet()) { + String keyStr = (String) key; + String[] value = (String[]) params.get(key); + s_logger.trace(" key: " + keyStr + ", value: " + ((value == null) ? "'null'" : value[0])); + } + } + throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "Invalid request, no command sent"); + } else { + Map paramMap = new HashMap(); + Set keys = params.keySet(); + Iterator keysIter = keys.iterator(); + while (keysIter.hasNext()) { + String key = (String) keysIter.next(); + if ("command".equalsIgnoreCase(key)) { + continue; + } + String[] value = (String[]) params.get(key); + + String decodedValue = null; + if (decode) { + try { + decodedValue = URLDecoder.decode(value[0], "UTF-8"); + } catch (UnsupportedEncodingException usex) { + s_logger.warn(key + " could not be decoded, value = " + value[0]); + throw new ServerApiException(BaseCmd.PARAM_ERROR, key + " could not be decoded, received value " + value[0]); + } catch (IllegalArgumentException iae) { + s_logger.warn(key + " could not be decoded, value = " + value[0]); + throw new ServerApiException(BaseCmd.PARAM_ERROR, key + " could not be decoded, received value " + value[0] + " which contains illegal characters eg.%"); + } + } else { + decodedValue = value[0]; + } + paramMap.put(key, decodedValue); + } + String cmdClassName = _apiCommands.getProperty(command[0]); + if (cmdClassName != null) { + Class cmdClass = Class.forName(cmdClassName); + BaseCmd cmdObj = (BaseCmd) cmdClass.newInstance(); + cmdObj.setFullUrlParams(paramMap); + cmdObj.setResponseType(responseType); + // This is where the command is either serialized, or directly dispatched + response = queueCommand(cmdObj, paramMap); + buildAuditTrail(auditTrailSb, command[0], response); + } else { + if (!command[0].equalsIgnoreCase("login") && !command[0].equalsIgnoreCase("logout")) { + String errorString = "Unknown API command: " + ((command == null) ? "null" : command[0]); + s_logger.warn(errorString); + auditTrailSb.append(" " + errorString); + throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, errorString); + } + } + } + } catch (Exception ex) { + if (ex instanceof InvalidParameterValueException) { + InvalidParameterValueException ref = (InvalidParameterValueException)ex; + ServerApiException e = new ServerApiException(BaseCmd.PARAM_ERROR, ex.getMessage()); + // copy over the IdentityProxy information as well and throw the serverapiexception. + ArrayList idList = ref.getIdProxyList(); + if (idList != null) { + // Iterate through entire arraylist and copy over each proxy id. + for (int i = 0 ; i < idList.size(); i++) { + IdentityProxy obj = idList.get(i); + e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName()); + } + } + // Also copy over the cserror code and the function/layer in which it was thrown. + e.setCSErrorCode(ref.getCSErrorCode()); + throw e; + } else if (ex instanceof PermissionDeniedException) { + PermissionDeniedException ref = (PermissionDeniedException)ex; + ServerApiException e = new ServerApiException(BaseCmd.ACCOUNT_ERROR, ex.getMessage()); + // copy over the IdentityProxy information as well and throw the serverapiexception. + ArrayList idList = ref.getIdProxyList(); + if (idList != null) { + // Iterate through entire arraylist and copy over each proxy id. + for (int i = 0 ; i < idList.size(); i++) { + IdentityProxy obj = idList.get(i); + e.addProxyObject(obj.getTableName(), obj.getValue(), obj.getidFieldName()); + } + } + e.setCSErrorCode(ref.getCSErrorCode()); + throw e; + } else if (ex instanceof ServerApiException) { + throw (ServerApiException) ex; + } else { + s_logger.error("unhandled exception executing api command: " + ((command == null) ? "null" : command[0]), ex); + ServerApiException e = new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal server error, unable to execute request."); + e.setCSErrorCode(CSExceptionErrorCode.getCSErrCode("ServerApiException")); + throw e; + } + } + return response; + } + + private String queueCommand(BaseCmd cmdObj, Map params) { + UserContext ctx = UserContext.current(); + Long callerUserId = ctx.getCallerUserId(); + Account caller = ctx.getCaller(); + if (cmdObj instanceof BaseAsyncCmd) { + Long objectId = null; + String objectEntityTable = null; + if (cmdObj instanceof BaseAsyncCreateCmd) { + BaseAsyncCreateCmd createCmd = (BaseAsyncCreateCmd) cmdObj; + _dispatcher.dispatchCreateCmd(createCmd, params); + objectId = createCmd.getEntityId(); + objectEntityTable = createCmd.getEntityTable(); + params.put("id", objectId.toString()); + } else { + ApiDispatcher.setupParameters(cmdObj, params); + ApiDispatcher.plugService(cmdObj); + } + + BaseAsyncCmd asyncCmd = (BaseAsyncCmd) cmdObj; + + if (callerUserId != null) { + params.put("ctxUserId", callerUserId.toString()); + } + if (caller != null) { + params.put("ctxAccountId", String.valueOf(caller.getId())); + } + + long startEventId = ctx.getStartEventId(); + asyncCmd.setStartEventId(startEventId); + + // save the scheduled event + Long eventId = EventUtils.saveScheduledEvent((callerUserId == null) ? User.UID_SYSTEM : callerUserId, + asyncCmd.getEntityOwnerId(), asyncCmd.getEventType(), asyncCmd.getEventDescription(), + startEventId); + if (startEventId == 0) { + // There was no create event before, set current event id as start eventId + startEventId = eventId; + } + + params.put("ctxStartEventId", String.valueOf(startEventId)); + + ctx.setAccountId(asyncCmd.getEntityOwnerId()); + + AsyncJobVO job = new AsyncJobVO(); + job.setInstanceId((objectId == null) ? asyncCmd.getInstanceId() : objectId); + job.setInstanceType(asyncCmd.getInstanceType()); + job.setUserId(callerUserId); + job.setAccountId(caller.getId()); + + job.setCmd(cmdObj.getClass().getName()); + job.setCmdInfo(ApiGsonHelper.getBuilder().create().toJson(params)); + + long jobId = _asyncMgr.submitAsyncJob(job); + + if (jobId == 0L) { + String errorMsg = "Unable to schedule async job for command " + job.getCmd(); + s_logger.warn(errorMsg); + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, errorMsg); + } + + if (objectId != null) { + SerializationContext.current().setUuidTranslation(true); + return ((BaseAsyncCreateCmd) asyncCmd).getResponse(jobId, objectId, objectEntityTable); + } + + SerializationContext.current().setUuidTranslation(true); + return ApiResponseSerializer.toSerializedString(asyncCmd.getResponse(jobId), asyncCmd.getResponseType()); + } else { + _dispatcher.dispatch(cmdObj, params); + + // if the command is of the listXXXCommand, we will need to also return the + // the job id and status if possible + if (cmdObj instanceof BaseListCmd) { + buildAsyncListResponse((BaseListCmd) cmdObj, caller); + } + + SerializationContext.current().setUuidTranslation(true); + return ApiResponseSerializer.toSerializedString((ResponseObject) cmdObj.getResponseObject(), cmdObj.getResponseType()); + } + } + + private void buildAsyncListResponse(BaseListCmd command, Account account) { + List responses = ((ListResponse) command.getResponseObject()).getResponses(); + if (responses != null && responses.size() > 0) { + List jobs = null; + + // list all jobs for ROOT admin + if (account.getType() == Account.ACCOUNT_TYPE_ADMIN) { + jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType(), null); + } else { + jobs = _asyncMgr.findInstancePendingAsyncJobs(command.getInstanceType(), account.getId()); + } + + if (jobs.size() == 0) { + return; + } + + // Using maps might possibly be more efficient if the set is large enough but for now, we'll just do a + // comparison of two lists. Either way, there shouldn't be too many async jobs active for the account. + for (AsyncJob job : jobs) { + if (job.getInstanceId() == null) { + continue; + } + for (ResponseObject response : responses) { + if (response.getObjectId() != null && job.getInstanceId().longValue() == response.getObjectId().longValue()) { + response.setJobId(job.getId()); + response.setJobStatus(job.getStatus()); + } + } + } + } + } + + private void buildAuditTrail(StringBuffer auditTrailSb, String command, String result) { + if (result == null) { + return; + } + auditTrailSb.append(" " + HttpServletResponse.SC_OK + " "); + auditTrailSb.append(result); + /* + * if (command.equals("queryAsyncJobResult")){ //For this command we need to also log job status and job + * resultcode for + * (Pair pair : resultValues){ String key = pair.first(); if (key.equals("jobstatus")){ + * auditTrailSb.append(" "); auditTrailSb.append(key); auditTrailSb.append("="); + * auditTrailSb.append(pair.second()); + * }else if (key.equals("jobresultcode")){ auditTrailSb.append(" "); auditTrailSb.append(key); + * auditTrailSb.append("="); + * auditTrailSb.append(pair.second()); } } }else { for (Pair pair : resultValues){ if + * (pair.first().equals("jobid")){ // Its an async job so report the jobid auditTrailSb.append(" "); + * auditTrailSb.append(pair.first()); auditTrailSb.append("="); auditTrailSb.append(pair.second()); } } } + */ + } + + private static boolean isCommandAvailable(String commandName) { + boolean isCommandAvailable = false; + isCommandAvailable = s_allCommands.contains(commandName); + return isCommandAvailable; + } + + public boolean verifyRequest(Map requestParameters, Long userId) throws ServerApiException { + try { + String apiKey = null; + String secretKey = null; + String signature = null; + String unsignedRequest = null; + + String[] command = (String[]) requestParameters.get("command"); + if (command == null) { + s_logger.info("missing command, ignoring request..."); + return false; + } + + String commandName = command[0]; + + // if userId not null, that mean that user is logged in + if (userId != null) { + Long accountId = ApiDBUtils.findUserById(userId).getAccountId(); + Account userAccount = _accountMgr.getAccount(accountId); + short accountType = userAccount.getType(); + + if (!isCommandAvailable(accountType, commandName)) { + s_logger.warn("The given command:" + commandName + " does not exist"); + throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist"); + } + return true; + } else { + // check against every available command to see if the command exists or not + if (!isCommandAvailable(commandName) && !commandName.equals("login") && !commandName.equals("logout")) { + s_logger.warn("The given command:" + commandName + " does not exist"); + throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist"); + } + } + + // - build a request string with sorted params, make sure it's all lowercase + // - sign the request, verify the signature is the same + List parameterNames = new ArrayList(); + + for (Object paramNameObj : requestParameters.keySet()) { + parameterNames.add((String) paramNameObj); // put the name in a list that we'll sort later + } + + Collections.sort(parameterNames); + + String signatureVersion = null; + String expires = null; + + for (String paramName : parameterNames) { + // parameters come as name/value pairs in the form String/String[] + String paramValue = ((String[]) requestParameters.get(paramName))[0]; + + if ("signature".equalsIgnoreCase(paramName)) { + signature = paramValue; + } else { + if ("apikey".equalsIgnoreCase(paramName)) { + apiKey = paramValue; + } + else if ("signatureversion".equalsIgnoreCase(paramName)) { + signatureVersion = paramValue; + } else if ("expires".equalsIgnoreCase(paramName)) { + expires = paramValue; + } + + if (unsignedRequest == null) { + unsignedRequest = paramName + "=" + URLEncoder.encode(paramValue, "UTF-8").replaceAll("\\+", "%20"); + } else { + unsignedRequest = unsignedRequest + "&" + paramName + "=" + URLEncoder.encode(paramValue, "UTF-8").replaceAll("\\+", "%20"); + } + } + } + + // if api/secret key are passed to the parameters + if ((signature == null) || (apiKey == null)) { + if (s_logger.isDebugEnabled()) { + s_logger.info("expired session, missing signature, or missing apiKey -- ignoring request...sig: " + signature + ", apiKey: " + apiKey); + } + return false; // no signature, bad request + } + + Date expiresTS = null; + if ("3".equals(signatureVersion)) { + // New signature authentication. Check for expire parameter and its validity + if (expires == null) { + s_logger.info("missing Expires parameter -- ignoring request...sig: " + signature + ", apiKey: " + apiKey); + return false; + } + synchronized (_dateFormat) { + try { + expiresTS = _dateFormat.parse(expires); + } catch (ParseException pe) { + s_logger.info("Incorrect date format for Expires parameter", pe); + return false; + } + } + Date now = new Date(System.currentTimeMillis()); + if (expiresTS.before(now)) { + s_logger.info("Request expired -- ignoring ...sig: " + signature + ", apiKey: " + apiKey); + return false; + } + } + + Transaction txn = Transaction.open(Transaction.CLOUD_DB); + txn.close(); + User user = null; + // verify there is a user with this api key + Pair userAcctPair = _accountMgr.findUserByApiKey(apiKey); + if (userAcctPair == null) { + s_logger.info("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey); + return false; + } + + user = userAcctPair.first(); + Account account = userAcctPair.second(); + + if (user.getState() != Account.State.enabled || !account.getState().equals(Account.State.enabled)) { + s_logger.info("disabled or locked user accessing the api, userid = " + user.getId() + "; name = " + user.getUsername() + "; state: " + user.getState() + "; accountState: " + + account.getState()); + return false; + } + + UserContext.updateContext(user.getId(), account, null); + + if (!isCommandAvailable(account.getType(), commandName)) { + s_logger.warn("The given command:" + commandName + " does not exist"); + throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command:" + commandName + " does not exist"); + } + + // verify secret key exists + secretKey = user.getSecretKey(); + if (secretKey == null) { + s_logger.info("User does not have a secret key associated with the account -- ignoring request, username: " + user.getUsername()); + return false; + } + + unsignedRequest = unsignedRequest.toLowerCase(); + + Mac mac = Mac.getInstance("HmacSHA1"); + SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA1"); + mac.init(keySpec); + mac.update(unsignedRequest.getBytes()); + byte[] encryptedBytes = mac.doFinal(); + String computedSignature = Base64.encodeBytes(encryptedBytes); + boolean equalSig = signature.equals(computedSignature); + if (!equalSig) { + s_logger.info("User signature: " + signature + " is not equaled to computed signature: " + computedSignature); + } + return equalSig; + } catch (Exception ex) { + if (ex instanceof ServerApiException && ((ServerApiException) ex).getErrorCode() == BaseCmd.UNSUPPORTED_ACTION_ERROR) { + throw (ServerApiException) ex; + } + s_logger.error("unable to verifty request signature", ex); + } + return false; + } + + public Long fetchDomainId(String domainUUID){ + ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name); + IdentityDao identityDao = locator.getDao(IdentityDao.class); + try{ + Long domainId = identityDao.getIdentityId("domain", domainUUID); + return domainId; + }catch(InvalidParameterValueException ex){ + return null; + } + } + + public void loginUser(HttpSession session, String username, String password, Long domainId, String domainPath, String loginIpAddress ,Map requestParameters) throws CloudAuthenticationException { + // We will always use domainId first. If that does not exist, we will use domain name. If THAT doesn't exist + // we will default to ROOT + if (domainId == null) { + if (domainPath == null || domainPath.trim().length() == 0) { + domainId = DomainVO.ROOT_DOMAIN; + } else { + Domain domainObj = _domainMgr.findDomainByPath(domainPath); + if (domainObj != null) { + domainId = domainObj.getId(); + } else { // if an unknown path is passed in, fail the login call + throw new CloudAuthenticationException("Unable to find the domain from the path " + domainPath); + } + } + } + + UserAccount userAcct = _accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); + if (userAcct != null) { + String timezone = userAcct.getTimezone(); + float offsetInHrs = 0f; + if (timezone != null) { + TimeZone t = TimeZone.getTimeZone(timezone); + s_logger.info("Current user logged in under " + timezone + " timezone"); + + java.util.Date date = new java.util.Date(); + long longDate = date.getTime(); + float offsetInMs = (t.getOffset(longDate)); + offsetInHrs = offsetInMs / (1000 * 60 * 60); + s_logger.info("Timezone offset from UTC is: " + offsetInHrs); + } + + Account account = _accountMgr.getAccount(userAcct.getAccountId()); + + // set the userId and account object for everyone + session.setAttribute("userid", userAcct.getId()); + UserVO user = (UserVO) _accountMgr.getActiveUser(userAcct.getId()); + if(user.getUuid() != null){ + session.setAttribute("user_UUID", user.getUuid()); + } + + session.setAttribute("username", userAcct.getUsername()); + session.setAttribute("firstname", userAcct.getFirstname()); + session.setAttribute("lastname", userAcct.getLastname()); + session.setAttribute("accountobj", account); + session.setAttribute("account", account.getAccountName()); + + session.setAttribute("domainid", account.getDomainId()); + DomainVO domain = (DomainVO) _domainMgr.getDomain(account.getDomainId()); + if(domain.getUuid() != null){ + session.setAttribute("domain_UUID", domain.getUuid()); + } + + session.setAttribute("type", Short.valueOf(account.getType()).toString()); + session.setAttribute("registrationtoken", userAcct.getRegistrationToken()); + session.setAttribute("registered", new Boolean(userAcct.isRegistered()).toString()); + + if (timezone != null) { + session.setAttribute("timezone", timezone); + session.setAttribute("timezoneoffset", Float.valueOf(offsetInHrs).toString()); + } + + // (bug 5483) generate a session key that the user must submit on every request to prevent CSRF, add that + // to the login response so that session-based authenticators know to send the key back + SecureRandom sesssionKeyRandom = new SecureRandom(); + byte sessionKeyBytes[] = new byte[20]; + sesssionKeyRandom.nextBytes(sessionKeyBytes); + String sessionKey = Base64.encodeBytes(sessionKeyBytes); + session.setAttribute("sessionkey", sessionKey); + + return; + } + throw new CloudAuthenticationException("Failed to authenticate user " + username + " in domain " + domainId + "; please provide valid credentials"); + } + + public void logoutUser(long userId) { + _accountMgr.logoutUser(Long.valueOf(userId)); + return; + } + + public boolean verifyUser(Long userId) { + User user = _accountMgr.getUserIncludingRemoved(userId); + Account account = null; + if (user != null) { + account = _accountMgr.getAccount(user.getAccountId()); + } + + if ((user == null) || (user.getRemoved() != null) || !user.getState().equals(Account.State.enabled) || (account == null) || !account.getState().equals(Account.State.enabled)) { + s_logger.warn("Deleted/Disabled/Locked user with id=" + userId + " attempting to access public API"); + return false; + } + return true; + } + + public static boolean isCommandAvailable(short accountType, String commandName) { + boolean isCommandAvailable = false; + switch (accountType) { + case Account.ACCOUNT_TYPE_ADMIN: + isCommandAvailable = s_adminCommands.contains(commandName); + break; + case Account.ACCOUNT_TYPE_DOMAIN_ADMIN: + isCommandAvailable = s_resellerCommands.contains(commandName); + break; + case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN: + isCommandAvailable = s_resourceDomainAdminCommands.contains(commandName); + break; + case Account.ACCOUNT_TYPE_NORMAL: + isCommandAvailable = s_userCommands.contains(commandName); + break; + } + return isCommandAvailable; + } + + // FIXME: rather than isError, we might was to pass in the status code to give more flexibility + private void writeResponse(HttpResponse resp, final String responseText, final int statusCode, String responseType, String reasonPhrase) { + try { + resp.setStatusCode(statusCode); + resp.setReasonPhrase(reasonPhrase); + + BasicHttpEntity body = new BasicHttpEntity(); + if (BaseCmd.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { + // JSON response + body.setContentType(jsonContentType); + if (responseText == null) { + body.setContent(new ByteArrayInputStream("{ \"error\" : { \"description\" : \"Internal Server Error\" } }".getBytes("UTF-8"))); + } + } else { + body.setContentType("text/xml"); + if (responseText == null) { + body.setContent(new ByteArrayInputStream("Internal Server Error".getBytes("UTF-8"))); + } + } + + if (responseText != null) { + body.setContent(new ByteArrayInputStream(responseText.getBytes("UTF-8"))); + } + resp.setEntity(body); + } catch (Exception ex) { + s_logger.error("error!", ex); + } + } + + // FIXME: the following two threads are copied from + // http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/httpcore/src/examples/org/apache/http/examples/ElementalHttpServer.java + // we have to cite a license if we are using this code directly, so we need to add the appropriate citation or + // modify the + // code to be very specific to our needs + static class ListenerThread extends Thread { + private HttpService _httpService = null; + private ServerSocket _serverSocket = null; + private HttpParams _params = null; + + public ListenerThread(ApiServer requestHandler, int port) { + try { + _serverSocket = new ServerSocket(port); + } catch (IOException ioex) { + s_logger.error("error initializing api server", ioex); + return; + } + + _params = new BasicHttpParams(); + _params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 30000).setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024) + .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false).setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) + .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1"); + + // Set up the HTTP protocol processor + BasicHttpProcessor httpproc = new BasicHttpProcessor(); + httpproc.addInterceptor(new ResponseDate()); + httpproc.addInterceptor(new ResponseServer()); + httpproc.addInterceptor(new ResponseContent()); + httpproc.addInterceptor(new ResponseConnControl()); + + // Set up request handlers + HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); + reqistry.register("*", requestHandler); + + // Set up the HTTP service + _httpService = new HttpService(httpproc, new NoConnectionReuseStrategy(), new DefaultHttpResponseFactory()); + _httpService.setParams(_params); + _httpService.setHandlerResolver(reqistry); + } + + @Override + public void run() { + s_logger.info("ApiServer listening on port " + _serverSocket.getLocalPort()); + while (!Thread.interrupted()) { + try { + // Set up HTTP connection + Socket socket = _serverSocket.accept(); + DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); + conn.bind(socket, _params); + + // Execute a new worker task to handle the request + _executor.execute(new WorkerTask(_httpService, conn, _workerCount++)); + } catch (InterruptedIOException ex) { + break; + } catch (IOException e) { + s_logger.error("I/O error initializing connection thread", e); + break; + } + } + } + } + + static class WorkerTask implements Runnable { + private final HttpService _httpService; + private final HttpServerConnection _conn; + + public WorkerTask(final HttpService httpService, final HttpServerConnection conn, final int count) { + _httpService = httpService; + _conn = conn; + } + + @Override + public void run() { + HttpContext context = new BasicHttpContext(null); + try { + while (!Thread.interrupted() && _conn.isOpen()) { + try { + _httpService.handleRequest(_conn, context); + _conn.close(); + } finally { + StackMaid.current().exitCleanup(); + } + } + } catch (ConnectionClosedException ex) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("ApiServer: Client closed connection"); + } + } catch (IOException ex) { + if (s_logger.isTraceEnabled()) { + s_logger.trace("ApiServer: IOException - " + ex); + } + } catch (HttpException ex) { + s_logger.warn("ApiServer: Unrecoverable HTTP protocol violation" + ex); + } finally { + try { + _conn.shutdown(); + } catch (IOException ignore) { + } + } + } + } + + public String getSerializedApiError(int errorCode, String errorText, Map apiCommandParams, String responseType, Exception ex) { + String responseName = null; + String cmdClassName = null; + + String responseText = null; + + try { + if (errorCode == BaseCmd.UNSUPPORTED_ACTION_ERROR || apiCommandParams == null || apiCommandParams.isEmpty()) { + responseName = "errorresponse"; + } else { + Object cmdObj = apiCommandParams.get("command"); + // cmd name can be null when "command" parameter is missing in the request + if (cmdObj != null) { + String cmdName = ((String[]) cmdObj)[0]; + cmdClassName = _apiCommands.getProperty(cmdName); + if (cmdClassName != null) { + Class claz = Class.forName(cmdClassName); + responseName = ((BaseCmd) claz.newInstance()).getCommandName(); + } else { + responseName = "errorresponse"; + } + } + } + ExceptionResponse apiResponse = new ExceptionResponse(); + apiResponse.setErrorCode(errorCode); + apiResponse.setErrorText(errorText); + apiResponse.setResponseName(responseName); + // Also copy over the IdentityProxy object List into this new apiResponse, from + // the exception caught. When invoked from handle(), the exception here can + // be either ServerApiException, PermissionDeniedException or InvalidParameterValue + // Exception. When invoked from ApiServlet's processRequest(), this can be + // a standard exception like NumberFormatException. We'll leave the standard ones alone. + if (ex != null) { + if (ex instanceof ServerApiException || ex instanceof PermissionDeniedException + || ex instanceof InvalidParameterValueException) { + // Cast the exception appropriately and retrieve the IdentityProxy + if (ex instanceof ServerApiException) { + ServerApiException ref = (ServerApiException) ex; + ArrayList idList = ref.getIdProxyList(); + if (idList != null) { + for (int i=0; i < idList.size(); i++) { + IdentityProxy id = idList.get(i); + apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName()); + } + } + // Also copy over the cserror code and the function/layer in which it was thrown. + apiResponse.setCSErrorCode(ref.getCSErrorCode()); + } else if (ex instanceof PermissionDeniedException) { + PermissionDeniedException ref = (PermissionDeniedException) ex; + ArrayList idList = ref.getIdProxyList(); + if (idList != null) { + for (int i=0; i < idList.size(); i++) { + IdentityProxy id = idList.get(i); + apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName()); + } + } + // Also copy over the cserror code and the function/layer in which it was thrown. + apiResponse.setCSErrorCode(ref.getCSErrorCode()); + } else if (ex instanceof InvalidParameterValueException) { + InvalidParameterValueException ref = (InvalidParameterValueException) ex; + ArrayList idList = ref.getIdProxyList(); + if (idList != null) { + for (int i=0; i < idList.size(); i++) { + IdentityProxy id = idList.get(i); + apiResponse.addProxyObject(id.getTableName(), id.getValue(), id.getidFieldName()); + } + } + // Also copy over the cserror code and the function/layer in which it was thrown. + apiResponse.setCSErrorCode(ref.getCSErrorCode()); + } + } + } + SerializationContext.current().setUuidTranslation(true); + responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType); + + } catch (Exception e) { + s_logger.error("Exception responding to http request", e); + } + return responseText; + } +} diff --git a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java index 43a1f854f61..1013aa2be1c 100644 --- a/server/src/com/cloud/network/as/AutoScaleManagerImpl.java +++ b/server/src/com/cloud/network/as/AutoScaleManagerImpl.java @@ -43,7 +43,9 @@ import com.cloud.api.commands.ListCountersCmd; import com.cloud.api.commands.UpdateAutoScalePolicyCmd; import com.cloud.api.commands.UpdateAutoScaleVmGroupCmd; import com.cloud.api.commands.UpdateAutoScaleVmProfileCmd; +import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenter; import com.cloud.dc.dao.DataCenterDao; import com.cloud.event.ActionEvent; @@ -87,7 +89,7 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.net.NetUtils; -@Local(value = { AutoScaleService.class }) +@Local(value = { AutoScaleService.class }) public class AutoScaleManagerImpl implements AutoScaleService, Manager { private static final Logger s_logger = Logger.getLogger(AutoScaleManagerImpl.class); @@ -128,6 +130,8 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { UserDao _userDao; @Inject IPAddressDao _ipAddressDao; + @Inject + ConfigurationDao _configDao; @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -168,7 +172,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { for (Counter counter : counters) { if (!supportedCounters.contains(counter.getSource())) { throw new InvalidParameterException("AutoScale counter with source='" + counter.getSource() + "' is not supported " + - "in the network where lb is configured"); + "in the network where lb is configured"); } } } @@ -293,10 +297,17 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { autoscaleUserId = UserContext.current().getCallerUserId(); } - // TODO check template is present or not. + String csUrl = cmd.getCsUrl(); + if (csUrl == null) { + String mgmtIP = _configDao.getValue(Config.ManagementHostIPAdr.key()); + csUrl = "http://" + mgmtIP + ":8080/client/api?"; + } + else { + csUrl += "/client/api?"; + } AutoScaleVmProfileVO profileVO = new AutoScaleVmProfileVO(cmd.getZoneId(), cmd.getDomainId(), cmd.getAccountId(), cmd.getServiceOfferingId(), cmd.getTemplateId(), cmd.getOtherDeployParams(), - cmd.getSnmpCommunity(), cmd.getSnmpPort(), cmd.getDestroyVmGraceperiod(), autoscaleUserId); + cmd.getSnmpCommunity(), cmd.getSnmpPort(), cmd.getDestroyVmGraceperiod(), autoscaleUserId, csUrl); _autoScaleVmProfileDao.persist(profileVO); return profileVO; } @@ -347,7 +358,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { AutoScaleVmProfileVO vmProfile = getEntityInDatabase("Auto Scale Vm Profile", profileId, _autoScaleVmProfileDao); AutoScaleVmProfileVO bakUpProfile = getEntityInDatabase("Auto Scale Vm Profile", profileId, _autoScaleVmProfileDao); - if(templateId == null && otherDeployParams == null) { + if (templateId == null && otherDeployParams == null) { throw new InvalidParameterValueException("Atleast one parameter should be passed for update"); } @@ -394,36 +405,36 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { autoScalePolicyVO = _autoScalePolicyDao.persist(autoScalePolicyVO); - if(conditionIds != null) { + if (conditionIds != null) { SearchBuilder conditionsSearch = _conditionDao.createSearchBuilder(); conditionsSearch.and("ids", conditionsSearch.entity().getId(), Op.IN); conditionsSearch.done(); SearchCriteria sc = conditionsSearch.create(); - sc.setParameters("ids", conditionIds.toArray(new Object[0])); - List conditions = _conditionDao.search(sc, null); + sc.setParameters("ids", conditionIds.toArray(new Object[0])); + List conditions = _conditionDao.search(sc, null); - ControlledEntity[] sameOwnerEntities = conditions.toArray(new ControlledEntity[conditions.size() + 1]); - sameOwnerEntities[sameOwnerEntities.length - 1] = autoScalePolicyVO; - _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, sameOwnerEntities); + ControlledEntity[] sameOwnerEntities = conditions.toArray(new ControlledEntity[conditions.size() + 1]); + sameOwnerEntities[sameOwnerEntities.length - 1] = autoScalePolicyVO; + _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, sameOwnerEntities); - if (conditionIds.size() != conditions.size()) { - // TODO report the condition id which could not be found - throw new InvalidParameterValueException("Unable to find a condition specified"); - } - - ArrayList counterIds = new ArrayList(); - for (ConditionVO condition : conditions) { - if (counterIds.contains(condition.getCounterid())) { - throw new InvalidParameterValueException("atleast two conditions in the conditionids have the same counter. It is not right to apply two different conditions for the same counter"); + if (conditionIds.size() != conditions.size()) { + // TODO report the condition id which could not be found + throw new InvalidParameterValueException("Unable to find a condition specified"); } - counterIds.add(condition.getCounterid()); - } - for (Long conditionId : conditionIds) { - AutoScalePolicyConditionMapVO policyConditionMapVO = new AutoScalePolicyConditionMapVO(autoScalePolicyVO.getId(), conditionId); - _autoScalePolicyConditionMapDao.persist(policyConditionMapVO); - } + ArrayList counterIds = new ArrayList(); + for (ConditionVO condition : conditions) { + if (counterIds.contains(condition.getCounterid())) { + throw new InvalidParameterValueException("atleast two conditions in the conditionids have the same counter. It is not right to apply two different conditions for the same counter"); + } + counterIds.add(condition.getCounterid()); + } + + for (Long conditionId : conditionIds) { + AutoScalePolicyConditionMapVO policyConditionMapVO = new AutoScalePolicyConditionMapVO(autoScalePolicyVO.getId(), conditionId); + _autoScalePolicyConditionMapDao.persist(policyConditionMapVO); + } } txn.commit(); @@ -450,7 +461,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { AutoScalePolicyVO policyVO = new AutoScalePolicyVO(cmd.getDomainId(), cmd.getAccountId(), duration, quietTime, action); - policyVO = checkValidityAndPersist(policyVO, cmd.getConditionIds()); + policyVO = checkValidityAndPersist(policyVO, cmd.getConditionIds()); return policyVO; } @@ -475,12 +486,12 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { s_logger.warn("Failed to remove AutoScale Policy db object"); return false; } - success = _autoScalePolicyConditionMapDao.removeByAutoScalePolicyId(id); + success = _autoScalePolicyConditionMapDao.removeByAutoScalePolicyId(id); if (!success) { s_logger.warn("Failed to remove AutoScale Policy Condition mappings"); return false; } - txn.commit(); + txn.commit(); return success; // successful } @@ -517,7 +528,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { Account caller = UserContext.current().getCaller(); Ternary domainIdRecursiveListProject = new Ternary(domainId, isRecursive, null); + ListProjectResourcesCriteria>(domainId, isRecursive, null); _accountMgr.buildACLSearchParameters(caller, id, accountName, null, permittedAccounts, domainIdRecursiveListProject, listAll, false); domainId = domainIdRecursiveListProject.first(); @@ -580,7 +591,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { List conditionIds = cmd.getConditionIds(); AutoScalePolicyVO policy = getEntityInDatabase("Auto Scale Policy", policyId, _autoScalePolicyDao); - if(duration == null && quietTime == null && conditionIds == null) { + if (duration == null && quietTime == null && conditionIds == null) { throw new InvalidParameterValueException("Atleast one parameter should be passed for update"); } @@ -598,10 +609,10 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { if (!vmGroupVO.getState().equals(AutoScaleVmGroup.State_Disabled)) { throw new InvalidParameterValueException("The AutoScale Policy can be updated only if the Vm Group it is associated with is disabled in state"); } - if(vmGroupVO.getInterval() < duration) { + if (vmGroupVO.getInterval() < duration) { throw new InvalidParameterValueException("duration is less than the associated AutoScaleVmGroup's interval"); } - if(vmGroupVO.getInterval() < quietTime) { + if (vmGroupVO.getInterval() < quietTime) { throw new InvalidParameterValueException("quietTime is less than the associated AutoScaleVmGroup's interval"); } } @@ -610,7 +621,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { s_logger.debug("Updated Auto Scale Policy id:" + policyId); - return policy; + return policy; } @Override @@ -621,7 +632,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { int maxMembers = cmd.getMaxMembers(); Integer interval = cmd.getInterval(); - if(interval == null) { + if (interval == null) { interval = NetUtils.DEFAULT_AUTOSCALE_POLICY_INTERVAL_TIME; } @@ -633,7 +644,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { Long zoneId = _ipAddressDao.findById(loadBalancer.getSourceIpAddressId()).getDataCenterId(); - if(_autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancer.getId())) { + if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(loadBalancer.getId())) { throw new InvalidParameterValueException("an AutoScaleVmGroup is already attached to the lb rule, the existing vm group has to be first deleted"); } @@ -661,7 +672,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { public boolean configureAutoScaleVmGroup(long vmGroupid) { AutoScaleVmGroup vmGroup = _autoScaleVmGroupDao.findById(vmGroupid); - if(isLoadBalancerBasedAutoScaleVmGroup(vmGroup)) { + if (isLoadBalancerBasedAutoScaleVmGroup(vmGroup)) { return _lbRulesMgr.configureLbAutoScaleVmGroup(vmGroupid); } @@ -675,7 +686,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { public boolean deleteAutoScaleVmGroup(long id) { AutoScaleVmGroupVO autoScaleVmGroupVO = getEntityInDatabase("AutoScale Vm Group", id, _autoScaleVmGroupDao); - if(autoScaleVmGroupVO.getState().equals(AutoScaleVmGroup.State_New)) { + if (autoScaleVmGroupVO.getState().equals(AutoScaleVmGroup.State_New)) { /* This condition is for handling failures during creation command */ return _autoScaleVmGroupDao.remove(id); } @@ -687,7 +698,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { try { success = configureAutoScaleVmGroup(id); } finally { - if(!success) { + if (!success) { s_logger.warn("Could not delete AutoScale Vm Group id : " + id); autoScaleVmGroupVO.setState(bakupState); _autoScaleVmGroupDao.persist(autoScaleVmGroupVO); @@ -704,13 +715,13 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { return false; } - success = _autoScaleVmGroupPolicyMapDao.removeByGroupId(id); + success = _autoScaleVmGroupPolicyMapDao.removeByGroupId(id); if (!success) { s_logger.warn("Failed to remove AutoScale Group Policy mappings"); return false; } - txn.commit(); + txn.commit(); return success; // Successfull } @@ -778,11 +789,11 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { throw new InvalidParameterValueException("interval is an invalid value: " + interval); } - if(scaleUpPolicyIds != null) { + if (scaleUpPolicyIds != null) { policies.addAll(getAutoScalePolicies("scaleuppolicyid", scaleUpPolicyIds, counters, interval, true)); } - if(scaleDownPolicyIds != null) { + if (scaleDownPolicyIds != null) { policies.addAll(getAutoScalePolicies("scaledownpolicyid", scaleDownPolicyIds, counters, interval, false)); } @@ -820,7 +831,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { List scaleUpPolicyIds = cmd.getScaleUpPolicyIds(); List scaleDownPolicyIds = cmd.getScaleDownPolicyIds(); - if(minMembers == null && maxMembers == null && interval == null && scaleUpPolicyIds == null && scaleDownPolicyIds == null) { + if (minMembers == null && maxMembers == null && interval == null && scaleUpPolicyIds == null && scaleDownPolicyIds == null) { throw new InvalidParameterValueException("Atleast one parameter should be passed for update"); } @@ -845,18 +856,18 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { boolean success = true; List bakupPolicyIds = new ArrayList(); - if(scaleUpPolicyIds != null || scaleDownPolicyIds != null) { + if (scaleUpPolicyIds != null || scaleDownPolicyIds != null) { List bakupScaleUpPolicyIds = new ArrayList(); List bakupScaleDownPolicyIds = new ArrayList(); ApiDBUtils.getAutoScaleVmGroupPolicyIds(vmGroupId, bakupScaleUpPolicyIds, bakupScaleDownPolicyIds); - if(scaleUpPolicyIds != null) { + if (scaleUpPolicyIds != null) { bakupPolicyIds.addAll(bakupScaleUpPolicyIds); } - if(scaleDownPolicyIds != null) { + if (scaleDownPolicyIds != null) { bakupPolicyIds.addAll(bakupScaleDownPolicyIds); } success = _autoScaleVmGroupPolicyMapDao.removeByGroupAndPolicies(vmGroupId, bakupPolicyIds); - if(!success) { + if (!success) { s_logger.warn("Removal of existing policy mappings for vmgroup failed"); return null; } @@ -865,16 +876,15 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { vmGroupVO = checkValidityAndPersist(vmGroupVO, scaleUpPolicyIds, scaleDownPolicyIds); try { success = configureAutoScaleVmGroup(vmGroupVO.getId()); - } - finally { - if (!success) { - Transaction.currentTxn().start(); + } finally { + if (!success) { + Transaction.currentTxn().start(); for (Long backUpPolicyId : bakupPolicyIds) { _autoScaleVmGroupPolicyMapDao.persist(new AutoScaleVmGroupPolicyMapVO(vmGroupId, backUpPolicyId)); + } + _autoScaleVmGroupDao.update(bakUpVmGroupVO.getId(), bakUpVmGroupVO); + Transaction.currentTxn().commit(); } - _autoScaleVmGroupDao.update(bakUpVmGroupVO.getId(), bakUpVmGroupVO); - Transaction.currentTxn().commit(); - } } if (success) { s_logger.debug("Updated Auto Scale VmGroup id:" + vmGroupId); @@ -894,18 +904,18 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { } try { - vmGroup.setState(AutoScaleVmGroup.State_Enabled); - vmGroup = _autoScaleVmGroupDao.persist(vmGroup); + vmGroup.setState(AutoScaleVmGroup.State_Enabled); + vmGroup = _autoScaleVmGroupDao.persist(vmGroup); success = _lbRulesMgr.configureLbAutoScaleVmGroup(id); } finally { if (!success) { - vmGroup.setState(AutoScaleVmGroup.State_Disabled); - _autoScaleVmGroupDao.persist(vmGroup); + vmGroup.setState(AutoScaleVmGroup.State_Disabled); + _autoScaleVmGroupDao.persist(vmGroup); s_logger.warn("Failed to enable AutoScale Vm Group id : " + id); - return null; + return null; + } } - } return vmGroup; } @@ -920,18 +930,18 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { } try { - vmGroup.setState(AutoScaleVmGroup.State_Disabled); - vmGroup = _autoScaleVmGroupDao.persist(vmGroup); + vmGroup.setState(AutoScaleVmGroup.State_Disabled); + vmGroup = _autoScaleVmGroupDao.persist(vmGroup); success = _lbRulesMgr.configureLbAutoScaleVmGroup(id); } finally { if (!success) { - vmGroup.setState(AutoScaleVmGroup.State_Enabled); - _autoScaleVmGroupDao.persist(vmGroup); + vmGroup.setState(AutoScaleVmGroup.State_Enabled); + _autoScaleVmGroupDao.persist(vmGroup); s_logger.warn("Failed to disable AutoScale Vm Group id : " + id); - return null; + return null; + } } - } return vmGroup; } @@ -994,7 +1004,7 @@ public class AutoScaleManagerImpl implements AutoScaleService, Manager { String name = cmd.getName(); Long id = cmd.getId(); String source = cmd.getSource(); - if(source != null ) + if (source != null) source = source.toLowerCase(); Filter searchFilter = new Filter(CounterVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal()); diff --git a/server/src/com/cloud/network/as/AutoScaleVmProfileVO.java b/server/src/com/cloud/network/as/AutoScaleVmProfileVO.java index ecda5e65e88..82c0faf7134 100644 --- a/server/src/com/cloud/network/as/AutoScaleVmProfileVO.java +++ b/server/src/com/cloud/network/as/AutoScaleVmProfileVO.java @@ -62,6 +62,9 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity { @Column(name = "other_deploy_params", updatable = true, length = 1024) private String otherDeployParams; + @Column(name = "cs_url") + private String csUrl; + @Column(name = "destroy_vm_grace_period", updatable = true) private Integer destroyVmGraceperiod = NetUtils.DEFAULT_AUTOSCALE_VM_DESTROY_TIME; @@ -81,7 +84,7 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity { } public AutoScaleVmProfileVO(long zoneId, long domainId, long accountId, long serviceOfferingId, long templateId, String otherDeployParams, String snmpCommunity, Integer snmpPort, Integer destroyVmGraceperiod, - long autoscaleUserId) { + long autoscaleUserId, String csUrl) { this.uuid = UUID.randomUUID().toString(); setZoneId(zoneId); setDomainId(domainId); @@ -90,6 +93,7 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity { setTemplateId(templateId); setOtherDeployParams(otherDeployParams); setAutoscaleUserId(autoscaleUserId); + setCsUrl(csUrl); if (destroyVmGraceperiod != null) { setDestroyVmGraceperiod(destroyVmGraceperiod); } @@ -138,6 +142,14 @@ public class AutoScaleVmProfileVO implements AutoScaleVmProfile, Identity { return snmpCommunity; } + public String getCsUrl() { + return csUrl; + } + + public void setCsUrl(String csUrl) { + this.csUrl = csUrl; + } + public void setSnmpCommunity(String snmpCommunity) { this.snmpCommunity = snmpCommunity; } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index e9252fd63c4..f39b439e556 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -8,7 +8,7 @@ // 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. -// +// // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.network.lb; @@ -16,7 +16,6 @@ import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Formatter; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -188,7 +187,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa TemplateManager _templateMgr; @Inject ExternalLoadBalancerUsageManager _externalLBUsageMgr; - @Inject + @Inject NetworkServiceMapDao _ntwkSrvcDao; @Inject ResourceTagDao _resourceTagDao; @@ -221,7 +220,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa serviceResponse.setName(service.getName()); if ("Lb".equalsIgnoreCase(service.getName())) { Map serviceCapabilities = serviceCapabilitiesMap - .get(service); + .get(service); if (serviceCapabilities != null) { for (Capability capability : serviceCapabilities .keySet()) { @@ -251,19 +250,12 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa autoScalePolicies.add(new LbAutoScalePolicy(autoScalePolicy, lbConditions)); } ApiServer apiserver = ApiServer.getInstance(); - String apiIpAddress = apiserver.getServerIpAddress(); - String apiPort = apiserver.getServerPort(); - StringBuilder sb = new StringBuilder(); - - Formatter formatter = new Formatter(sb, java.util.Locale.US); - formatter.format("https://%s:%s/client/api?", apiIpAddress, apiPort); - String csurl = sb.toString(); AutoScaleVmProfile autoScaleVmProfile = _autoScaleVmProfileDao.findById(vmGroup.getProfileId()); Long autoscaleUserId = autoScaleVmProfile.getAutoScaleUserId(); User user = _userDao.findById(autoscaleUserId); String apiKey = user.getApiKey(); String secretKey = user.getSecretKey(); - LbAutoScaleVmProfile lbAutoScaleVmProfile = new LbAutoScaleVmProfile(autoScaleVmProfile, csurl, apiKey, secretKey); + LbAutoScaleVmProfile lbAutoScaleVmProfile = new LbAutoScaleVmProfile(autoScaleVmProfile, apiKey, secretKey); return new LbAutoScaleVmGroup(vmGroup, autoScalePolicies, lbAutoScaleVmProfile); } @@ -537,7 +529,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa } return success; - } + } private boolean isRollBackAllowedForProvider(LoadBalancerVO loadBalancer) { Network network = _networkDao.findById(loadBalancer.getNetworkId()); @@ -557,7 +549,6 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa throw new InvalidParameterValueException("Failed to assign to load balancer; the load balancer was not found.", null); } - List mappedInstances = _lb2VmMapDao.listByLoadBalancerId(loadBalancerId, false); Set mappedInstanceIds = new HashSet(); for (LoadBalancerVMMapVO mappedInstance : mappedInstances) { @@ -649,8 +640,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa if(!success){ CloudRuntimeException ex = new CloudRuntimeException("Failed to add specified loadbalancerruleid for vms " + instanceIds); - ex.addProxyObject(loadBalancer, loadBalancerId, "loadBalancerId"); - // TBD: Also pack in the instanceIds in the exception using the right VO object or table name. + ex.addProxyObject(loadBalancer, loadBalancerId, "loadBalancerId"); + // TBD: Also pack in the instanceIds in the exception using the right VO object or table name. throw ex; } @@ -695,7 +686,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa if (!applyLoadBalancerConfig(loadBalancerId)) { s_logger.warn("Failed to remove load balancer rule id " + loadBalancerId + " for vms " + instanceIds); CloudRuntimeException ex = new CloudRuntimeException("Failed to remove specified load balancer rule id for vms " + instanceIds); - ex.addProxyObject(loadBalancer, loadBalancerId, "loadBalancerId"); + ex.addProxyObject(loadBalancer, loadBalancerId, "loadBalancerId"); throw ex; } success = true; @@ -717,7 +708,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa } if(!success){ CloudRuntimeException ex = new CloudRuntimeException("Failed to remove specified load balancer rule id for vms " + instanceIds); - ex.addProxyObject(loadBalancer, loadBalancerId, "loadBalancerId"); + ex.addProxyObject(loadBalancer, loadBalancerId, "loadBalancerId"); throw ex; } return success; @@ -911,23 +902,23 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa try { if (ipVO.getAssociatedWithNetworkId() == null) { - boolean assignToVpcNtwk = network.getVpcId() != null - && ipVO.getVpcId() != null && ipVO.getVpcId().longValue() == network.getVpcId(); + boolean assignToVpcNtwk = network.getVpcId() != null + && ipVO.getVpcId() != null && ipVO.getVpcId().longValue() == network.getVpcId(); if (assignToVpcNtwk) { - //set networkId just for verification purposes + //set networkId just for verification purposes _networkMgr.checkIpForService(ipVO, Service.Lb, lb.getNetworkId()); s_logger.debug("The ip is not associated with the VPC network id="+ lb.getNetworkId() + " so assigning"); ipVO = _networkMgr.associateIPToGuestNetwork(ipAddrId, lb.getNetworkId(), false); - performedIpAssoc = true; + performedIpAssoc = true; } - } else { + } else { _networkMgr.checkIpForService(ipVO, Service.Lb, null); - } - - if (ipVO.getAssociatedWithNetworkId() == null) { + } + + if (ipVO.getAssociatedWithNetworkId() == null) { throw new InvalidParameterValueException("Ip address " + ipVO + " is not assigned to the network " + network); - } + } if (lb.getSourceIpAddressId() == null) { throw new CloudRuntimeException("No ip address is defined to assign the LB to"); @@ -972,15 +963,15 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa // make sure ip address exists if (ipAddr == null || !ipAddr.readyToUse()) { InvalidParameterValueException ex = new InvalidParameterValueException("Unable to create load balancer rule, invalid IP address id specified", null); - ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); + ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); throw ex; } else if (ipAddr.isOneToOneNat()) { InvalidParameterValueException ex = new InvalidParameterValueException("Unable to create load balancer rule; specified sourceip id has static nat enabled", null); - ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); + ex.addProxyObject(ipAddr, sourceIpId, "sourceIpId"); throw ex; } - _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), + _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol(), Purpose.LoadBalancing, FirewallRuleType.User); Long networkId = ipAddr.getAssociatedWithNetworkId(); @@ -1010,7 +1001,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa newRule = _lbDao.persist(newRule); if (openFirewall) { - _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), lb.getSourcePortStart(), + _firewallMgr.createRuleForAllCidrs(sourceIpId, caller.getCaller(), lb.getSourcePortStart(), lb.getSourcePortEnd(), lb.getProtocol(), null, null, newRule.getId(), networkId); } @@ -1050,7 +1041,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa public boolean applyLoadBalancerConfig(long lbRuleId) throws ResourceUnavailableException { LoadBalancerVO lb = _lbDao.findById(lbRuleId); List lbs; - if (isRollBackAllowedForProvider(lb)) { + if (isRollBackAllowedForProvider(lb)) { // this is for Netscalar type of devices. if their is failure the db entries will be rollbacked. lbs = Arrays.asList(lb); } else { @@ -1313,13 +1304,13 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesMa * update if there is no change in the object. */ if (lbBackup.getName() != null) { - lb.setName(lbBackup.getName()); + lb.setName(lbBackup.getName()); } if (lbBackup.getDescription() != null) { lb.setDescription(lbBackup.getDescription()); } if (lbBackup.getAlgorithm() != null){ - lb.setAlgorithm(lbBackup.getAlgorithm()); + lb.setAlgorithm(lbBackup.getAlgorithm()); } lb.setState(lbBackup.getState()); _lbDao.update(lb.getId(), lb); diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index d74fc3cc247..f0e386bc9a7 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -2375,6 +2375,7 @@ CREATE TABLE `cloud`.`autoscale_vmprofiles` ( `destroy_vm_grace_period` int unsigned COMMENT 'the time allowed for existing connections to get closed before a vm is destroyed', `snmp_community` varchar(255) COMMENT 'the community string to be used to reach out to the VM deployed by this profile', `snmp_port` int unsigned COMMENT 'the snmp port to be used to reach out to the VM deployed by this profile', + `cs_url` varchar(255) NOT NULL COMMENT 'the URL including port of the CloudStack Management Server e.g. http://server.cloud.com:8080', `created` datetime NOT NULL COMMENT 'date created', `removed` datetime COMMENT 'date removed if not null', PRIMARY KEY (`id`),