Pull changes from master into javelin

- Disables simulator plugin, breaks build, available via simulator profile
- Fixes spring injections
- Fix api,acl plugins, ApiServer, ApiDispatcher
- Fix other merge conflicts

Conflicts:
	docs/en-US/external-firewalls-and-load-balancers.xml
	plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java
	server/src/com/cloud/api/ApiDispatcher.java
	server/src/com/cloud/api/ApiServer.java
	server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
	utils/test/com/cloud/utils/log/CglibThrowableRendererTest.java

Signed-off-by: Rohit Yadav <bhaisaab@apache.org>
This commit is contained in:
Rohit Yadav 2013-01-12 06:01:58 -08:00
commit 38eaa04b98
40 changed files with 899 additions and 231 deletions

View File

@ -60,6 +60,8 @@ public interface NetworkService {
Network getNetwork(long networkId); Network getNetwork(long networkId);
Network getNetwork(String networkUuid);
IpAddress getIp(long id); IpAddress getIp(long id);
NetworkProfile convertNetworkToNetworkProfile(long networkId); NetworkProfile convertNetworkToNetworkProfile(long networkId);

View File

@ -30,6 +30,8 @@ public interface DomainService {
Domain getDomain(long id); Domain getDomain(long id);
Domain getDomain(String uuid);
/** /**
* Return whether a domain is a child domain of a given domain. * Return whether a domain is a child domain of a given domain.
* *

View File

@ -16,14 +16,12 @@
// under the License. // under the License.
package org.apache.cloudstack.acl; package org.apache.cloudstack.acl;
import org.apache.cloudstack.acl.RoleType;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import org.apache.cloudstack.acl.RoleType;
import com.cloud.utils.component.Adapter; import com.cloud.utils.component.Adapter;
/** // APIChecker checks the ownership and access control to API requests
* APIAccessChecker checks the ownership and access control to API requests public interface APIChecker extends Adapter {
*/ // Interface for checking access for a role using apiname
public interface APIAccessChecker extends Adapter { boolean checkAccess(RoleType roleType, String apiCommandName) throws PermissionDeniedException;
// Interface for checking access to an API for an user
boolean canAccessAPI(RoleType roleType, String apiCommandName) throws PermissionDeniedException;
} }

View File

@ -158,6 +158,7 @@ public class ApiConstants {
public static final String RECEIVED_BYTES = "receivedbytes"; public static final String RECEIVED_BYTES = "receivedbytes";
public static final String REQUIRES_HVM = "requireshvm"; public static final String REQUIRES_HVM = "requireshvm";
public static final String RESOURCE_TYPE = "resourcetype"; public static final String RESOURCE_TYPE = "resourcetype";
public static final String RESPONSE = "response";
public static final String QUERY_FILTER = "queryfilter"; public static final String QUERY_FILTER = "queryfilter";
public static final String SCHEDULE = "schedule"; public static final String SCHEDULE = "schedule";
public static final String SCOPE = "scope"; public static final String SCOPE = "scope";

View File

@ -314,13 +314,6 @@ public interface ResponseGenerator {
StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result); StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result);
/**
* @param tableName TODO
* @param token
* @return
*/
Long getIdentiyId(String tableName, String token);
/** /**
* @param resourceTag * @param resourceTag
* @param keyValueOnly TODO * @param keyValueOnly TODO

View File

@ -147,10 +147,9 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
private List<String> securityGroupNameList; private List<String> securityGroupNameList;
@ACL(checkKeyAccess=true) @ACL(checkKeyAccess=true)
@Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, entityType={Network.class,IpAddress.class}, @Parameter(name = ApiConstants.IP_NETWORK_LIST, type = CommandType.MAP, entityType={Network.class, IpAddress.class},
description = "ip to network mapping. Can't be specified with networkIds parameter." + description = "ip to network mapping. Can't be specified with networkIds parameter." +
" Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].networkid=204 - requests to" + " Example: iptonetworklist[0].ip=10.10.10.11&iptonetworklist[0].networkid=uuid - requests to use ip 10.10.10.11 in network id=uuid")
" use ip 10.10.10.11 in network id=204")
private Map ipToNetworkList; private Map ipToNetworkList;
@Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, description="the ip address for default vm's network") @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, description="the ip address for default vm's network")
@ -284,7 +283,17 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
Iterator iter = ipsCollection.iterator(); Iterator iter = ipsCollection.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
HashMap<String, String> ips = (HashMap<String, String>) iter.next(); HashMap<String, String> ips = (HashMap<String, String>) iter.next();
Long networkId = Long.valueOf(_responseGenerator.getIdentiyId("networks", ips.get("networkid"))); Long networkId;
Network network = _networkService.getNetwork(ips.get("networkid"));
if (network != null) {
networkId = network.getId();
} else {
try {
networkId = Long.parseLong(ips.get("networkid"));
} catch(NumberFormatException e) {
throw new InvalidParameterValueException("Unable to translate and find entity with networkId: " + ips.get("networkid"));
}
}
String requestedIp = (String) ips.get("ip"); String requestedIp = (String) ips.get("ip");
ipToNetworkMap.put(networkId, requestedIp); ipToNetworkMap.put(networkId, requestedIp);
} }

View File

@ -137,7 +137,7 @@ public class ExtractVolumeCmd extends BaseAsyncCmd {
Volume vol = _entityMgr.findById(Volume.class, id); Volume vol = _entityMgr.findById(Volume.class, id);
response.setId(vol.getUuid()); response.setId(vol.getUuid());
response.setName(vol.getName()); response.setName(vol.getName());
DataCenter zone = _entityMgr.findById(DataCenter.class, id); DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
response.setZoneId(zone.getUuid()); response.setZoneId(zone.getUuid());
response.setZoneName(zone.getName()); response.setZoneName(zone.getName());
response.setMode(mode); response.setMode(mode);

View File

@ -16,8 +16,8 @@
<!-- <!--
Configurable components Configurable components
--> -->
<bean id="ManagementServerExtImpl" class ="com.cloud.server.ManagementServerExtImpl" /> <bean id="management-server" class ="com.cloud.server.ManagementServerExtImpl" />
<bean id="configuration-server" class="com.cloud.server.ConfigurationServerImpl" />
<!-- <!--
Network Elements Network Elements

View File

@ -53,7 +53,7 @@ under the License.
<dao name="Configuration configuration server" class="com.cloud.configuration.dao.ConfigurationDaoImpl"> <dao name="Configuration configuration server" class="com.cloud.configuration.dao.ConfigurationDaoImpl">
<param name="premium">true</param> <param name="premium">true</param>
</dao> </dao>
<adapters key="org.apache.cloudstack.acl.APIAccessChecker"> <adapters key="org.apache.cloudstack.acl.APIChecker">
<adapter name="StaticRoleBasedAPIAccessChecker" class="org.apache.cloudstack.acl.StaticRoleBasedAPIAccessChecker"/> <adapter name="StaticRoleBasedAPIAccessChecker" class="org.apache.cloudstack.acl.StaticRoleBasedAPIAccessChecker"/>
</adapters> </adapters>
<adapters key="com.cloud.agent.manager.allocator.HostAllocator"> <adapters key="com.cloud.agent.manager.allocator.HostAllocator">

284
docs/en-US/autoscale.xml Normal file
View File

@ -0,0 +1,284 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES;
]>
<!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<section id="autoscale">
<title>Configuring AutoScale</title>
<para>AutoScaling allows you to scale your back-end services or application VMs up or down
seamlessly and automatically according to the conditions you define. With AutoScaling enabled,
you can ensure that the number of VMs you are using seamlessly scale up when demand increases,
and automatically decreases when demand subsides. Thus it helps you save compute costs by
terminating underused VMs automatically and launching new VMs when you need them, without the
need for manual intervention.</para>
<para>NetScaler AutoScaling is designed to seamlessly launch or terminate VMs based on
user-defined conditions. Conditions for triggering a scaleup or scaledown action can vary from a
simple use case like monitoring the CPU usage of a server to a complex use case of monitoring a
combination of server's responsiveness and its CPU usage. For example, you can configure
AutoScaling to launch an additional VM whenever CPU usage exceeds 80 percent for 15 minutes, or
to remove a VM whenever CPU usage is less than 20 percent for 30 minutes.</para>
<para>&PRODUCT; uses the NetScaler load balancer to monitor all aspects of a system's health and
work in unison with &PRODUCT; to initiate scale-up or scale-down actions. The supported
NetScaler version is 10.0.</para>
<formalpara>
<title>Prerequisites</title>
<para>Before you configure an AutoScale rule, consider the following:</para>
</formalpara>
<itemizedlist>
<listitem>
<para>Ensure that the necessary template is prepared before configuring AutoScale. When a VM
is deployed by using a template and when it comes up, the application should be up and
running.</para>
<note>
<para>If the application is not running, the NetScaler device considers the VM as
ineffective and continues provisioning the VMs unconditionally until the resource limit is
exhausted.</para>
</note>
</listitem>
<listitem>
<para>Deploy the templates you prepared. Ensure that the applications come up on the first
boot and is ready to take the traffic. Observe the time requires to deploy the template.
Consider this time when you specify the quiet time while configuring AutoScale.</para>
</listitem>
<listitem>
<para>The AutoScale feature supports the SNMP counters that can be used to define conditions
for taking scale up or scale down actions. To monitor the SNMP-based counter, ensure that
the SNMP agent is installed in the template used for creating the AutoScale VMs, and the
SNMP operations work with the configured SNMP community and port by using standard SNMP
managers. For example, see <xref linkend="configure-snmp-rhel"/> to configure SNMP on a RHEL
machine.</para>
</listitem>
<listitem>
<para>Ensure that the endpointe.url parameter present in the Global Settings is set to the
Management Server API URL. For example, http://10.102.102.22:8080/client/api. In a
multi-node Management Server deployment, use the virtual IP address configured in the load
balancer for the management servers cluster. Additionally, ensure that the NetScaler device
has access to this IP address to provide AutoScale support.</para>
<para>If you update the endpointe.url, disable the AutoScale functionality of the load
balancer rules in the system, then enable them back to reflect the changes. For more
information see <xref linkend="update-autoscale"/></para>
</listitem>
<listitem>
<para>If the API Key and Secret Key are regenerated for an AutoScale user, ensure that the
AutoScale functionality of the load balancers that the user participates in are disabled and
then enabled to reflect the configuration changes in the NetScaler.</para>
</listitem>
<listitem>
<para>In an advanced Zone, ensure that at least one VM should be present before configuring a
load balancer rule with AutoScale. Having one VM in the network ensures that the network is
in implemented state for configuring AutoScale.</para>
</listitem>
</itemizedlist>
<formalpara>
<title>Configuration</title>
<para>Specify the following:</para>
</formalpara>
<mediaobject>
<imageobject>
<imagedata fileref="./images/autoscale-config.png"/>
</imageobject>
<textobject>
<phrase>autoscaleateconfig.png: Configuring AutoScale</phrase>
</textobject>
</mediaobject>
<itemizedlist>
<listitem>
<para><emphasis role="bold">Template</emphasis>: A template consists of a base OS image and
application. A template is used to provision the new instance of an application on a scaleup
action. When a VM is deployed from a template, the VM can start taking the traffic from the
load balancer without any admin intervention. For example, if the VM is deployed for a Web
service, it should have the Web server running, the database connected, and so on.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Compute offering</emphasis>: A predefined set of virtual hardware
attributes, including CPU speed, number of CPUs, and RAM size, that the user can select when
creating a new virtual machine instance. Choose one of the compute offerings to be used
while provisioning a VM instance as part of scaleup action.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Min Instance</emphasis>: The minimum number of active VM instances
that is assigned to a load balancing rule. The active VM instances are the application
instances that are up and serving the traffic, and are being load balanced. This parameter
ensures that a load balancing rule has at least the configured number of active VM instances
are available to serve the traffic.</para>
<note>
<para>If an application, such as SAP, running on a VM instance is down for some reason, the
VM is then not counted as part of Min Instance parameter, and the AutoScale feature
initiates a scaleup action if the number of active VM instances is below the configured
value. Similarly, when an application instance comes up from its earlier down state, this
application instance is counted as part of the active instance count and the AutoScale
process initiates a scaledown action when the active instance count breaches the Max
instance value.</para>
</note>
</listitem>
<listitem>
<para><emphasis role="bold">Max Instance</emphasis>: Maximum number of active VM instances
that <emphasis role="bold">should be assigned to </emphasis>a load balancing rule. This
parameter defines the upper limit of active VM instances that can be assigned to a load
balancing rule.</para>
<para>Specifying a large value for the maximum instance parameter might result in provisioning
large number of VM instances, which in turn leads to a single load balancing rule exhausting
the VM instances limit specified at the account or domain level.</para>
<note>
<para>If an application, such as SAP, running on a VM instance is down for some reason, the
VM is not counted as part of Max Instance parameter. So there may be scenarios where the
number of VMs provisioned for a scaleup action might be more than the configured Max
Instance value. Once the application instances in the VMs are up from an earlier down
state, the AutoScale feature starts aligning to the configured Max Instance value.</para>
</note>
</listitem>
</itemizedlist>
<para>Specify the following scale-up and scale-down policies:</para>
<itemizedlist>
<listitem>
<para><emphasis role="bold">Duration</emphasis>: The duration, in seconds, for which the
conditions you specify must be true to trigger a scaleup action. The conditions defined
should hold true for the entire duration you specify for an AutoScale action to be invoked.
</para>
</listitem>
<listitem>
<para><emphasis role="bold">Counter</emphasis>: The performance counters expose the state of
the monitored instances. By default, &PRODUCT; offers four performance counters: Three SNMP
counters and one NetScaler counter. The SNMP counters are Linux User CPU, Linux System CPU,
and Linux CPU Idle. The NetScaler counter is ResponseTime. The root administrator can add
additional counters into &PRODUCT; by using the &PRODUCT; API. </para>
</listitem>
<listitem>
<para><emphasis role="bold">Operator</emphasis>: The following five relational operators are
supported in AutoScale feature: Greater than, Less than, Less than or equal to, Greater than
or equal to, and Equal to.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Threshold</emphasis>: Threshold value to be used for the counter.
Once the counter defined above breaches the threshold value, the AutoScale feature initiates
a scaleup or scaledown action.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Add</emphasis>: Click Add to add the condition.</para>
</listitem>
</itemizedlist>
<para>Additionally, if you want to configure the advanced settings, click Show advanced settings,
and specify the following:</para>
<itemizedlist>
<listitem>
<para><emphasis role="bold">Polling interval</emphasis>: Frequency in which the conditions,
combination of counter, operator and threshold, are to be evaluated before taking a scale up
or down action. The default polling interval is 30 seconds.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Quiet Time</emphasis>: This is the cool down period after an
AutoScale action is initiated. The time includes the time taken to complete provisioning a
VM instance from its template and the time taken by an application to be ready to serve
traffic. This quiet time allows the fleet to come up to a stable state before any action can
take place. The default is 300 seconds.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Destroy VM Grace Period</emphasis>: The duration in seconds, after
a scaledown action is initiated, to wait before the VM is destroyed as part of scaledown
action. This is to ensure graceful close of any pending sessions or transactions being
served by the VM marked for destroy. The default is 120 seconds.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Security Groups</emphasis>: Security groups provide a way to
isolate traffic to the VM instances. A security group is a group of VMs that filter their
incoming and outgoing traffic according to a set of rules, called ingress and egress rules.
These rules filter network traffic according to the IP address that is attempting to
communicate with the VM.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Disk Offerings</emphasis>: A predefined set of disk size for
primary data storage. </para>
</listitem>
<listitem>
<para><emphasis role="bold">SNMP Community</emphasis>: The SNMP community string to be used by
the NetScaler device to query the configured counter value from the provisioned VM
instances. Default is public.</para>
</listitem>
<listitem>
<para><emphasis role="bold">SNMP Port</emphasis>: The port number on which the SNMP agent that
run on the provisioned VMs is listening. Default port is 161. </para>
</listitem>
<listitem>
<para><emphasis role="bold">User</emphasis>: This is the user that the NetScaler device use to
invoke scaleup and scaledown API calls to the cloud. If no option is specified, the user who
configures AutoScaling is applied. Specify another user name to override.</para>
</listitem>
<listitem>
<para><emphasis role="bold">Apply</emphasis>: Click Apply to create the AutoScale
configuration.</para>
</listitem>
</itemizedlist>
<formalpara>
<title>Disabling and Enabling an AutoScale Configuration</title>
<para>If you want to perform any maintenance operation on the AutoScale VM instances, disable
the AutoScale configuration. When the AutoScale configuration is disabled, no scaleup or
scaledown action is performed. You can use this downtime for the maintenance activities. To
disable the AutoScale configuration, click the Disable AutoScale<inlinemediaobject>
<imageobject>
<imagedata fileref="./images/enable-disable-autoscale.png"/>
</imageobject>
<textobject>
<phrase>EnableDisable.png: button to enable or disable AutoScale.</phrase>
</textobject>
</inlinemediaobject>button.</para>
</formalpara>
<para>The button toggles between enable and disable, depending on whether AutoScale is currently
enabled or not. After the maintenance operations are done, you can enable the AutoScale
configuration back. To enable, open the AutoScale configuration page again, then click the
Enable AutoScale<inlinemediaobject>
<imageobject>
<imagedata fileref="./images/enable-disable-autoscale.png"/>
</imageobject>
<textobject>
<phrase>EnableDisable.png: button to enable or disable AutoScale.</phrase>
</textobject>
</inlinemediaobject>button.</para>
<formalpara id="update-autoscale">
<title>Updating an AutoScale Configuration</title>
<para>You can update the various parameters and add or delete the conditions in a scaleup or
scaledown rule. Before you update an AutoScale configuration, ensure that you disable the
AutoScale load balancer rule by clicking the Disable AutoScale button.</para>
</formalpara>
<para>After you modify the required AutoScale parameters, click Apply. To apply the new AutoScale
policies, open the AutoScale configuration page again, then click the Enable AutoScale
button.</para>
<formalpara>
<title>Runtime Considerations</title>
<para/>
</formalpara>
<itemizedlist>
<listitem>
<para>An administrator should not assign a VM to a load balancing rule which is configured for
AutoScale.</para>
</listitem>
<listitem>
<para>Before a VM provisioning is completed if NetScaler is shutdown or restarted, the
provisioned VM cannot be a part of the load balancing rule though the intent was to assign
it to a load balancing rule. To workaround, rename the AutoScale provisioned VMs based on
the rule name or ID so at any point of time the VMs can be reconciled to its load balancing
rule.</para>
</listitem>
<listitem>
<para>Making API calls outside the context of AutoScale, such as destroyVM, on an autoscaled
VM leaves the load balancing configuration in an inconsistent state. Though VM is destroyed
from the load balancer rule, NetScaler continues to show the VM as a service assigned to a
rule.</para>
</listitem>
</itemizedlist>
</section>

View File

@ -0,0 +1,46 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES;
]>
<!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<section id="building-marvin">
<title>Building and Installing Marvin</title>
<para>Marvin is built with Maven and is dependent on APIdoc. To build it do the following in the root tree of &PRODUCT;:</para>
<programlisting>mvn -P developer -l :cloud-apidoc</programlisting>
<programlisting>mvn -P developer -l :cloud-marvin</programlisting>
<para>If successfull the build will have created the cloudstackAPI Python package under tools/marvin/marvin/cloudstackAPI as well as a gziped Marvin package under tools/marvin dist. To install the Python Marvin module do the following in tools/marvin:</para>
<programlisting>sudo python ./setup.py install</programlisting>
<para>The dependencies will be downloaded the Python module installed and you should be able to use Marvin in Python. Check that you can import the module before starting to use it.</para>
<programlisting>$ python
Python 2.7.3 (default, Nov 17 2012, 19:54:34)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import marvin
>>> from marvin.cloudstackAPI import *
>>> </programlisting>
<para>You could also install it using <emphasis>pip</emphasis> or <emphasis>easy_install</emphasis> using the local distribution package in tools/marvin/dist :</para>
<programlisting>pip install tools/marvin/dist/Marvin-0.1.0.tar.gz</programlisting>
<para>Or:</para>
<programlisting>easy_install tools/marvin/dist/Marvin-0.1.0.tar.gz</programlisting>
</section>

View File

@ -0,0 +1,86 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES;
]>
<!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<section id="configure-snmp-rhel">
<title>Configuring SNMP Community String on a RHEL Server</title>
<para>The SNMP Community string is similar to a user id or password that provides access to a
network device, such as router. This string is sent along with all SNMP requests. If the
community string is correct, the device responds with the requested information. If the
community string is incorrect, the device discards the request and does not respond.</para>
<para>The NetScaler device uses SNMP to communicate with the VMs. You must install SNMP and
configure SNMP Community string for a secure communication between the NetScaler device and the
RHEL machine.</para>
<orderedlist>
<listitem>
<para>Ensure that you installed SNMP on RedHat. If not, run the following command:</para>
<screen>yum install net-snmp-utils</screen>
</listitem>
<listitem>
<para>Edit the /etc/snmp/snmpd.conf file to allow the SNMP polling from the NetScaler
device.</para>
<orderedlist>
<listitem>
<para>Map the community name into a security name (local and mynetwork, depending on where
the request is coming from):</para>
<note>
<para>Use a strong password instead of public when you edit the following table.</para>
</note>
<screen># sec.name source community
com2sec local localhost public
com2sec mynetwork 0.0.0.0 public</screen>
<note>
<para>Setting to 0.0.0.0 allows all IPs to poll the NetScaler server.</para>
</note>
</listitem>
<listitem>
<para>Map the security names into group names: </para>
<screen># group.name sec.model sec.name
group MyRWGroup v1 local
group MyRWGroup v2c local
group MyROGroup v1 mynetwork
group MyROGroup v2c mynetwork</screen>
</listitem>
<listitem>
<para>Create a view to allow the groups to have the permission to:</para>
<screen>incl/excl subtree mask view all included .1 </screen>
</listitem>
<listitem>
<para>Grant access with different write permissions to the two groups to the view you
created.</para>
<screen># context sec.model sec.level prefix read write notif
access MyROGroup "" any noauth exact all none none
access MyRWGroup "" any noauth exact all all all </screen>
</listitem>
</orderedlist>
</listitem>
<listitem>
<para>Unblock SNMP in iptables.</para>
<screen>iptables -A INPUT -p udp --dport 161 -j ACCEPT</screen>
</listitem>
<listitem>
<para>Start the SNMP service:</para>
<screen>service snmpd start</screen>
</listitem>
<listitem>
<para>Ensure that the SNMP service is started automatically during the system startup:</para>
<screen>chkconfig snmpd on</screen>
</listitem>
</orderedlist>
</section>

View File

@ -3,30 +3,31 @@
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent"> <!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES; %BOOK_ENTITIES;
]> ]>
<!-- Licensed to the Apache Software Foundation (ASF) under one <!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file or more contributor license agreements. See the NOTICE file
distributed with this work for additional information distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
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
Unless required by applicable law or agreed to in writing, "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
software distributed under the License is distributed on an KIND, either express or implied. See the License for the
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY specific language governing permissions and limitations
KIND, either express or implied. See the License for the under the License.
specific language governing permissions and limitations -->
under the License.
-->
<section id="external-firewalls-and-load-balancers"> <section id="external-firewalls-and-load-balancers">
<title>External Firewalls and Load Balancers</title> <title>External Firewalls and Load Balancers</title>
<para>&PRODUCT; is capable of replacing its Virtual Router with an external Juniper SRX device and an optional external NetScaler or F5 load balancer for gateway and load balancing services. In this case, the VMs use the SRX as their gateway.</para> <para>&PRODUCT; is capable of replacing its Virtual Router with an external Juniper SRX device and
<xi:include href="using-netscaler-load-balancers.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> an optional external NetScaler or F5 load balancer for gateway and load balancing services. In
<xi:include href="configure-snmp-rhel.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> this case, the VMs use the SRX as their gateway.</para>
<xi:include href="initial-setup-of-external-firewalls-loadbalancers.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> <xi:include href="using-netscaler-load-balancers.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="ongoing-configuration-of-external-firewalls-loadbalancer.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> <xi:include href="configure-snmp-rhel.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="autoscale.xml" xmlns:xi="http://www.w3.org/2001/XInclude" /> <xi:include href="initial-setup-of-external-firewalls-loadbalancers.xml"
xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="ongoing-configuration-of-external-firewalls-loadbalancer.xml"
xmlns:xi="http://www.w3.org/2001/XInclude"/>
<xi:include href="autoscale.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
</section> </section>

View File

@ -29,4 +29,5 @@
<para>Marvin's complete documenation is on the wiki at <ulink url="https://cwiki.apache.org/CLOUDSTACK/testing-with-python.html">https://cwiki.apache.org/CLOUDSTACK/testing-with-python.html</ulink></para> <para>Marvin's complete documenation is on the wiki at <ulink url="https://cwiki.apache.org/CLOUDSTACK/testing-with-python.html">https://cwiki.apache.org/CLOUDSTACK/testing-with-python.html</ulink></para>
<para>The source code is located at <emphasis>tools/marvin</emphasis></para> <para>The source code is located at <emphasis>tools/marvin</emphasis></para>
</note> </note>
<xi:include href="building-marvin.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</section> </section>

View File

@ -0,0 +1,46 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES;
]>
<!-- Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<section id="ongoing-configuration-of-external-firewalls-loadbalancer">
<title>Ongoing Configuration of External Firewalls and Load Balancers</title>
<para>Additional user actions (e.g. setting a port forward) will cause further programming of the
firewall and load balancer. A user may request additional public IP addresses and forward
traffic received at these IPs to specific VMs. This is accomplished by enabling static NAT for a
public IP address, assigning the IP to a VM, and specifying a set of protocols and port ranges
to open. When a static NAT rule is created, &PRODUCT; programs the zone's external firewall with
the following objects:</para>
<itemizedlist>
<listitem>
<para>A static NAT rule that maps the public IP address to the private IP address of a
VM.</para>
</listitem>
<listitem>
<para>A security policy that allows traffic within the set of protocols and port ranges that
are specified.</para>
</listitem>
<listitem>
<para>A firewall filter counter that measures the number of bytes of incoming traffic to the
public IP.</para>
</listitem>
</itemizedlist>
<para>The number of incoming and outgoing bytes through source NAT, static NAT, and load balancing
rules is measured and saved on each external element. This data is collected on a regular basis
and stored in the &PRODUCT; database.</para>
</section>

View File

@ -26,4 +26,5 @@
<title>System Service Offerings</title> <title>System Service Offerings</title>
<para>System service offerings provide a choice of CPU speed, number of CPUs, tags, and RAM size, just as other service offerings do. But rather than being used for virtual machine instances and exposed to users, system service offerings are used to change the default properties of virtual routers, console proxies, and other system VMs. System service offerings are visible only to the &PRODUCT; root administrator. &PRODUCT; provides default system service offerings. The &PRODUCT; root administrator can create additional custom system service offerings.</para> <para>System service offerings provide a choice of CPU speed, number of CPUs, tags, and RAM size, just as other service offerings do. But rather than being used for virtual machine instances and exposed to users, system service offerings are used to change the default properties of virtual routers, console proxies, and other system VMs. System service offerings are visible only to the &PRODUCT; root administrator. &PRODUCT; provides default system service offerings. The &PRODUCT; root administrator can create additional custom system service offerings.</para>
<para>When &PRODUCT; creates a virtual router for a guest network, it uses default settings which are defined in the system service offering associated with the network offering. You can upgrade the capabilities of the virtual router by applying a new network offering that contains a different system service offering. All virtual routers in that network will begin using the settings from the new service offering.</para> <para>When &PRODUCT; creates a virtual router for a guest network, it uses default settings which are defined in the system service offering associated with the network offering. You can upgrade the capabilities of the virtual router by applying a new network offering that contains a different system service offering. All virtual routers in that network will begin using the settings from the new service offering.</para>
<xi:include href="creating-system-service-offerings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</section> </section>

View File

@ -1,13 +1,12 @@
package org.apache.cloudstack.storage.db; package org.apache.cloudstack.storage.db;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event;
import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State;
import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericDaoBase;
@Component
public class ObjectInDataStoreDaoImpl extends GenericDaoBase<ObjectInDataStoreVO, Long> implements ObjectInDataStoreDao { public class ObjectInDataStoreDaoImpl extends GenericDaoBase<ObjectInDataStoreVO, Long> implements ObjectInDataStoreDao {
@Override @Override

View File

@ -34,105 +34,67 @@ import javax.naming.ConfigurationException;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.cloud.server.ManagementServer;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.PluggableService; import com.cloud.utils.component.PluggableService;
// This is the default API access checker that grab's the user's account // This is the default API access checker that grab's the user's account
// based on the account type, access is granted // based on the account type, access is granted
@Component @Component
@Local(value=APIAccessChecker.class) @Local(value=APIChecker.class)
public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIAccessChecker { public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker {
protected static final Logger s_logger = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); protected static final Logger s_logger = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class);
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;
@Inject AccountManager _accountMgr; private static Map<RoleType, Set<String>> s_roleBasedApisMap =
new HashMap<RoleType, Set<String>>();
@Inject List<PluggableService> _services; @Inject List<PluggableService> _services;
private static Set<String> s_userCommands = null;
private static Set<String> s_resellerCommands = null; // AKA domain-admin
private static Set<String> s_adminCommands = null;
private static Set<String> s_resourceDomainAdminCommands = null;
private static Set<String> s_allCommands = null;
protected StaticRoleBasedAPIAccessChecker() { protected StaticRoleBasedAPIAccessChecker() {
super(); super();
s_allCommands = new HashSet<String>(); for (RoleType roleType: RoleType.values())
s_userCommands = new HashSet<String>(); s_roleBasedApisMap.put(roleType, new HashSet<String>());
s_resellerCommands = new HashSet<String>();
s_adminCommands = new HashSet<String>();
s_resourceDomainAdminCommands = new HashSet<String>();
} }
@Override @Override
public boolean canAccessAPI(RoleType roleType, String commandName) public boolean checkAccess(RoleType roleType, String commandName)
throws PermissionDeniedException { throws PermissionDeniedException {
boolean isAllowed = s_roleBasedApisMap.get(roleType).contains(commandName);
boolean commandExists = s_allCommands.contains(commandName); if (!isAllowed) {
boolean commandAccessible = false; throw new PermissionDeniedException("The API does not exist or is blacklisted. Role type=" + roleType.toString() + " is not allowed to request the api: " + commandName);
if (commandExists) {
switch (roleType) {
case Admin:
commandAccessible = s_adminCommands.contains(commandName);
break;
case DomainAdmin:
commandAccessible = s_resellerCommands.contains(commandName);
break;
case ResourceAdmin:
commandAccessible = s_resourceDomainAdminCommands.contains(commandName);
break;
case User:
commandAccessible = s_userCommands.contains(commandName);
break;
}
} }
return commandExists && commandAccessible; return isAllowed;
} }
@Override @Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params); super.configure(name, params);
_services.add((PluggableService) ComponentContext.getComponent(ManagementServer.Name));
// Read command properties files to build the static map per role.
Map<String, String> configPropertiesMap = new HashMap<String, String>();
for (PluggableService service : _services) { for (PluggableService service : _services) {
configPropertiesMap.putAll(service.getProperties()); processConfigFiles(service.getProperties(), service.getClass().toString());
s_logger.info("Processed role based acl for: " + service.toString());
} }
processConfigFiles(configPropertiesMap);
return true; return true;
} }
private void processConfigFiles(Map<String, String> config) { private void processConfigFiles(Map<String, String> configMap, String service) {
for (Map.Entry<String, String> entry: config.entrySet()) { for (Map.Entry<String, String> entry: configMap.entrySet()) {
String apiName = entry.getKey(); String apiName = entry.getKey();
String roleMask = entry.getValue(); String roleMask = entry.getValue();
try { try {
short cmdPermissions = Short.parseShort(roleMask); short cmdPermissions = Short.parseShort(roleMask);
if ((cmdPermissions & Admin.getValue()) != 0) { for (RoleType roleType: RoleType.values()) {
s_adminCommands.add(apiName); if ((cmdPermissions & roleType.getValue()) != 0)
} s_roleBasedApisMap.get(roleType).add(apiName);
if ((cmdPermissions & ResourceAdmin.getValue()) != 0) {
s_resourceDomainAdminCommands.add(apiName);
}
if ((cmdPermissions & DomainAdmin.getValue()) != 0) {
s_resellerCommands.add(apiName);
}
if ((cmdPermissions & User.getValue()) != 0) {
s_userCommands.add(apiName);
} }
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
s_logger.info("Malformed commands.properties permissions value, for entry: " + entry.toString()); s_logger.info("Malformed getProperties() value for service: " + service
+ " for entry: " + entry.toString());
} }
} }
s_allCommands.addAll(s_adminCommands);
s_allCommands.addAll(s_resourceDomainAdminCommands);
s_allCommands.addAll(s_userCommands);
s_allCommands.addAll(s_resellerCommands);
} }
} }

View File

@ -16,12 +16,12 @@
// under the License. // under the License.
package org.apache.cloudstack.api.command.user.discovery; package org.apache.cloudstack.api.command.user.discovery;
import com.cloud.user.Account;
import com.cloud.user.UserContext; import com.cloud.user.UserContext;
import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.PlugService; import org.apache.cloudstack.api.PlugService;
import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
@ -30,8 +30,8 @@ import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
@APICommand(name = "listApis", responseObject = ApiDiscoveryResponse.class, description = "lists all available apis on the server, provided by Api Discovery plugin", since = "4.1.0") @APICommand(name = "listApis", responseObject = ApiDiscoveryResponse.class, description = "lists all available apis on the server, provided by the Api Discovery plugin", since = "4.1.0")
public class ListApisCmd extends BaseListCmd { public class ListApisCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(ListApisCmd.class.getName()); public static final Logger s_logger = Logger.getLogger(ListApisCmd.class.getName());
private static final String s_name = "listapisresponse"; private static final String s_name = "listapisresponse";
@ -39,14 +39,16 @@ public class ListApisCmd extends BaseListCmd {
@PlugService @PlugService
ApiDiscoveryService _apiDiscoveryService; ApiDiscoveryService _apiDiscoveryService;
@Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="API name")
private String name;
@Override @Override
public void execute() throws ServerApiException { public void execute() throws ServerApiException {
if (_apiDiscoveryService != null) { if (_apiDiscoveryService != null) {
Account caller = UserContext.current().getCaller();
RoleType roleType = _accountService.getRoleType(UserContext.current().getCaller()); RoleType roleType = _accountService.getRoleType(UserContext.current().getCaller());
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) _apiDiscoveryService.listApis(roleType); ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) _apiDiscoveryService.listApis(roleType, name);
if (response == null) { if (response == null) {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Api Discovery plugin was unable to find and process any apis"); throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Api Discovery plugin was unable to find an api by that name or process any apis");
} }
response.setResponseName(getCommandName()); response.setResponseName(getCommandName());
this.setResponseObject(response); this.setResponseObject(response);
@ -57,4 +59,10 @@ public class ListApisCmd extends BaseListCmd {
public String getCommandName() { public String getCommandName() {
return s_name; return s_name;
} }
@Override
public long getEntityOwnerId() {
// no owner is needed for list command
return 0;
}
} }

View File

@ -16,18 +16,15 @@
// under the License. // under the License.
package org.apache.cloudstack.api.response; package org.apache.cloudstack.api.response;
import com.cloud.user.Account;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import com.cloud.serializer.Param; import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@EntityReference(value = Account.class)
public class ApiDiscoveryResponse extends BaseResponse { public class ApiDiscoveryResponse extends BaseResponse {
@SerializedName(ApiConstants.NAME) @Param(description="the name of the api command") @SerializedName(ApiConstants.NAME) @Param(description="the name of the api command")
private String name; private String name;
@ -41,11 +38,18 @@ public class ApiDiscoveryResponse extends BaseResponse {
@SerializedName(ApiConstants.IS_ASYNC) @Param(description="true if api is asynchronous") @SerializedName(ApiConstants.IS_ASYNC) @Param(description="true if api is asynchronous")
private Boolean isAsync; private Boolean isAsync;
@SerializedName("related") @Param(description="comma separated related apis")
private String related;
@SerializedName(ApiConstants.PARAMS) @Param(description="the list params the api accepts", responseObject = ApiParameterResponse.class) @SerializedName(ApiConstants.PARAMS) @Param(description="the list params the api accepts", responseObject = ApiParameterResponse.class)
private Set<ApiParameterResponse> params; private Set<ApiParameterResponse> params;
@SerializedName(ApiConstants.RESPONSE) @Param(description="api response fields", responseObject = ApiResponseResponse.class)
private Set<ApiResponseResponse> apiResponse;
public ApiDiscoveryResponse(){ public ApiDiscoveryResponse(){
params = new HashSet<ApiParameterResponse>(); params = new HashSet<ApiParameterResponse>();
apiResponse = new HashSet<ApiResponseResponse>();
isAsync = false; isAsync = false;
} }
@ -65,6 +69,18 @@ public class ApiDiscoveryResponse extends BaseResponse {
this.isAsync = isAsync; this.isAsync = isAsync;
} }
public String getRelated() {
return related;
}
public void setRelated(String related) {
this.related = related;
}
public Set<ApiParameterResponse> getParams() {
return params;
}
public void setParams(Set<ApiParameterResponse> params) { public void setParams(Set<ApiParameterResponse> params) {
this.params = params; this.params = params;
} }
@ -72,4 +88,8 @@ public class ApiDiscoveryResponse extends BaseResponse {
public void addParam(ApiParameterResponse param) { public void addParam(ApiParameterResponse param) {
this.params.add(param); this.params.add(param);
} }
public void addApiResponse(ApiResponseResponse apiResponse) {
this.apiResponse.add(apiResponse);
}
} }

View File

@ -40,6 +40,9 @@ public class ApiParameterResponse extends BaseResponse {
@SerializedName(ApiConstants.SINCE) @Param(description="version of CloudStack the api was introduced in") @SerializedName(ApiConstants.SINCE) @Param(description="version of CloudStack the api was introduced in")
private String since; private String since;
@SerializedName("related") @Param(description="comma separated related apis to get the parameter")
private String related;
public ApiParameterResponse(){ public ApiParameterResponse(){
} }
@ -67,4 +70,12 @@ public class ApiParameterResponse extends BaseResponse {
this.since = since; this.since = since;
} }
public String getRelated() {
return related;
}
public void setRelated(String related) {
this.related = related;
}
} }

View File

@ -0,0 +1,45 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.response;
import org.apache.cloudstack.api.ApiConstants;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.BaseResponse;
public class ApiResponseResponse extends BaseResponse {
@SerializedName(ApiConstants.NAME) @Param(description="the name of the api response field")
private String name;
@SerializedName(ApiConstants.DESCRIPTION) @Param(description="description of the api response field")
private String description;
@SerializedName(ApiConstants.TYPE) @Param(description="response field type")
private String type;
public void setName(String name) {
this.name = name;
}
public void setDescription(String description) {
this.description = description;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -22,5 +22,5 @@ import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
public interface ApiDiscoveryService extends PluggableService { public interface ApiDiscoveryService extends PluggableService {
ListResponse<? extends BaseResponse> listApis(RoleType roleType); ListResponse<? extends BaseResponse> listApis(RoleType roleType, String apiName);
} }

View File

@ -16,8 +16,13 @@
// under the License. // under the License.
package org.apache.cloudstack.discovery; package org.apache.cloudstack.discovery;
import com.cloud.utils.PropertiesUtil; import com.cloud.serializer.Param;
import com.cloud.server.ManagementServer;
import com.cloud.utils.ReflectUtil; import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.PluggableService;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.BaseCmd;
@ -27,45 +32,77 @@ import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ApiDiscoveryResponse; import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
import org.apache.cloudstack.api.response.ApiParameterResponse; import org.apache.cloudstack.api.response.ApiParameterResponse;
import org.apache.cloudstack.api.response.ApiResponseResponse;
import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ListResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import javax.ejb.Local; import javax.ejb.Local;
import javax.inject.Inject;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@Component
@Local(value = ApiDiscoveryService.class) @Local(value = ApiDiscoveryService.class)
public class ApiDiscoveryServiceImpl implements ApiDiscoveryService { public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
private static final Logger s_logger = Logger.getLogger(ApiDiscoveryServiceImpl.class); private static final Logger s_logger = Logger.getLogger(ApiDiscoveryServiceImpl.class);
private ListResponse<ApiDiscoveryResponse> _discoveryResponse = new ListResponse<ApiDiscoveryResponse>(); private static Map<RoleType, List<ApiDiscoveryResponse>> _roleTypeDiscoveryResponseListMap;
private Map<String, Class<?>> _apiNameCmdClassMap = new HashMap<String, Class<?>>(); private static Map<String, ApiDiscoveryResponse> _apiNameDiscoveryResponseMap =
new HashMap<String, ApiDiscoveryResponse>();
private static Map<String, List<RoleType>> _apiNameRoleTypeListMap = null;
@Inject List<PluggableService> _services;
protected ApiDiscoveryServiceImpl() { protected ApiDiscoveryServiceImpl() {
super(); super();
generateApiNameCmdClassMap(); if (_roleTypeDiscoveryResponseListMap == null) {
cacheListApiResponse(); long startTime = System.nanoTime();
_roleTypeDiscoveryResponseListMap = new HashMap<RoleType, List<ApiDiscoveryResponse>>();
for (RoleType roleType: RoleType.values())
_roleTypeDiscoveryResponseListMap.put(roleType, new ArrayList<ApiDiscoveryResponse>());
cacheResponseMap();
long endTime = System.nanoTime();
s_logger.info("Api Discovery Service: Annotation, docstrings, api relation graph processed in " + (endTime - startTime) / 1000000.0 + " ms");
}
} }
private void generateApiNameCmdClassMap() { private Map<String, List<RoleType>> getApiNameRoleTypeListMap() {
Map<String, List<RoleType>> apiNameRoleTypeMap = new HashMap<String, List<RoleType>>();
_services.add((PluggableService) ComponentContext.getComponent(ManagementServer.Name));
for (PluggableService service : _services) {
for (Map.Entry<String, String> entry: service.getProperties().entrySet()) {
String apiName = entry.getKey();
String roleMask = entry.getValue();
try {
short cmdPermissions = Short.parseShort(roleMask);
if (!apiNameRoleTypeMap.containsKey(apiName))
apiNameRoleTypeMap.put(apiName, new ArrayList<RoleType>());
for (RoleType roleType: RoleType.values()) {
if ((cmdPermissions & roleType.getValue()) != 0)
apiNameRoleTypeMap.get(apiName).add(roleType);
}
} catch (NumberFormatException nfe) {
}
}
}
return apiNameRoleTypeMap;
}
private void cacheResponseMap() {
Set<Class<?>> cmdClasses = ReflectUtil.getClassesWithAnnotation(APICommand.class, Set<Class<?>> cmdClasses = ReflectUtil.getClassesWithAnnotation(APICommand.class,
new String[]{"org.apache.cloudstack.api", "com.cloud.api"}); new String[]{"org.apache.cloudstack.api", "com.cloud.api"});
for(Class<?> cmdClass: cmdClasses) Map<String, List<String>> responseApiNameListMap = new HashMap<String, List<String>>();
_apiNameCmdClassMap.put(cmdClass.getAnnotation(APICommand.class).name(), cmdClass);
}
private void cacheListApiResponse() { for(Class<?> cmdClass: cmdClasses) {
List<ApiDiscoveryResponse> apiDiscoveryResponses = new ArrayList<ApiDiscoveryResponse>();
for(String key: _apiNameCmdClassMap.keySet()) {
Class<?> cmdClass = _apiNameCmdClassMap.get(key);
APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class); APICommand apiCmdAnnotation = cmdClass.getAnnotation(APICommand.class);
if (apiCmdAnnotation == null) if (apiCmdAnnotation == null)
apiCmdAnnotation = cmdClass.getSuperclass().getAnnotation(APICommand.class); apiCmdAnnotation = cmdClass.getSuperclass().getAnnotation(APICommand.class);
@ -74,10 +111,33 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
|| apiCmdAnnotation.name().isEmpty()) || apiCmdAnnotation.name().isEmpty())
continue; continue;
String apiName = apiCmdAnnotation.name();
String responseName = apiCmdAnnotation.responseObject().getName();
if (!responseName.contains("SuccessResponse")) {
if (!responseApiNameListMap.containsKey(responseName))
responseApiNameListMap.put(responseName, new ArrayList<String>());
responseApiNameListMap.get(responseName).add(apiName);
}
ApiDiscoveryResponse response = new ApiDiscoveryResponse(); ApiDiscoveryResponse response = new ApiDiscoveryResponse();
response.setName(apiCmdAnnotation.name()); response.setName(apiName);
response.setDescription(apiCmdAnnotation.description()); response.setDescription(apiCmdAnnotation.description());
response.setSince(apiCmdAnnotation.since()); if (!apiCmdAnnotation.since().isEmpty())
response.setSince(apiCmdAnnotation.since());
response.setRelated(responseName);
Field[] responseFields = apiCmdAnnotation.responseObject().getDeclaredFields();
for(Field responseField: responseFields) {
SerializedName serializedName = responseField.getAnnotation(SerializedName.class);
if(serializedName != null) {
ApiResponseResponse responseResponse = new ApiResponseResponse();
responseResponse.setName(serializedName.value());
Param param = responseField.getAnnotation(Param.class);
if (param != null)
responseResponse.setDescription(param.description());
responseResponse.setType(responseField.getType().getSimpleName().toLowerCase());
response.addApiResponse(responseResponse);
}
}
Field[] fields = ReflectUtil.getAllFieldsForClass(cmdClass, Field[] fields = ReflectUtil.getAllFieldsForClass(cmdClass,
new Class<?>[] {BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class}); new Class<?>[] {BaseCmd.class, BaseAsyncCmd.class, BaseAsyncCreateCmd.class});
@ -96,22 +156,74 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
ApiParameterResponse paramResponse = new ApiParameterResponse(); ApiParameterResponse paramResponse = new ApiParameterResponse();
paramResponse.setName(parameterAnnotation.name()); paramResponse.setName(parameterAnnotation.name());
paramResponse.setDescription(parameterAnnotation.description()); paramResponse.setDescription(parameterAnnotation.description());
paramResponse.setType(parameterAnnotation.type().toString()); paramResponse.setType(parameterAnnotation.type().toString().toLowerCase());
paramResponse.setLength(parameterAnnotation.length()); paramResponse.setLength(parameterAnnotation.length());
paramResponse.setRequired(parameterAnnotation.required()); paramResponse.setRequired(parameterAnnotation.required());
paramResponse.setSince(parameterAnnotation.since()); if (!parameterAnnotation.since().isEmpty())
paramResponse.setSince(parameterAnnotation.since());
paramResponse.setRelated(parameterAnnotation.entityType()[0].getName());
response.addParam(paramResponse); response.addParam(paramResponse);
} }
} }
response.setObjectName("apis"); response.setObjectName("api");
apiDiscoveryResponses.add(response); _apiNameDiscoveryResponseMap.put(apiName, response);
}
for (String apiName: _apiNameDiscoveryResponseMap.keySet()) {
ApiDiscoveryResponse response = _apiNameDiscoveryResponseMap.get(apiName);
Set<ApiParameterResponse> processedParams = new HashSet<ApiParameterResponse>();
for (ApiParameterResponse param: response.getParams()) {
if (responseApiNameListMap.containsKey(param.getRelated())) {
List<String> relatedApis = responseApiNameListMap.get(param.getRelated());
param.setRelated(StringUtils.join(relatedApis, ","));
} else {
param.setRelated(null);
}
processedParams.add(param);
}
response.setParams(processedParams);
if (responseApiNameListMap.containsKey(response.getRelated())) {
List<String> relatedApis = responseApiNameListMap.get(response.getRelated());
relatedApis.remove(apiName);
response.setRelated(StringUtils.join(relatedApis, ","));
} else {
response.setRelated(null);
}
_apiNameDiscoveryResponseMap.put(apiName, response);
} }
_discoveryResponse.setResponses(apiDiscoveryResponses);
} }
@Override @Override
public ListResponse<? extends BaseResponse> listApis(RoleType roleType) { public ListResponse<? extends BaseResponse> listApis(RoleType roleType, String name) {
return _discoveryResponse; // Creates roles based response list cache the first time listApis is called
// Due to how adapters work, this cannot be done when mgmt loads
if (_apiNameRoleTypeListMap == null) {
long startTime = System.nanoTime();
_apiNameRoleTypeListMap = getApiNameRoleTypeListMap();
for (Map.Entry<String, List<RoleType>> entry: _apiNameRoleTypeListMap.entrySet()) {
String apiName = entry.getKey();
for (RoleType roleTypeInList: entry.getValue()) {
_roleTypeDiscoveryResponseListMap.get(roleTypeInList).add(
_apiNameDiscoveryResponseMap.get(apiName));
}
}
long endTime = System.nanoTime();
s_logger.info("Api Discovery Service: List apis cached in " + (endTime - startTime) / 1000000.0 + " ms");
}
ListResponse<ApiDiscoveryResponse> response = new ListResponse<ApiDiscoveryResponse>();
if (name != null) {
if (!_apiNameDiscoveryResponseMap.containsKey(name))
return null;
List<ApiDiscoveryResponse> singleResponse = new ArrayList<ApiDiscoveryResponse>();
singleResponse.add(_apiNameDiscoveryResponseMap.get(name));
response.setResponses(singleResponse);
} else {
response.setResponses(_roleTypeDiscoveryResponseListMap.get(roleType));
}
return response;
} }
@Override @Override

View File

@ -40,7 +40,6 @@
<module>hypervisors/ovm</module> <module>hypervisors/ovm</module>
<module>hypervisors/xen</module> <module>hypervisors/xen</module>
<module>hypervisors/kvm</module> <module>hypervisors/kvm</module>
<module>hypervisors/simulator</module>
<module>network-elements/elastic-loadbalancer</module> <module>network-elements/elastic-loadbalancer</module>
<module>network-elements/ovs</module> <module>network-elements/ovs</module>
<module>network-elements/nicira-nvp</module> <module>network-elements/nicira-nvp</module>

View File

@ -69,7 +69,6 @@ import com.cloud.utils.NumbersUtil;
import com.cloud.utils.ReflectUtil; import com.cloud.utils.ReflectUtil;
import com.cloud.utils.exception.CSExceptionErrorCode; import com.cloud.utils.exception.CSExceptionErrorCode;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.uuididentity.dao.IdentityDao;
@Component @Component
public class ApiDispatcher { public class ApiDispatcher {
@ -79,8 +78,6 @@ public class ApiDispatcher {
@Inject AsyncJobManager _asyncMgr = null; @Inject AsyncJobManager _asyncMgr = null;
@Inject AccountManager _accountMgr = null; @Inject AccountManager _accountMgr = null;
@Inject EntityManager _entityMgr = null; @Inject EntityManager _entityMgr = null;
@Inject IdentityDao _identityDao = null;
@Inject ConfigurationDao _configDao = null;
private static ApiDispatcher s_instance; private static ApiDispatcher s_instance;
@ -90,20 +87,13 @@ public class ApiDispatcher {
protected ApiDispatcher() { protected ApiDispatcher() {
super(); super();
Map<String, String> configs = _configDao.getConfiguration();
String strSnapshotLimit = configs.get(Config.ConcurrentSnapshotsThresholdPerHost.key());
if (strSnapshotLimit != null) {
Long snapshotLimit = NumbersUtil.parseLong(strSnapshotLimit, 1L);
if (snapshotLimit <= 0) {
s_logger.debug("Global config parameter " + Config.ConcurrentSnapshotsThresholdPerHost.toString()
+ " is less or equal 0; defaulting to unlimited");
} else {
_createSnapshotQueueSizeLimit = snapshotLimit;
}
}
s_instance = this; s_instance = this;
} }
public void setCreateSnapshotQueueSizeLimit(Long snapshotLimit) {
_createSnapshotQueueSizeLimit = snapshotLimit;
}
public void dispatchCreateCmd(BaseAsyncCreateCmd cmd, Map<String, String> params) { public void dispatchCreateCmd(BaseAsyncCreateCmd cmd, Map<String, String> params) {
processParameters(cmd, params); processParameters(cmd, params);
@ -701,8 +691,4 @@ public class ApiDispatcher {
throw new CloudRuntimeException("Internal error at plugService for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]"); throw new CloudRuntimeException("Internal error at plugService for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
} }
} }
public static Long getIdentiyId(String tableName, String token) {
return s_instance._identityDao.getIdentityId(tableName, token);
}
} }

View File

@ -2791,11 +2791,6 @@ public class ApiResponseHelper implements ResponseGenerator {
return response; return response;
} }
@Override
public Long getIdentiyId(String tableName, String token) {
return ApiDispatcher.getIdentiyId(tableName, token);
}
@Override @Override
public ResourceTagResponse createResourceTagResponse(ResourceTag resourceTag, boolean keyValueOnly) { public ResourceTagResponse createResourceTagResponse(ResourceTag resourceTag, boolean keyValueOnly) {
ResourceTagJoinVO rto = ApiDBUtils.newResourceTagView(resourceTag); ResourceTagJoinVO rto = ApiDBUtils.newResourceTagView(resourceTag);

View File

@ -51,7 +51,7 @@ import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import org.apache.cloudstack.acl.APIAccessChecker; import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCmd;
@ -128,6 +128,7 @@ import com.cloud.user.UserAccount;
import com.cloud.user.UserContext; import com.cloud.user.UserContext;
import com.cloud.user.UserVO; import com.cloud.user.UserVO;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.ReflectUtil; import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils; import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentContext;
@ -136,7 +137,6 @@ import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction; import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CSExceptionErrorCode; import com.cloud.utils.exception.CSExceptionErrorCode;
import com.cloud.uuididentity.dao.IdentityDao;
@Component @Component
public class ApiServer implements HttpRequestHandler { public class ApiServer implements HttpRequestHandler {
@ -153,9 +153,8 @@ public class ApiServer implements HttpRequestHandler {
@Inject private ConfigurationDao _configDao; @Inject private ConfigurationDao _configDao;
@Inject List<PluggableService> _pluggableServices; @Inject List<PluggableService> _pluggableServices;
@Inject IdentityDao _identityDao;
@Inject List<APIAccessChecker> _apiAccessCheckers; @Inject List<APIChecker> _apiAccessCheckers;
private Account _systemAccount = null; private Account _systemAccount = null;
private User _systemUser = null; private User _systemUser = null;
@ -203,6 +202,18 @@ public class ApiServer implements HttpRequestHandler {
} }
} }
Map<String, String> configs = _configDao.getConfiguration();
String strSnapshotLimit = configs.get(Config.ConcurrentSnapshotsThresholdPerHost.key());
if (strSnapshotLimit != null) {
Long snapshotLimit = NumbersUtil.parseLong(strSnapshotLimit, 1L);
if (snapshotLimit <= 0) {
s_logger.debug("Global config parameter " + Config.ConcurrentSnapshotsThresholdPerHost.toString()
+ " is less or equal 0; defaulting to unlimited");
} else {
_dispatcher.setCreateSnapshotQueueSizeLimit(snapshotLimit);
}
}
Set<Class<?>> cmdClasses = ReflectUtil.getClassesWithAnnotation(APICommand.class, Set<Class<?>> cmdClasses = ReflectUtil.getClassesWithAnnotation(APICommand.class,
new String[]{"org.apache.cloudstack.api", "com.cloud.api"}); new String[]{"org.apache.cloudstack.api", "com.cloud.api"});
@ -552,23 +563,23 @@ public class ApiServer implements HttpRequestHandler {
} }
String commandName = command[0]; String commandName = command[0];
/*
// if userId not null, that mean that user is logged in // if userId not null, that mean that user is logged in
if (userId != null) { if (userId != null) {
User user = ApiDBUtils.findUserById(userId); User user = ApiDBUtils.findUserById(userId);
if (!isCommandAvailable(user, commandName)) { if (!isCommandAvailable(user, commandName)) {
s_logger.warn("The given command:" + commandName + " does not exist or it is not available for user"); s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user with id:" + userId);
throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user"); throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user");
} }
return true; return true;
} else { } else {
// check against every available command to see if the command exists or not // check against every available command to see if the command exists or not
if (!isCommandAvailable(null, commandName) && !commandName.equals("login") && !commandName.equals("logout")) { if (!_apiNameCmdClassMap.containsKey(commandName) && !commandName.equals("login") && !commandName.equals("logout")) {
s_logger.warn("The given command:" + commandName + " does not exist or it is not available for user"); s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user with id:" + userId);
throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user"); throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command does not exist or it is not available for user");
} }
} }
*/
// - build a request string with sorted params, make sure it's all lowercase // - build a request string with sorted params, make sure it's all lowercase
// - sign the request, verify the signature is the same // - sign the request, verify the signature is the same
List<String> parameterNames = new ArrayList<String>(); List<String> parameterNames = new ArrayList<String>();
@ -608,30 +619,29 @@ public class ApiServer implements HttpRequestHandler {
// if api/secret key are passed to the parameters // if api/secret key are passed to the parameters
if ((signature == null) || (apiKey == null)) { if ((signature == null) || (apiKey == null)) {
if (s_logger.isDebugEnabled()) { s_logger.debug("Expired session, missing signature, or missing apiKey -- ignoring request. Signature: " + signature + ", apiKey: " + apiKey);
s_logger.info("expired session, missing signature, or missing apiKey -- ignoring request...sig: " + signature + ", apiKey: " + apiKey);
}
return false; // no signature, bad request return false; // no signature, bad request
} }
Date expiresTS = null; Date expiresTS = null;
// FIXME: Hard coded signature, why not have an enum
if ("3".equals(signatureVersion)) { if ("3".equals(signatureVersion)) {
// New signature authentication. Check for expire parameter and its validity // New signature authentication. Check for expire parameter and its validity
if (expires == null) { if (expires == null) {
s_logger.info("missing Expires parameter -- ignoring request...sig: " + signature + ", apiKey: " + apiKey); s_logger.debug("Missing Expires parameter -- ignoring request. Signature: " + signature + ", apiKey: " + apiKey);
return false; return false;
} }
synchronized (_dateFormat) { synchronized (_dateFormat) {
try { try {
expiresTS = _dateFormat.parse(expires); expiresTS = _dateFormat.parse(expires);
} catch (ParseException pe) { } catch (ParseException pe) {
s_logger.info("Incorrect date format for Expires parameter", pe); s_logger.debug("Incorrect date format for Expires parameter", pe);
return false; return false;
} }
} }
Date now = new Date(System.currentTimeMillis()); Date now = new Date(System.currentTimeMillis());
if (expiresTS.before(now)) { if (expiresTS.before(now)) {
s_logger.info("Request expired -- ignoring ...sig: " + signature + ", apiKey: " + apiKey); s_logger.debug("Request expired -- ignoring ...sig: " + signature + ", apiKey: " + apiKey);
return false; return false;
} }
} }
@ -642,7 +652,7 @@ public class ApiServer implements HttpRequestHandler {
// verify there is a user with this api key // verify there is a user with this api key
Pair<User, Account> userAcctPair = _accountMgr.findUserByApiKey(apiKey); Pair<User, Account> userAcctPair = _accountMgr.findUserByApiKey(apiKey);
if (userAcctPair == null) { if (userAcctPair == null) {
s_logger.info("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey); s_logger.debug("apiKey does not map to a valid user -- ignoring request, apiKey: " + apiKey);
return false; return false;
} }
@ -658,8 +668,8 @@ public class ApiServer implements HttpRequestHandler {
UserContext.updateContext(user.getId(), account, null); UserContext.updateContext(user.getId(), account, null);
if (!isCommandAvailable(user, commandName)) { if (!isCommandAvailable(user, commandName)) {
s_logger.warn("The given command:" + commandName + " does not exist or it is not available for user"); s_logger.debug("The given command:" + commandName + " does not exist or it is not available for user");
throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command:" + commandName + " does not exist or it is not available for user"); throw new ServerApiException(BaseCmd.UNSUPPORTED_ACTION_ERROR, "The given command:" + commandName + " does not exist or it is not available for user with id:" + userId);
} }
// verify secret key exists // verify secret key exists
@ -686,18 +696,13 @@ public class ApiServer implements HttpRequestHandler {
if (ex instanceof ServerApiException && ((ServerApiException) ex).getErrorCode() == BaseCmd.UNSUPPORTED_ACTION_ERROR) { if (ex instanceof ServerApiException && ((ServerApiException) ex).getErrorCode() == BaseCmd.UNSUPPORTED_ACTION_ERROR) {
throw (ServerApiException) ex; throw (ServerApiException) ex;
} }
s_logger.error("unable to verifty request signature", ex); s_logger.error("unable to verify request signature", ex);
} }
return false; return false;
} }
public Long fetchDomainId(String domainUUID){ public Long fetchDomainId(String domainUUID) {
try{ return _domainMgr.getDomain(domainUUID).getId();
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<String, Object[]> requestParameters) throws CloudAuthenticationException { public void loginUser(HttpSession session, String username, String password, Long domainId, String domainPath, String loginIpAddress ,Map<String, Object[]> requestParameters) throws CloudAuthenticationException {
@ -793,17 +798,16 @@ public class ApiServer implements HttpRequestHandler {
return true; return true;
} }
private boolean isCommandAvailable(User user, String commandName) private boolean isCommandAvailable(User user, String commandName) throws PermissionDeniedException {
throws PermissionDeniedException {
if (user == null) { if (user == null) {
return false; throw new PermissionDeniedException("User is null for role based API access check for command" + commandName);
} }
Account account = _accountMgr.getAccount(user.getAccountId()); Account account = _accountMgr.getAccount(user.getAccountId());
RoleType roleType = _accountMgr.getRoleType(account); RoleType roleType = _accountMgr.getRoleType(account);
for (APIAccessChecker apiChecker : _apiAccessCheckers) { for (APIChecker apiChecker : _apiAccessCheckers) {
// Fail the checking if any checker fails to verify // Fail the checking if any checker fails to verify
if (!apiChecker.canAccessAPI(roleType, commandName)) if (!apiChecker.checkAccess(roleType, commandName))
return false; return false;
} }
return true; return true;

View File

@ -32,6 +32,8 @@ import javax.naming.ConfigurationException;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.ServerApiException;
import com.cloud.offering.DiskOffering;
import com.cloud.storage.dao.DiskOfferingDao;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -109,7 +111,6 @@ import com.cloud.resource.UnableDeleteHostException;
import com.cloud.service.ServiceOfferingVO; import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.servlet.ConsoleProxyServlet; import com.cloud.servlet.ConsoleProxyServlet;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.StoragePoolStatus;
import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StoragePoolVO;
@ -137,7 +138,6 @@ import com.cloud.utils.db.Transaction;
import com.cloud.utils.events.SubscriptionMgr; import com.cloud.utils.events.SubscriptionMgr;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
import com.cloud.uuididentity.dao.IdentityDao;
import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.ConsoleProxyVO;
import com.cloud.vm.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContext;
@ -218,6 +218,8 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
@Inject @Inject
ServiceOfferingDao _offeringDao; ServiceOfferingDao _offeringDao;
@Inject @Inject
DiskOfferingDao _diskOfferingDao;
@Inject
NetworkOfferingDao _networkOfferingDao; NetworkOfferingDao _networkOfferingDao;
@Inject @Inject
StoragePoolDao _storagePoolDao; StoragePoolDao _storagePoolDao;
@ -226,8 +228,6 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
@Inject @Inject
ResourceManager _resourceMgr; ResourceManager _resourceMgr;
@Inject @Inject
IdentityDao _identityDao;
@Inject
NetworkDao _networkDao; NetworkDao _networkDao;
@Inject @Inject
RulesManager _rulesMgr; RulesManager _rulesMgr;
@ -929,14 +929,12 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
return new ConsoleAccessAuthenticationAnswer(cmd, false); return new ConsoleAccessAuthenticationAnswer(cmd, false);
} }
vmId = _identityDao.getIdentityId("vm_instance", cmd.getVmId()); VirtualMachine vm = _instanceDao.findByUuid(cmd.getVmId());
if (vmId == null) {
s_logger.error("Invalid vm id " + cmd.getVmId() + " sent from console access authentication");
return new ConsoleAccessAuthenticationAnswer(cmd, false);
}
VMInstanceVO vm = _instanceDao.findById(vmId);
if (vm == null) { if (vm == null) {
vm = _instanceDao.findById(Long.parseLong(cmd.getVmId()));
}
if (vm == null) {
s_logger.error("Invalid vm id " + cmd.getVmId() + " sent from console access authentication");
return new ConsoleAccessAuthenticationAnswer(cmd, false); return new ConsoleAccessAuthenticationAnswer(cmd, false);
} }
@ -1513,20 +1511,17 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key())); boolean useLocalStorage = Boolean.parseBoolean(configs.get(Config.SystemVMUseLocalStorage.key()));
//check if there is a default service offering configured //check if there is a default service offering configured
String cpvmSrvcOffIdStr = configs.get(Config.ConsoleProxyServiceOffering.key()); String cpvmSrvcOffIdStr = configs.get(Config.ConsoleProxyServiceOffering.key());
if (cpvmSrvcOffIdStr != null) { if (cpvmSrvcOffIdStr != null) {
DiskOffering diskOffering = _diskOfferingDao.findByUuid(cpvmSrvcOffIdStr);
Long cpvmSrvcOffId = null; if (diskOffering == null)
try { diskOffering = _diskOfferingDao.findById(Long.parseLong(cpvmSrvcOffIdStr));
cpvmSrvcOffId = _identityDao.getIdentityId(DiskOfferingVO.class.getAnnotation(Table.class).name(),cpvmSrvcOffIdStr); if (diskOffering != null) {
} catch (Exception e) { _serviceOffering = _offeringDao.findById(diskOffering.getId());
String msg = "Can't find system service offering specified by global config, uuid=" + cpvmSrvcOffIdStr + " for console proxy vm"; } else {
s_logger.warn(msg); s_logger.warn("Can't find system service offering specified by global config, uuid=" + cpvmSrvcOffIdStr + " for console proxy vm");
} }
if(cpvmSrvcOffId != null){ }
_serviceOffering = _offeringDao.findById(cpvmSrvcOffId);
}
}
if(_serviceOffering == null || !_serviceOffering.getSystemUse()){ if(_serviceOffering == null || !_serviceOffering.getSystemUse()){
int ramSize = NumbersUtil.parseInt(_configDao.getValue("console.ram.size"), DEFAULT_PROXY_VM_RAMSIZE); int ramSize = NumbersUtil.parseInt(_configDao.getValue("console.ram.size"), DEFAULT_PROXY_VM_RAMSIZE);

View File

@ -2438,6 +2438,12 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
return _networksDao.findById(id); return _networksDao.findById(id);
} }
@Override
@DB
public Network getNetwork(String uuid) {
return _networksDao.findByUuid(uuid);
}
@Override @Override
public List<? extends RemoteAccessVPNServiceProvider> getRemoteAccessVpnElements() { public List<? extends RemoteAccessVPNServiceProvider> getRemoteAccessVpnElements() {
List<RemoteAccessVPNServiceProvider> elements = new ArrayList<RemoteAccessVPNServiceProvider>(); List<RemoteAccessVPNServiceProvider> elements = new ArrayList<RemoteAccessVPNServiceProvider>();

View File

@ -87,6 +87,11 @@ public class DomainManagerImpl implements DomainManager, DomainService, Manager
return _domainDao.findById(domainId); return _domainDao.findById(domainId);
} }
@Override
public Domain getDomain(String domainUuid) {
return _domainDao.findByUuid(domainUuid);
}
@Override @Override
public String getName() { public String getName() {
return _name; return _name;

View File

@ -112,6 +112,12 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager, NetworkS
return null; return null;
} }
@Override
public Network getNetwork(String networkUuid) {
// TODO Auto-generated method stub
return null;
}
@Override @Override
public IpAddress getIp(long id) { public IpAddress getIp(long id) {
// TODO Auto-generated method stub // TODO Auto-generated method stub

View File

@ -46,6 +46,12 @@ public class MockDomainManagerImpl implements Manager, DomainManager {
return null; return null;
} }
@Override
public Domain getDomain(String uuid) {
// TODO Auto-generated method stub
return null;
}
@Override @Override
public boolean isChildDomain(Long parentId, Long childId) { public boolean isChildDomain(Long parentId, Long childId) {
// TODO Auto-generated method stub // TODO Auto-generated method stub

View File

@ -156,6 +156,12 @@ public class MockNetworkManagerImpl implements NetworkManager, Manager{
return null; return null;
} }
@Override
public Network getNetwork(String networkUuid) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see com.cloud.network.NetworkService#getIp(long) * @see com.cloud.network.NetworkService#getIp(long)
*/ */

View File

@ -129,7 +129,6 @@ known_categories = {
'AutoScale': 'AutoScale', 'AutoScale': 'AutoScale',
'Counter': 'AutoScale', 'Counter': 'AutoScale',
'Condition': 'AutoScale', 'Condition': 'AutoScale',
'Api': 'API Discovery',
} }

View File

@ -57,7 +57,7 @@
<argument>${client.config.jars}</argument> <argument>${client.config.jars}</argument>
<argument>./target</argument> <argument>./target</argument>
<argument>-f</argument> <argument>-f</argument>
<argument>${client.config.conf}/commands.properties,${client.config.conf}/commands-ext.properties,${client.config.conf}/virtualrouter_commands.properties,${client.config.conf}/nicira-nvp_commands.properties,${client.config.conf}/api-discovery_commands.properties </argument> <argument>${client.config.conf}/commands.properties,${client.config.conf}/commands-ext.properties,${client.config.conf}/virtualrouter_commands.properties,${client.config.conf}/nicira-nvp_commands.properties</argument>
</arguments> </arguments>
</configuration> </configuration>
</execution> </execution>

View File

@ -37,4 +37,4 @@ INSERT INTO `cloud`.`configuration` (instance, name, value) VALUE('DEFAULT', 'se
UPDATE `cloud`.`configuration` SET value='10' where name = 'storage.overprovisioning.factor'; UPDATE `cloud`.`configuration` SET value='10' where name = 'storage.overprovisioning.factor';
UPDATE `cloud`.`configuration` SET value='10' where name = 'cpu.overprovisioning.factor'; UPDATE `cloud`.`configuration` SET value='10' where name = 'cpu.overprovisioning.factor';
UPDATE `cloud`.`configuration` SET value='10' where name = 'mem.overprovisioning.factor'; UPDATE `cloud`.`configuration` SET value='10' where name = 'mem.overprovisioning.factor';
UPDATE `cloud`.`vm_template` SET unique_name="tiny Linux",name="tiny Linux",url="https://dl.dropbox.com/u/678991/cloudstack-extras/ttylinux_pv.qcow2",checksum="81dcf4b4ca05a3b637a040e851568f29",display_text="tiny Linux",format='QCOW2',hypervisor_type='KVM' where id=5; UPDATE `cloud`.`vm_template` SET unique_name="tiny Linux",name="tiny Linux",url="http://marcus.mlsorensen.com/cloudstack-extras/ttylinux_pv.qcow2",checksum="81dcf4b4ca05a3b637a040e851568f29",display_text="tiny Linux",format='QCOW2',hypervisor_type='KVM' where id=5;

View File

@ -56,7 +56,7 @@ public interface GenericDao<T, ID extends Serializable> {
T findById(ID id, boolean fresh); T findById(ID id, boolean fresh);
// Finds one unique VO using uuid // Finds one unique VO using uuid
T findByUuid(ID uuid); T findByUuid(String uuid);
/** /**
* @return VO object ready to be used for update. It won't have any fields filled in. * @return VO object ready to be used for update. It won't have any fields filled in.

View File

@ -915,7 +915,7 @@ public abstract class GenericDaoBase<T, ID extends Serializable> implements Gene
@Override @DB(txn=false) @Override @DB(txn=false)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T findByUuid(final ID uuid) { public T findByUuid(final String uuid) {
SearchCriteria<T> sc = createSearchCriteria(); SearchCriteria<T> sc = createSearchCriteria();
sc.addAnd("uuid", SearchCriteria.Op.EQ, uuid); sc.addAnd("uuid", SearchCriteria.Op.EQ, uuid);
return findOneBy(sc); return findOneBy(sc);

View File

@ -18,14 +18,21 @@ package com.cloud.utils.log;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.log4j.Logger; import org.apache.log4j.*;
import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.db.DB; import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.log4j.spi.RootLogger;
import org.apache.log4j.spi.ThrowableRenderer;
import java.io.CharArrayWriter;
import java.io.Writer;
public class CglibThrowableRendererTest extends TestCase { public class CglibThrowableRendererTest extends TestCase {
static Logger another = Logger.getLogger("TEST");
private final static Logger s_logger = Logger.getLogger(CglibThrowableRendererTest.class); private final static Logger s_logger = Logger.getLogger(CglibThrowableRendererTest.class);
public static class Test { public static class Test {
@DB @DB
@ -49,12 +56,39 @@ public class CglibThrowableRendererTest extends TestCase {
} }
} }
private Logger getAlternateLogger(Writer writer, ThrowableRenderer renderer) {
Hierarchy hierarchy = new Hierarchy(new RootLogger(Level.INFO));
if (renderer != null) {
hierarchy.setThrowableRenderer(renderer);
}
Logger alternateRoot = hierarchy.getRootLogger();
alternateRoot.addAppender(new WriterAppender(new SimpleLayout(), writer));
return alternateRoot;
}
public void testException() { public void testException() {
Writer w = new CharArrayWriter();
Logger alt = getAlternateLogger(w, null);
Test test = ComponentContext.inject(Test.class); Test test = ComponentContext.inject(Test.class);
try { try {
test.exception(); test.exception();
} catch (Exception e) { } catch (Exception e) {
s_logger.warn("exception caught", e); alt.warn("exception caught", e);
} }
// first check that we actually have some call traces containing "<generated>"
assertTrue(w.toString().contains("<generated>"));
w = new CharArrayWriter();
alt = getAlternateLogger(w, new CglibThrowableRenderer());
try {
test.exception();
} catch (Exception e) {
alt.warn("exception caught", e);
}
// then we check that CglibThrowableRenderer indeed remove those occurrences
assertFalse(w.toString().contains("<generated>"));
} }
} }