diff --git a/agent-simulator/db/create-schema-simulator.sql b/agent-simulator/db/create-schema-simulator.sql index bae65ee1c34..0b3a820b92d 100644 --- a/agent-simulator/db/create-schema-simulator.sql +++ b/agent-simulator/db/create-schema-simulator.sql @@ -1,15 +1,19 @@ -# Copyright 2012 Citrix Systems, Inc. Licensed under the -# Apache License, Version 2.0 (the "License"); you may not use this -# file except in compliance with the License. Citrix Systems, Inc. -# reserves all rights not expressly granted by the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Automatically generated by addcopyright.py at 04/03/2012 +# 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. DROP TABLE IF EXISTS `cloud`.`mockhost`; DROP TABLE IF EXISTS `cloud`.`mocksecstorage`; DROP TABLE IF EXISTS `cloud`.`mockstoragepool`; diff --git a/agent-simulator/scripts/zucchini/zucchini.configuration.sql b/agent-simulator/scripts/zucchini/zucchini.configuration.sql index 6a267be52ab..f2c492ea189 100644 --- a/agent-simulator/scripts/zucchini/zucchini.configuration.sql +++ b/agent-simulator/scripts/zucchini/zucchini.configuration.sql @@ -1,15 +1,19 @@ -# Copyright 2012 Citrix Systems, Inc. Licensed under the -# Apache License, Version 2.0 (the "License"); you may not use this -# file except in compliance with the License. Citrix Systems, Inc. -# reserves all rights not expressly granted by the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Automatically generated by addcopyright.py at 04/03/2012 +# 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. update configuration set value='pod' where name='network.dns.basiczone.updates'; update configuration set value='false' where name='use.user.concentrated.pod.allocation'; diff --git a/agent/conf/environment.properties.in b/agent/conf/environment.properties.in index c38e2b8137b..7fcf570538f 100644 --- a/agent/conf/environment.properties.in +++ b/agent/conf/environment.properties.in @@ -18,3 +18,4 @@ # management server compile-time environment parameters paths.pid=@PIDDIR@ +paths.scripts=@AGENTLIBDIR@ diff --git a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in index d98d6e23bc4..488ced2fa90 100755 --- a/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/centos/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -33,17 +33,34 @@ PIDFILE=@PIDDIR@/"$whatami".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ PROGNAME="Cloud Agent" +CLASS="com.cloud.agent.AgentShell" unset OPTIONS [ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME" -DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize -PROG=@LIBEXECDIR@/agent-runner + +# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT) +JDK_DIRS="/usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun /usr/lib/jvm/java-1.5.0-sun /usr/lib/j2sdk1.5-sun /usr/lib/j2sdk1.5-ibm" + +for jdir in $JDK_DIRS; do + if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then + JAVA_HOME="$jdir" + fi +done +export JAVA_HOME + +SCP="@SYSTEMCLASSPATH@" +DCP="@DEPSCLASSPATH@" +ACP="@AGENTCLASSPATH@" +JCP="/usr/share/java/commons-daemon.jar" + +# We need to append the JSVC daemon JAR to the classpath +# AgentShell implements the JSVC daemon methods +export CLASSPATH="$SCP:$DCP:$ACP:$JCP:@AGENTSYSCONFDIR@" start() { echo -n $"Starting $PROGNAME: " if hostname --fqdn >/dev/null 2>&1 ; then - daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \ - -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS + jsvc -cp "$CLASSPATH" -pidfile "$PIDFILE" $CLASS RETVAL=$? echo else @@ -58,7 +75,7 @@ start() { stop() { echo -n $"Stopping $PROGNAME: " - killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME + jsvc -pidfile "$PIDFILE" -stop $CLASS RETVAL=$? echo [ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE} diff --git a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in index d98d6e23bc4..488ced2fa90 100755 --- a/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/fedora/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -33,17 +33,34 @@ PIDFILE=@PIDDIR@/"$whatami".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ PROGNAME="Cloud Agent" +CLASS="com.cloud.agent.AgentShell" unset OPTIONS [ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME" -DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize -PROG=@LIBEXECDIR@/agent-runner + +# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT) +JDK_DIRS="/usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun /usr/lib/jvm/java-1.5.0-sun /usr/lib/j2sdk1.5-sun /usr/lib/j2sdk1.5-ibm" + +for jdir in $JDK_DIRS; do + if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then + JAVA_HOME="$jdir" + fi +done +export JAVA_HOME + +SCP="@SYSTEMCLASSPATH@" +DCP="@DEPSCLASSPATH@" +ACP="@AGENTCLASSPATH@" +JCP="/usr/share/java/commons-daemon.jar" + +# We need to append the JSVC daemon JAR to the classpath +# AgentShell implements the JSVC daemon methods +export CLASSPATH="$SCP:$DCP:$ACP:$JCP:@AGENTSYSCONFDIR@" start() { echo -n $"Starting $PROGNAME: " if hostname --fqdn >/dev/null 2>&1 ; then - daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \ - -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS + jsvc -cp "$CLASSPATH" -pidfile "$PIDFILE" $CLASS RETVAL=$? echo else @@ -58,7 +75,7 @@ start() { stop() { echo -n $"Stopping $PROGNAME: " - killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME + jsvc -pidfile "$PIDFILE" -stop $CLASS RETVAL=$? echo [ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE} diff --git a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in index 4046d225258..01606c72a0d 100644 --- a/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/opensuse/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -1,8 +1,8 @@ #!/bin/bash ### BEGIN INIT INFO # Provides: cloud agent -# Required-Start: $network -# Required-Stop: $network +# Required-Start: $network +# Required-Stop: $network # Default-Start: 3 4 5 # Default-Stop: 0 1 2 6 # X-Interactive: true @@ -40,17 +40,37 @@ PIDFILE=@PIDDIR@/"$whatami".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ PROGNAME="Cloud Agent" +CLASS="com.cloud.agent.AgentShell" unset OPTIONS [ -r @SYSCONFDIR@/default/"$SHORTNAME" ] && source @SYSCONFDIR@/default/"$SHORTNAME" -DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize -PROG=@LIBEXECDIR@/agent-runner + +# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT) +JDK_DIRS="/usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun /usr/lib/jvm/java-1.5.0-sun /usr/lib/j2sdk1.5-sun /usr/lib/j2sdk1.5-ibm" + +for jdir in $JDK_DIRS; do + if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then + JAVA_HOME="$jdir" + fi +done +export JAVA_HOME + +SCP="@SYSTEMCLASSPATH@" +DCP="@DEPSCLASSPATH@" +ACP="@AGENTCLASSPATH@" +JCP="/usr/share/java/commons-daemon.jar" + +# We need to append the JSVC daemon JAR to the classpath +# AgentShell implements the JSVC daemon methods +export CLASSPATH="$SCP:$DCP:$ACP:$JCP:@AGENTSYSCONFDIR@" wait_for_network() { i=1 while [ $i -lt 10 ] do - if ip addr show cloudbr0 |grep -w inet > /dev/null 2>&1; then + # Under Ubuntu and Debian libvirt by default creates a bridge called virbr0. + # That's why we want more then 3 lines back from brctl, so that there is a manually created bridge + if [ "$(brctl show|wc -l)" -gt 2 ]; then break else sleep 1 @@ -75,12 +95,9 @@ start() { exit 1 fi - #FIXME: wait for network - wait_for_network + wait_for_network - if start-stop-daemon --start --quiet \ - --pidfile "$PIDFILE" \ - --exec "$DAEMONIZE" -- -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS + if jsvc -cp "$CLASSPATH" -pidfile "$PIDFILE" $CLASS RETVAL=$? then rc=0 @@ -106,11 +123,11 @@ stop() { count="0" echo -n $"Stopping $PROGNAME" "$SHORTNAME" - start-stop-daemon --stop --quiet --oknodo --pidfile "$PIDFILE" + jsvc -pidfile "$PIDFILE" -stop $CLASS until [ "$count" -gt "$SHUTDOWN_WAIT" ] do - agentPid=`ps aux|grep [j]ava|grep cloud-agent` + agentPid=`ps aux|grep [j]svc|grep cloud-agent` if [ "$?" -gt "0" ];then break fi @@ -118,16 +135,16 @@ stop() { let count="${count}+1" done - agentPid=`ps aux|grep [j]ava|grep cloud-agent` + agentPid=`ps aux|grep [j]svc|grep cloud-agent` if [ "$?" -eq "0" ]; then - agentPid=`ps aux|grep [j]ava|awk '{print $2}'` + agentPid=`ps aux|grep [j]svc|awk '{print $2}'` if [ "$agentPid" != "" ]; then kill -9 $agentPid fi fi - log_end_msg $? - rm -f "$PIDFILE" + log_end_msg $? + rm -f "$PIDFILE" } diff --git a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in index d98d6e23bc4..488ced2fa90 100644 --- a/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in +++ b/agent/distro/rhel/SYSCONFDIR/rc.d/init.d/cloud-agent.in @@ -33,17 +33,34 @@ PIDFILE=@PIDDIR@/"$whatami".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ PROGNAME="Cloud Agent" +CLASS="com.cloud.agent.AgentShell" unset OPTIONS [ -r @SYSCONFDIR@/sysconfig/"$SHORTNAME" ] && source @SYSCONFDIR@/sysconfig/"$SHORTNAME" -DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize -PROG=@LIBEXECDIR@/agent-runner + +# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT) +JDK_DIRS="/usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun /usr/lib/jvm/java-1.5.0-sun /usr/lib/j2sdk1.5-sun /usr/lib/j2sdk1.5-ibm" + +for jdir in $JDK_DIRS; do + if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then + JAVA_HOME="$jdir" + fi +done +export JAVA_HOME + +SCP="@SYSTEMCLASSPATH@" +DCP="@DEPSCLASSPATH@" +ACP="@AGENTCLASSPATH@" +JCP="/usr/share/java/commons-daemon.jar" + +# We need to append the JSVC daemon JAR to the classpath +# AgentShell implements the JSVC daemon methods +export CLASSPATH="$SCP:$DCP:$ACP:$JCP:@AGENTSYSCONFDIR@" start() { echo -n $"Starting $PROGNAME: " if hostname --fqdn >/dev/null 2>&1 ; then - daemon --check=$SHORTNAME --pidfile=${PIDFILE} "$DAEMONIZE" \ - -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS + jsvc -cp "$CLASSPATH" -pidfile "$PIDFILE" $CLASS RETVAL=$? echo else @@ -58,7 +75,7 @@ start() { stop() { echo -n $"Stopping $PROGNAME: " - killproc -p ${PIDFILE} $SHORTNAME # -d 10 $SHORTNAME + jsvc -pidfile "$PIDFILE" -stop $CLASS RETVAL=$? echo [ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE} diff --git a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in index 4046d225258..01606c72a0d 100644 --- a/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/sles/SYSCONFDIR/init.d/cloud-agent.in @@ -1,8 +1,8 @@ #!/bin/bash ### BEGIN INIT INFO # Provides: cloud agent -# Required-Start: $network -# Required-Stop: $network +# Required-Start: $network +# Required-Stop: $network # Default-Start: 3 4 5 # Default-Stop: 0 1 2 6 # X-Interactive: true @@ -40,17 +40,37 @@ PIDFILE=@PIDDIR@/"$whatami".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ PROGNAME="Cloud Agent" +CLASS="com.cloud.agent.AgentShell" unset OPTIONS [ -r @SYSCONFDIR@/default/"$SHORTNAME" ] && source @SYSCONFDIR@/default/"$SHORTNAME" -DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize -PROG=@LIBEXECDIR@/agent-runner + +# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT) +JDK_DIRS="/usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun /usr/lib/jvm/java-1.5.0-sun /usr/lib/j2sdk1.5-sun /usr/lib/j2sdk1.5-ibm" + +for jdir in $JDK_DIRS; do + if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then + JAVA_HOME="$jdir" + fi +done +export JAVA_HOME + +SCP="@SYSTEMCLASSPATH@" +DCP="@DEPSCLASSPATH@" +ACP="@AGENTCLASSPATH@" +JCP="/usr/share/java/commons-daemon.jar" + +# We need to append the JSVC daemon JAR to the classpath +# AgentShell implements the JSVC daemon methods +export CLASSPATH="$SCP:$DCP:$ACP:$JCP:@AGENTSYSCONFDIR@" wait_for_network() { i=1 while [ $i -lt 10 ] do - if ip addr show cloudbr0 |grep -w inet > /dev/null 2>&1; then + # Under Ubuntu and Debian libvirt by default creates a bridge called virbr0. + # That's why we want more then 3 lines back from brctl, so that there is a manually created bridge + if [ "$(brctl show|wc -l)" -gt 2 ]; then break else sleep 1 @@ -75,12 +95,9 @@ start() { exit 1 fi - #FIXME: wait for network - wait_for_network + wait_for_network - if start-stop-daemon --start --quiet \ - --pidfile "$PIDFILE" \ - --exec "$DAEMONIZE" -- -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS + if jsvc -cp "$CLASSPATH" -pidfile "$PIDFILE" $CLASS RETVAL=$? then rc=0 @@ -106,11 +123,11 @@ stop() { count="0" echo -n $"Stopping $PROGNAME" "$SHORTNAME" - start-stop-daemon --stop --quiet --oknodo --pidfile "$PIDFILE" + jsvc -pidfile "$PIDFILE" -stop $CLASS until [ "$count" -gt "$SHUTDOWN_WAIT" ] do - agentPid=`ps aux|grep [j]ava|grep cloud-agent` + agentPid=`ps aux|grep [j]svc|grep cloud-agent` if [ "$?" -gt "0" ];then break fi @@ -118,16 +135,16 @@ stop() { let count="${count}+1" done - agentPid=`ps aux|grep [j]ava|grep cloud-agent` + agentPid=`ps aux|grep [j]svc|grep cloud-agent` if [ "$?" -eq "0" ]; then - agentPid=`ps aux|grep [j]ava|awk '{print $2}'` + agentPid=`ps aux|grep [j]svc|awk '{print $2}'` if [ "$agentPid" != "" ]; then kill -9 $agentPid fi fi - log_end_msg $? - rm -f "$PIDFILE" + log_end_msg $? + rm -f "$PIDFILE" } diff --git a/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in b/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in index c4607cbb799..c657ed2887d 100755 --- a/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in +++ b/agent/distro/ubuntu/SYSCONFDIR/init.d/cloud-agent.in @@ -1,12 +1,17 @@ #!/bin/bash + ### BEGIN INIT INFO # Provides: cloud agent -# Required-Start: $network -# Required-Stop: $network +# Required-Start: $network $local_fs +# Required-Stop: $network $local_fs # Default-Start: 3 4 5 # Default-Stop: 0 1 2 6 -# X-Interactive: true -# Short-Description: Start/stop apache2 web server +# Short-Description: Start/stop Apache CloudStack Agent +# Description: This scripts Starts/Stops the Apache CloudStack agent +## The CloudStack Agent is a part of the Apache CloudStack project and is used +## for managing KVM-based Hypervisors and performing secondary storage tasks inside +## the Secondary Storage System Virtual Machine. +## JSVC (Java daemonizing) is used for starting and stopping the agent ### END INIT INFO # Licensed to the Apache Software Foundation (ASF) under one @@ -26,25 +31,39 @@ # specific language governing permissions and limitations # under the License. -# WARNING: if this script is changed, then all other initscripts MUST BE changed to match it as well - . /lib/lsb/init-functions -. /etc/default/rcS -whatami=cloud-agent - -# set environment variables - -SHORTNAME="$whatami" -PIDFILE=@PIDDIR@/"$whatami".pid +SHORTNAME="cloud-agent" +PIDFILE=@PIDDIR@/"$SHORTNAME".pid LOCKFILE=@LOCKDIR@/"$SHORTNAME" LOGFILE=@AGENTLOG@ -PROGNAME="Cloud Agent" +PROGNAME="CloudStack Agent" +CLASS="com.cloud.agent.AgentShell" +PROG="jsvc" +DAEMON="/usr/bin/jsvc" +SHUTDOWN_WAIT="30" unset OPTIONS [ -r @SYSCONFDIR@/default/"$SHORTNAME" ] && source @SYSCONFDIR@/default/"$SHORTNAME" -DAEMONIZE=@BINDIR@/@PACKAGE@-daemonize -PROG=@LIBEXECDIR@/agent-runner + +# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT) +JDK_DIRS="/usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-sun /usr/lib/jvm/java-1.5.0-sun /usr/lib/j2sdk1.5-sun /usr/lib/j2sdk1.5-ibm" + +for jdir in $JDK_DIRS; do + if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then + JAVA_HOME="$jdir" + fi +done +export JAVA_HOME + +SCP="@SYSTEMCLASSPATH@" +DCP="@DEPSCLASSPATH@" +ACP="@AGENTCLASSPATH@" +JCP="/usr/share/java/commons-daemon.jar" + +# We need to append the JSVC daemon JAR to the classpath +# AgentShell implements the JSVC daemon methods +export CLASSPATH="$SCP:$DCP:$ACP:$JCP:@AGENTSYSCONFDIR@" wait_for_network() { i=1 @@ -63,55 +82,53 @@ wait_for_network() { } start() { - log_daemon_msg $"Starting $PROGNAME" "$SHORTNAME" - if [ -s "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then - log_progress_msg "apparently already running" - log_end_msg 0 - exit 0 - fi - if hostname --fqdn >/dev/null 2>&1 ; then - true - else - log_failure_msg "The host name does not resolve properly to an IP address. Cannot start $PROGNAME" - log_end_msg 1 - exit 1 - fi + if [ -s "$PIDFILE" ] && kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then + log_daemon_msg "$PROGNAME apparently already running" + log_end_msg 0 + exit 0 + fi - wait_for_network + log_daemon_msg "Starting $PROGNAME" "$SHORTNAME" + if hostname --fqdn >/dev/null 2>&1 ; then + true + else + log_failure_msg "The host name does not resolve properly to an IP address. Cannot start $PROGNAME" + log_end_msg 1 + exit 1 + fi - if start-stop-daemon --start --quiet \ - --pidfile "$PIDFILE" \ - --exec "$DAEMONIZE" -- -n "$SHORTNAME" -p "$PIDFILE" -l "$LOGFILE" "$PROG" $OPTIONS - RETVAL=$? - then - rc=0 - sleep 1 - if ! kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then - log_failure_msg "$PROG failed to start" - rc=1 - fi - else - rc=1 - fi + wait_for_network - if [ $rc -eq 0 ]; then - log_end_msg 0 - else - log_end_msg 1 - rm -f "$PIDFILE" - fi + if start_daemon -p $PIDFILE $DAEMON -cp "$CLASSPATH" -pidfile "$PIDFILE" $CLASS + RETVAL=$? + then + rc=0 + sleep 1 + if ! kill -0 $(cat "$PIDFILE") >/dev/null 2>&1; then + log_failure_msg "$PROG failed to start" + rc=1 + fi + else + rc=1 + fi + + if [ $rc -eq 0 ]; then + log_end_msg 0 + else + log_end_msg 1 + rm -f "$PIDFILE" + fi } stop() { - SHUTDOWN_WAIT="30" count="0" - echo -n $"Stopping $PROGNAME" "$SHORTNAME" - start-stop-daemon --stop --quiet --oknodo --pidfile "$PIDFILE" + log_daemon_msg "Stopping $PROGNAME" "$SHORTNAME" + killproc -p $PIDFILE $DAEMON until [ "$count" -gt "$SHUTDOWN_WAIT" ] do - agentPid=`ps aux|grep [j]ava|grep cloud-agent` + agentPid=$(ps aux|grep [j]svc|grep $SHORTNAME) if [ "$?" -gt "0" ];then break fi @@ -119,40 +136,38 @@ stop() { let count="${count}+1" done - agentPid=`ps aux|grep [j]ava|grep cloud-agent` + agentPid=$(ps aux|grep [j]svc|grep $SHORTNAME) if [ "$?" -eq "0" ]; then - agentPid=`ps aux|grep [j]ava|awk '{print $2}'` - if [ "$agentPid" != "" ]; then - kill -9 $agentPid - fi + agentPid=$(ps aux|grep [j]svc|awk '{print $2}') + if [ "$agentPid" != "" ]; then + log_warning_msg "$PROG still running, forcing kill" + kill -9 $agentPid + fi fi - log_end_msg $? - rm -f "$PIDFILE" + log_end_msg $? + rm -f "$PIDFILE" } - -# See how we were called. case "$1" in - start) - start - ;; - stop) - stop - ;; - status) + start) + start + ;; + stop) + stop + ;; + status) status_of_proc -p "$PIDFILE" "$PROG" "$SHORTNAME" - RETVAL=$? - ;; - restart) - stop - sleep 3 - start - ;; - *) - echo $"Usage: $whatami {start|stop|restart|status|help}" - RETVAL=3 + RETVAL=$? + ;; + restart | force-reload) + stop + sleep 3 + start + ;; + *) + echo "Usage: $0 {start|stop|restart|force-reload|status}" + RETVAL=3 esac -exit $RETVAL - +exit $RETVAL \ No newline at end of file diff --git a/agent/libexec/agent-runner.in b/agent/libexec/agent-runner.in deleted file mode 100755 index 8e548ae78b3..00000000000 --- a/agent/libexec/agent-runner.in +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env bash -# 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. - -#run.sh runs the agent client. - -cd `dirname "$0"` - -SYSTEMJARS="@SYSTEMJARS@" -SCP=$(build-classpath $SYSTEMJARS) ; if [ $? != 0 ] ; then SCP="@SYSTEMCLASSPATH@" ; fi -DCP="@DEPSCLASSPATH@" -ACP="@AGENTCLASSPATH@" -export CLASSPATH=$SCP:$DCP:$ACP:@AGENTSYSCONFDIR@ -for jarfile in "@PREMIUMJAVADIR@"/* ; do - if [ ! -e "$jarfile" ] ; then continue ; fi - CLASSPATH=$jarfile:$CLASSPATH -done -for plugin in "@PLUGINJAVADIR@"/* ; do - if [ ! -e "$plugin" ] ; then continue ; fi - CLASSPATH=$plugin:$CLASSPATH -done -export CLASSPATH - -set -e -cd "@AGENTLIBDIR@" -echo Current directory is "$PWD" -echo CLASSPATH to run the agent: "$CLASSPATH" - -export PATH=/sbin:/usr/sbin:"$PATH" -SERVICEARGS= -for x in private public ; do - configuration=`grep "^$x.network.device" "@AGENTSYSCONFDIR@"/agent.properties||true` - if [ -n "$configuration" ] ; then - echo "Using manually-configured network device $CONFIGURATION" - else - defaultroute=`ip route | grep ^default | cut -d ' ' -f 5` - test -n "$defaultroute" - echo "Using auto-discovered network device $defaultroute which is the default route" - SERVICEARGS="$SERVICEARGS $x.network.device="$defaultroute - fi -done - -function termagent() { - if [ "$agentpid" != "" ] ; then - echo Killing VMOps Agent "(PID $agentpid)" with SIGTERM >&2 - kill -TERM $agentpid - echo Waiting for agent to exit >&2 - wait $agentpid - ex=$? - echo Agent exited with return code $ex >&2 - else - echo Agent PID is unknown >&2 - fi -} - -trap termagent TERM -while true ; do - java -Xms128M -Xmx384M -cp "$CLASSPATH" "$@" com.cloud.agent.AgentShell $SERVICEARGS & - agentpid=$! - echo "Agent started. PID: $!" >&2 - wait $agentpid - ex=$? - if [ $ex -gt 128 ]; then - echo "wait on agent process interrupted by SIGTERM" >&2 - exit $ex - fi - echo "Agent exited with return code $ex" >&2 - if [ $ex -eq 0 ] || [ $ex -eq 1 ] || [ $ex -eq 66 ] || [ $ex -gt 128 ]; then - echo "Exiting..." > /dev/stderr - exit $ex - fi - echo "Restarting agent..." > /dev/stderr - sleep 1 -done diff --git a/agent/src/com/cloud/agent/AgentShell.java b/agent/src/com/cloud/agent/AgentShell.java index 941f09498b4..ca3f7de02f4 100644 --- a/agent/src/com/cloud/agent/AgentShell.java +++ b/agent/src/com/cloud/agent/AgentShell.java @@ -27,6 +27,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; @@ -371,7 +372,7 @@ public class AgentShell implements IAgentShell { return true; } - private void init(String[] args) throws ConfigurationException { + public void init(String[] args) throws ConfigurationException { final ComponentLocator locator = ComponentLocator.getLocator("agent"); @@ -383,8 +384,14 @@ public class AgentShell implements IAgentShell { } s_logger.info("Implementation Version is " + _version); + loadProperties(); parseCommand(args); + List properties = Collections.list((Enumeration)_properties.propertyNames()); + for (String property:properties){ + s_logger.debug("Found property: " + property); + } + _storage = locator.getManager(StorageComponent.class); if (_storage == null) { s_logger.info("Defaulting to using properties file for storage"); @@ -558,13 +565,10 @@ public class AgentShell implements IAgentShell { return _nextAgentId++; } - private void run(String[] args) { + public void start() { try { System.setProperty("java.net.preferIPv4Stack", "true"); - loadProperties(); - init(args); - String instance = getProperty(null, "instance"); if (instance == null) { if (Boolean.parseBoolean(getProperty(null, "developer"))) { @@ -579,7 +583,7 @@ public class AgentShell implements IAgentShell { String pidDir = getProperty(null, "piddir"); final String run = "agent." + instance + "pid"; - s_logger.debug("Checking to see if " + run + "exists."); + s_logger.debug("Checking to see if " + run + " exists."); ProcessUtil.pidCheck(pidDir, run); launchAgent(); @@ -616,22 +620,17 @@ public class AgentShell implements IAgentShell { } } - public static void main(String[] args) { - AgentShell shell = new AgentShell(); - Runtime.getRuntime().addShutdownHook(new ShutdownThread(shell)); - shell.run(args); + public void destroy() { + } - private static class ShutdownThread extends Thread { - AgentShell _shell; - - public ShutdownThread(AgentShell shell) { - this._shell = shell; - } - - @Override - public void run() { - _shell.stop(); + public static void main(String[] args) { + try { + AgentShell shell = new AgentShell(); + shell.init(args); + shell.start(); + } catch (ConfigurationException e) { + System.out.println(e.getMessage()); } } } diff --git a/agent/src/com/cloud/agent/resource/computing/KVMHAChecker.java b/agent/src/com/cloud/agent/resource/computing/KVMHAChecker.java index b2df8c1736a..f5b8a32bcee 100644 --- a/agent/src/com/cloud/agent/resource/computing/KVMHAChecker.java +++ b/agent/src/com/cloud/agent/resource/computing/KVMHAChecker.java @@ -53,7 +53,7 @@ public class KVMHAChecker extends KVMHABase implements Callable { cmd.add("-h", _hostIP); cmd.add("-r"); cmd.add("-t", - String.valueOf((_heartBeatUpdateFreq + _heartBeatUpdateTimeout) / 1000 * 2)); + String.valueOf(_heartBeatUpdateFreq/1000)); OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser(); String result = cmd.execute(parser); s_logger.debug("pool: " + pool._poolIp); diff --git a/api/src/com/cloud/api/BaseListTaggedResourcesCmd.java b/api/src/com/cloud/api/BaseListTaggedResourcesCmd.java index 9a70b107089..1894fba8bb4 100644 --- a/api/src/com/cloud/api/BaseListTaggedResourcesCmd.java +++ b/api/src/com/cloud/api/BaseListTaggedResourcesCmd.java @@ -1,15 +1,19 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// 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 // -// Automatically generated by addcopyright.py at 04/03/2012 +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. package com.cloud.api; import java.util.Collection; diff --git a/api/src/com/cloud/api/commands/CreateTagsCmd.java b/api/src/com/cloud/api/commands/CreateTagsCmd.java index f87ae6e96d8..a981363cc89 100644 --- a/api/src/com/cloud/api/commands/CreateTagsCmd.java +++ b/api/src/com/cloud/api/commands/CreateTagsCmd.java @@ -33,6 +33,7 @@ import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; import com.cloud.api.response.SuccessResponse; import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag.TaggedResourceType; diff --git a/api/src/com/cloud/api/commands/GetUserCmd.java b/api/src/com/cloud/api/commands/GetUserCmd.java new file mode 100644 index 00000000000..465e440a0f3 --- /dev/null +++ b/api/src/com/cloud/api/commands/GetUserCmd.java @@ -0,0 +1,76 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.api.commands; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.response.UserResponse; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.UserAccount; + +@Implementation(description="Find user account by API key", responseObject=UserResponse.class) +public class GetUserCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(GetUserCmd.class.getName()); + + private static final String s_name = "getuserresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.API_KEY, type=CommandType.STRING, required=true, description="API key of the user") + private String apiKey; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getApiKey() { + return apiKey; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return 0; + } + + @Override + public void execute(){ + UserAccount result = _accountService.getUserByApiKey(getApiKey()); + if(result != null){ + UserResponse response = _responseGenerator.createUserResponse(result); + response.setResponseName(getCommandName()); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } else { + throw new InvalidParameterValueException("User with specified API key does not exist"); + } + } +} diff --git a/api/src/com/cloud/user/AccountService.java b/api/src/com/cloud/user/AccountService.java index 02e9b27f0f5..53383d3c7c3 100755 --- a/api/src/com/cloud/user/AccountService.java +++ b/api/src/com/cloud/user/AccountService.java @@ -196,6 +196,8 @@ public interface AccountService { List searchForUsers(ListUsersCmd cmd) throws PermissionDeniedException; + UserAccount getUserByApiKey(String apiKey); + void checkAccess(Account account, Domain domain) throws PermissionDeniedException; void checkAccess(Account account, AccessType accessType, boolean sameOwner, ControlledEntity... entities) throws PermissionDeniedException; diff --git a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java index 9e10e0929a3..38f80c815fc 100644 --- a/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java +++ b/awsapi/src/com/cloud/bridge/service/EC2SoapServiceImpl.java @@ -33,6 +33,7 @@ import com.cloud.bridge.service.core.ec2.EC2CreateImage; import com.cloud.bridge.service.core.ec2.EC2CreateImageResponse; import com.cloud.bridge.service.core.ec2.EC2CreateKeyPair; import com.cloud.bridge.service.core.ec2.EC2CreateVolume; +import com.cloud.bridge.service.core.ec2.EC2Tags; import com.cloud.bridge.service.core.ec2.EC2DeleteKeyPair; import com.cloud.bridge.service.core.ec2.EC2DescribeAddresses; import com.cloud.bridge.service.core.ec2.EC2DescribeAddressesResponse; @@ -46,10 +47,13 @@ import com.cloud.bridge.service.core.ec2.EC2DescribeInstances; import com.cloud.bridge.service.core.ec2.EC2DescribeInstancesResponse; import com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairs; import com.cloud.bridge.service.core.ec2.EC2DescribeKeyPairsResponse; +import com.cloud.bridge.service.core.ec2.EC2ResourceTag; import com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroups; import com.cloud.bridge.service.core.ec2.EC2DescribeSecurityGroupsResponse; import com.cloud.bridge.service.core.ec2.EC2DescribeSnapshots; import com.cloud.bridge.service.core.ec2.EC2DescribeSnapshotsResponse; +import com.cloud.bridge.service.core.ec2.EC2DescribeTags; +import com.cloud.bridge.service.core.ec2.EC2DescribeTagsResponse; import com.cloud.bridge.service.core.ec2.EC2DescribeVolumes; import com.cloud.bridge.service.core.ec2.EC2DescribeVolumesResponse; import com.cloud.bridge.service.core.ec2.EC2DisassociateAddress; @@ -69,6 +73,8 @@ import com.cloud.bridge.service.core.ec2.EC2PasswordData; import com.cloud.bridge.service.core.ec2.EC2RebootInstances; import com.cloud.bridge.service.core.ec2.EC2RegisterImage; import com.cloud.bridge.service.core.ec2.EC2ReleaseAddress; +import com.cloud.bridge.service.core.ec2.EC2TagKeyValue; +import com.cloud.bridge.service.core.ec2.EC2TagTypeId; import com.cloud.bridge.service.core.ec2.EC2RunInstances; import com.cloud.bridge.service.core.ec2.EC2RunInstancesResponse; import com.cloud.bridge.service.core.ec2.EC2SSHKeyPair; @@ -79,6 +85,7 @@ import com.cloud.bridge.service.core.ec2.EC2StartInstances; import com.cloud.bridge.service.core.ec2.EC2StartInstancesResponse; import com.cloud.bridge.service.core.ec2.EC2StopInstances; import com.cloud.bridge.service.core.ec2.EC2StopInstancesResponse; +import com.cloud.bridge.service.core.ec2.EC2TagsFilterSet; import com.cloud.bridge.service.core.ec2.EC2Volume; import com.cloud.bridge.service.core.ec2.EC2VolumeFilterSet; import com.cloud.bridge.service.exception.EC2ServiceException; @@ -199,6 +206,89 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { return toCreateVolumeResponse( engine.createVolume( request )); } + public CreateTagsResponse createTags(CreateTags createTags) { + EC2Tags request = new EC2Tags(); + CreateTagsType ctt = createTags.getCreateTags(); + + ResourceIdSetType resourceIds = ctt.getResourcesSet(); + ResourceTagSetType resourceTags = ctt.getTagSet(); + request = toResourceTypeAndIds(resourceIds); + //add resource tag's to the request + if (resourceTags != null) { + ResourceTagSetItemType[] items = resourceTags.getItem(); + if (items != null) { + for( int i=0; i < items.length; i++ ) { + EC2TagKeyValue param1 = new EC2TagKeyValue(); + param1.setKey(items[i].getKey()); + param1.setValue(items[i].getValue()); + request.addResourceTag(param1); + } + } + } + return toCreateTagsResponse( engine.modifyTags( request, "create")); + } + + public DeleteTagsResponse deleteTags(DeleteTags deleteTags) { + EC2Tags request = new EC2Tags(); + DeleteTagsType dtt = deleteTags.getDeleteTags(); + + ResourceIdSetType resourceIds = dtt.getResourcesSet(); + DeleteTagsSetType resourceTags = dtt.getTagSet(); + request = toResourceTypeAndIds(resourceIds); + //add resource tag's to the request + if (resourceTags != null) { + DeleteTagsSetItemType[] items = resourceTags.getItem(); + if (items != null) { + for( int i=0; i < items.length; i++ ) { + EC2TagKeyValue param1 = new EC2TagKeyValue(); + param1.setKey(items[i].getKey()); + if (items[i].getValue() != null) + param1.setValue(items[i].getValue()); + request.addResourceTag(param1); + } + } + } + return toDeleteTagsResponse( engine.modifyTags( request, "delete")); + } + + private EC2Tags toResourceTypeAndIds(ResourceIdSetType resourceIds) { + EC2Tags request = new EC2Tags(); + //add resource-type and resource-id's to the request + if (resourceIds != null) { + ResourceIdSetItemType[] items = resourceIds.getItem(); + List resourceTypeList = new ArrayList(); + if (items != null) { + for( int i=0; i < items.length; i++ ) { + String resourceType = items[i].getResourceId().split(":")[0]; + if (resourceTypeList.isEmpty()) + resourceTypeList.add(resourceType); + else { + Boolean existsInList = false; + for (String addedResourceType : resourceTypeList) { + if (addedResourceType.equalsIgnoreCase(resourceType)) { + existsInList = true; + break; + } + } + if (!existsInList) + resourceTypeList.add(resourceType); + } + } + for (String resourceType : resourceTypeList){ + EC2TagTypeId param1 = new EC2TagTypeId(); + param1.setResourceType(resourceType); + for( int i=0; i < items.length; i++ ) { + String[] resourceTag = items[i].getResourceId().split(":"); + if (resourceType.equals(resourceTag[0])) + param1.addResourceId(resourceTag[1]); + } + request.addResourceType(param1); + } + } + } + return request; + } + public DeleteSecurityGroupResponse deleteSecurityGroup(DeleteSecurityGroup deleteSecurityGroup) { DeleteSecurityGroupType sgt = deleteSecurityGroup.getDeleteSecurityGroup(); return toDeleteSecurityGroupResponse( engine.deleteSecurityGroup( sgt.getGroupName())); @@ -323,11 +413,10 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { if (null != items) { // -> can be empty for( int i=0; i < items.length; i++ ) request.addInstanceId( items[i].getInstanceId()); } - - if (null != fst) { - request.setFilterSet( toInstanceFilterSet( fst )); - } - + + if (null != fst) + request = toInstanceFilterSet( request, fst ); + return toDescribeInstancesResponse( engine.describeInstances( request ), engine ); } @@ -428,13 +517,24 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { { String[] timeFilters = new String[1]; timeFilters[0] = new String( "start-time" ); - request.setFilterSet( toSnapshotFilterSet( fst, timeFilters )); + request = toSnapshotFilterSet( request, fst, timeFilters ); } return toDescribeSnapshotsResponse(engine.handleRequest(request)); } - + public DescribeTagsResponse describeTags(DescribeTags decsribeTags) { + EC2DescribeTags request = new EC2DescribeTags(); + DescribeTagsType dtt = decsribeTags.getDescribeTags(); + + FilterSetType fst = dtt.getFilterSet(); + + if (fst != null) + request.setFilterSet( toTagsFilterSet( fst )); + + return toDescribeTagsResponse(engine.describeTags(request)); + } + public DescribeVolumesResponse describeVolumes(DescribeVolumes describeVolumes) { EC2DescribeVolumes request = new EC2DescribeVolumes(); @@ -456,7 +556,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { String[] timeFilters = new String[2]; timeFilters[0] = new String( "attachment.attach-time" ); timeFilters[1] = new String( "create-time" ); - request.setFilterSet( toVolumeFilterSet( fst, timeFilters )); + request = toVolumeFilterSet( request, fst, timeFilters ); } return toDescribeVolumesResponse( engine.handleRequest( request )); @@ -855,7 +955,11 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param7.addItem( param8 ); param3.setBlockDeviceMapping( param7 ); - param2.addItem( param3 ); + + EC2TagKeyValue[] tags = images[i].getResourceTags(); + param3.setTagSet(setResourceTags(tags)); + + param2.addItem( param3 ); } param1.setImagesSet( param2 ); @@ -940,8 +1044,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { return vfs; } - - private EC2VolumeFilterSet toVolumeFilterSet( FilterSetType fst, String[] timeStrs ) + private EC2DescribeVolumes toVolumeFilterSet( EC2DescribeVolumes request, FilterSetType fst, String[] timeStrs ) { EC2VolumeFilterSet vfs = new EC2VolumeFilterSet(); boolean timeFilter = false; @@ -952,73 +1055,94 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { // -> each filter can have one or more values associated with it for( int j=0; j < items.length; j++ ) { - EC2Filter oneFilter = new EC2Filter(); - String filterName = items[j].getName(); - oneFilter.setName( filterName ); - - // -> is the filter one of the xsd:dateTime filters? - timeFilter = false; - for( int m=0; m < timeStrs.length; m++ ) - { - timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); - if (timeFilter) break; - } - - ValueSetType vst = items[j].getValueSet(); - ValueType[] valueItems = vst.getItem(); - for( int k=0; k < valueItems.length; k++ ) - { - // -> time values are not encoded as regexes - if ( timeFilter ) - oneFilter.addValue( valueItems[k].getValue()); - else oneFilter.addValueEncoded( valueItems[k].getValue()); - } - vfs.addFilter( oneFilter ); - } - } - return vfs; - } + String filterName = items[j].getName(); + ValueSetType vst = items[j].getValueSet(); + ValueType[] valueItems = vst.getItem(); - - private EC2SnapshotFilterSet toSnapshotFilterSet( FilterSetType fst, String[] timeStrs ) - { - EC2SnapshotFilterSet vfs = new EC2SnapshotFilterSet(); + if (filterName.startsWith("tag:")) { + String key= filterName.split(":")[1]; + for (ValueType valueItem : valueItems) { + EC2TagKeyValue tag = new EC2TagKeyValue(); + tag.setKey(key); + tag.setValue(valueItem.getValue()); + request.addResourceTag(tag); + } + } else { + EC2Filter oneFilter = new EC2Filter(); + oneFilter.setName( filterName ); + + // -> is the filter one of the xsd:dateTime filters? + timeFilter = false; + for( int m=0; m < timeStrs.length; m++ ) { + timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); + if (timeFilter) break; + } + + for( int k=0; k < valueItems.length; k++ ) { + // -> time values are not encoded as regexes + if ( timeFilter ) + oneFilter.addValue( valueItems[k].getValue()); + else + oneFilter.addValueEncoded( valueItems[k].getValue()); + } + vfs.addFilter( oneFilter ); + } + } + request.setFilterSet(vfs); + } + return request; + } + + private EC2DescribeSnapshots toSnapshotFilterSet( EC2DescribeSnapshots request, FilterSetType fst, String[] timeStrs ) + { + EC2SnapshotFilterSet sfs = new EC2SnapshotFilterSet(); boolean timeFilter = false; - + FilterType[] items = fst.getItem(); if (null != items) { // -> each filter can have one or more values associated with it for( int j=0; j < items.length; j++ ) { - EC2Filter oneFilter = new EC2Filter(); - String filterName = items[j].getName(); - oneFilter.setName( filterName ); - - // -> is the filter one of the xsd:dateTime filters? - timeFilter = false; - for( int m=0; m < timeStrs.length; m++ ) - { - timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); - if (timeFilter) break; - } - - ValueSetType vst = items[j].getValueSet(); - ValueType[] valueItems = vst.getItem(); - for( int k=0; k < valueItems.length; k++ ) - { - // -> time values are not encoded as regexes - if ( timeFilter ) - oneFilter.addValue( valueItems[k].getValue()); - else oneFilter.addValueEncoded( valueItems[k].getValue()); - } - vfs.addFilter( oneFilter ); - } - } - return vfs; - } + String filterName = items[j].getName(); + ValueSetType vst = items[j].getValueSet(); + ValueType[] valueItems = vst.getItem(); + + if (filterName.startsWith("tag:")) { + String key= filterName.split(":")[1]; + for (ValueType valueItem : valueItems) { + EC2TagKeyValue tag = new EC2TagKeyValue(); + tag.setKey(key); + tag.setValue(valueItem.getValue()); + request.addResourceTag(tag); + } + } + else { + EC2Filter oneFilter = new EC2Filter(); + oneFilter.setName( filterName ); + + // -> is the filter one of the xsd:dateTime filters? + timeFilter = false; + for( int m=0; m < timeStrs.length; m++ ) { + timeFilter = filterName.equalsIgnoreCase( timeStrs[m] ); + if (timeFilter) break; + } + + for( int k=0; k < valueItems.length; k++ ) { + // -> time values are not encoded as regexes + if ( timeFilter ) + oneFilter.addValue( valueItems[k].getValue()); + else + oneFilter.addValueEncoded( valueItems[k].getValue()); + } + sfs.addFilter( oneFilter ); + } + } + request.setFilterSet(sfs); + } + return request; + } - // TODO make these filter set functions use generics private EC2GroupFilterSet toGroupFilterSet( FilterSetType fst ) { @@ -1046,8 +1170,7 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { return gfs; } - - private EC2InstanceFilterSet toInstanceFilterSet( FilterSetType fst ) + private EC2DescribeInstances toInstanceFilterSet( EC2DescribeInstances request, FilterSetType fst ) { EC2InstanceFilterSet ifs = new EC2InstanceFilterSet(); @@ -1057,22 +1180,30 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { // -> each filter can have one or more values associated with it for( int j=0; j < items.length; j++ ) { - EC2Filter oneFilter = new EC2Filter(); - String filterName = items[j].getName(); - oneFilter.setName( filterName ); - - ValueSetType vst = items[j].getValueSet(); - ValueType[] valueItems = vst.getItem(); - for( int k=0; k < valueItems.length; k++ ) - { - oneFilter.addValueEncoded( valueItems[k].getValue()); - } - ifs.addFilter( oneFilter ); - } - } - return ifs; - } + String filterName = items[j].getName(); + ValueSetType vst = items[j].getValueSet(); + ValueType[] valueItems = vst.getItem(); + if (filterName.startsWith("tag:")) { + String key= filterName.split(":")[1]; + for (ValueType valueItem : valueItems) { + EC2TagKeyValue tag = new EC2TagKeyValue(); + tag.setKey(key); + tag.setValue(valueItem.getValue()); + request.addResourceTag(tag); + } + } else { + EC2Filter oneFilter = new EC2Filter(); + oneFilter.setName( filterName ); + for( int k=0; k < valueItems.length; k++ ) + oneFilter.addValueEncoded( valueItems[k].getValue()); + ifs.addFilter( oneFilter ); + } + } + request.setFilterSet(ifs); + } + return request; + } private EC2AvailabilityZonesFilterSet toAvailabiltyZonesFilterSet( FilterSetType fst ) { EC2AvailabilityZonesFilterSet azfs = new EC2AvailabilityZonesFilterSet(); @@ -1094,8 +1225,28 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { } return azfs; } - - + + private EC2TagsFilterSet toTagsFilterSet( FilterSetType fst ) { + EC2TagsFilterSet tfs = new EC2TagsFilterSet(); + + FilterType[] items = fst.getItem(); + if (items != null) { + for (FilterType item : items) { + EC2Filter oneFilter = new EC2Filter(); + String filterName = item.getName(); + oneFilter.setName( filterName ); + + ValueSetType vft = item.getValueSet(); + ValueType[] valueItems = vft.getItem(); + for (ValueType valueItem : valueItems) { + oneFilter.addValueEncoded( valueItem.getValue()); + } + tfs.addFilter( oneFilter ); + } + } + return tfs; + } + // toMethods public static DescribeVolumesResponse toDescribeVolumesResponse( EC2DescribeVolumesResponse engineResponse ) { @@ -1142,14 +1293,9 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { } param3.setAttachmentSet( param4 ); - - // -> try to generate an empty tag does not seem to work - ResourceTagSetType param6 = new ResourceTagSetType(); - ResourceTagSetItemType param7 = new ResourceTagSetItemType(); - param7.setKey(""); - param7.setValue(""); - param6.addItem( param7 ); - param3.setTagSet( param6 ); + + EC2TagKeyValue[] tags = vol.getResourceTags(); + param3.setTagSet( setResourceTags(tags) ); param2.addItem( param3 ); } param1.setVolumeSet( param2 ); @@ -1277,6 +1423,9 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param7.setSpotInstanceRequestId( "" ); param7.setHypervisor(inst.getHypervisor()); + EC2TagKeyValue[] tags = inst.getResourceTags(); + param7.setTagSet(setResourceTags(tags)); + param6.addItem( param7 ); param3.setInstancesSet( param6 ); param2.addItem( param3 ); @@ -1759,12 +1908,9 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { param3.setDescription( snap.getName()); param3.setOwnerAlias( snap.getAccountName() ); - ResourceTagSetType param18 = new ResourceTagSetType(); - ResourceTagSetItemType param19 = new ResourceTagSetItemType(); - param19.setKey(""); - param19.setValue(""); - param18.addItem( param19 ); - param3.setTagSet( param18 ); + + EC2TagKeyValue[] tags = snap.getResourceTags(); + param3.setTagSet(setResourceTags(tags)); param2.addItem( param3 ); } @@ -1931,7 +2077,48 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { response.setRevokeSecurityGroupIngressResponse( param1 ); return response; } - + + public static CreateTagsResponse toCreateTagsResponse( boolean success ) { + CreateTagsResponse response = new CreateTagsResponse(); + CreateTagsResponseType param1 = new CreateTagsResponseType(); + + param1.set_return(success); + param1.setRequestId( UUID.randomUUID().toString()); + response.setCreateTagsResponse(param1); + return response; + } + + public static DeleteTagsResponse toDeleteTagsResponse( boolean success ) { + DeleteTagsResponse response = new DeleteTagsResponse(); + DeleteTagsResponseType param1 = new DeleteTagsResponseType(); + + param1.set_return(success); + param1.setRequestId( UUID.randomUUID().toString()); + response.setDeleteTagsResponse(param1); + return response; + } + + public static DescribeTagsResponse toDescribeTagsResponse( EC2DescribeTagsResponse engineResponse) { + DescribeTagsResponse response = new DescribeTagsResponse(); + DescribeTagsResponseType param1 = new DescribeTagsResponseType(); + + EC2ResourceTag[] tags = engineResponse.getTagsSet(); + TagSetType param2 = new TagSetType(); + for (EC2ResourceTag tag : tags) { + TagSetItemType param3 = new TagSetItemType(); + param3.setResourceId(tag.getResourceId()); + param3.setResourceType(tag.getResourceType()); + param3.setKey(tag.getKey()); + if (tag.getValue() != null) + param3.setValue(tag.getValue()); + param2.addItem(param3); + } + param1.setTagSet(param2); + param1.setRequestId( UUID.randomUUID().toString()); + response.setDescribeTagsResponse(param1); + return response; + } + public DescribeKeyPairsResponse describeKeyPairs(DescribeKeyPairs describeKeyPairs) { EC2DescribeKeyPairs ec2Request = new EC2DescribeKeyPairs(); @@ -2047,7 +2234,29 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { public GetPasswordDataResponse getPasswordData(GetPasswordData getPasswordData) { return toGetPasswordData(engine.getPasswordData(getPasswordData.getGetPasswordData().getInstanceId())); } - + + public static ResourceTagSetType setResourceTags(EC2TagKeyValue[] tags){ + ResourceTagSetType param1 = new ResourceTagSetType(); + if (null == tags || 0 == tags.length) { + ResourceTagSetItemType param2 = new ResourceTagSetItemType(); + param2.setKey(""); + param2.setValue(""); + param1.addItem( param2 ); + } + else { + for(EC2TagKeyValue tag : tags) { + ResourceTagSetItemType param2 = new ResourceTagSetItemType(); + param2.setKey(tag.getKey()); + if (tag.getValue() != null) + param2.setValue(tag.getValue()); + else + param2.setValue(""); + param1.addItem(param2); + } + } + return param1; + } + @SuppressWarnings("serial") public static GetPasswordDataResponse toGetPasswordData(final EC2PasswordData passwdData) { return new GetPasswordDataResponse() {{ @@ -2116,10 +2325,6 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { public CreateSubnetResponse createSubnet(CreateSubnet createSubnet) { throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); } - - public CreateTagsResponse createTags(CreateTags createTags) { - throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); - } public CreateVpcResponse createVpc(CreateVpc createVpc) { throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); @@ -2156,10 +2361,6 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { public DeleteSubnetResponse deleteSubnet(DeleteSubnet deleteSubnet) { throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); } - - public DeleteTagsResponse deleteTags(DeleteTags deleteTags) { - throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); - } public DeleteVpcResponse deleteVpc(DeleteVpc deleteVpc) { throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); @@ -2229,10 +2430,6 @@ public class EC2SoapServiceImpl implements AmazonEC2SkeletonInterface { throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); } - public DescribeTagsResponse describeTags(DescribeTags describeTags) { - throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); - } - public DescribeVpcsResponse describeVpcs(DescribeVpcs describeVpcs) { throw new EC2ServiceException(ClientError.Unsupported, "This operation is not available"); } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java index e79cd9da870..145342fb8b0 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeInstances.java @@ -23,6 +23,7 @@ public class EC2DescribeInstances { private List instancesSet = new ArrayList(); // a list of strings identifying instances private EC2InstanceFilterSet ifs = null; + private List resourceTagSet = new ArrayList(); public EC2DescribeInstances() { } @@ -42,4 +43,12 @@ public class EC2DescribeInstances { public void setFilterSet( EC2InstanceFilterSet param ) { ifs = param; } + + public void addResourceTag( EC2TagKeyValue param ) { + resourceTagSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTagSet() { + return resourceTagSet.toArray(new EC2TagKeyValue[0]); + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java index 1bf6e3783e1..cd77fde854a 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeSnapshots.java @@ -23,6 +23,7 @@ public class EC2DescribeSnapshots { private List snapshotSet = new ArrayList(); // a list of strings identifying snapshots private EC2SnapshotFilterSet sfs = null; + private List resourceTagSet = new ArrayList(); public EC2DescribeSnapshots() { } @@ -42,4 +43,12 @@ public class EC2DescribeSnapshots { public void setFilterSet( EC2SnapshotFilterSet param ) { sfs = param; } + + public void addResourceTag( EC2TagKeyValue param ) { + resourceTagSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTagSet() { + return resourceTagSet.toArray(new EC2TagKeyValue[0]); + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTags.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTags.java new file mode 100644 index 00000000000..1ce65277c75 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTags.java @@ -0,0 +1,34 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.bridge.service.core.ec2; + +public class EC2DescribeTags { + + private EC2TagsFilterSet tfs = null; + + public EC2DescribeTags() { + } + + public EC2TagsFilterSet getFilterSet() { + return tfs; + } + + public void setFilterSet( EC2TagsFilterSet param ) { + tfs = param; + } +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTagsResponse.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTagsResponse.java new file mode 100644 index 00000000000..9559e65a373 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeTagsResponse.java @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.bridge.service.core.ec2; + +import java.util.ArrayList; +import java.util.List; + +public class EC2DescribeTagsResponse { + + private List tagsSet = new ArrayList(); + + public EC2DescribeTagsResponse() { + } + + public void addTags( EC2ResourceTag param ) { + tagsSet.add( param ); + } + + public EC2ResourceTag[] getTagsSet() { + return tagsSet.toArray(new EC2ResourceTag[0]); + } +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java index 04145fa36c7..3bfd2a41027 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2DescribeVolumes.java @@ -23,6 +23,7 @@ public class EC2DescribeVolumes { private List volumeSet = new ArrayList(); // a list of strings identifying volume ids private EC2VolumeFilterSet vfs = null; + private List resourceTagSet = new ArrayList(); public EC2DescribeVolumes() { } @@ -42,4 +43,12 @@ public class EC2DescribeVolumes { public void setFilterSet( EC2VolumeFilterSet param ) { vfs = param; } + + public void addResourceTag( EC2TagKeyValue param ) { + resourceTagSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTagSet() { + return resourceTagSet.toArray(new EC2TagKeyValue[0]); + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java index 5f4584759f9..1363d0d7a0f 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Engine.java @@ -59,6 +59,7 @@ import com.cloud.stack.models.CloudStackNic; import com.cloud.stack.models.CloudStackOsType; import com.cloud.stack.models.CloudStackPasswordData; import com.cloud.stack.models.CloudStackResourceLimit; +import com.cloud.stack.models.CloudStackResourceTag; import com.cloud.stack.models.CloudStackSecurityGroup; import com.cloud.stack.models.CloudStackSecurityGroupIngress; import com.cloud.stack.models.CloudStackServiceOffering; @@ -417,20 +418,22 @@ public class EC2Engine { * @param request * @return */ - public EC2DescribeSnapshotsResponse handleRequest( EC2DescribeSnapshots request ) + public EC2DescribeSnapshotsResponse handleRequest( EC2DescribeSnapshots request ) { EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); EC2SnapshotFilterSet sfs = request.getFilterSet(); + EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet(); try { // -> query to get the volume size for each snapshot - EC2DescribeSnapshotsResponse response = listSnapshots( request.getSnapshotSet()); + EC2DescribeSnapshotsResponse response = listSnapshots( request.getSnapshotSet(), + getResourceTags(tagKeyValueSet)); if (response == null) { return new EC2DescribeSnapshotsResponse(); } EC2Snapshot[] snapshots = response.getSnapshotSet(); for (EC2Snapshot snap : snapshots) { - volumes = listVolumes(snap.getVolumeId(), null, volumes); + volumes = listVolumes(snap.getVolumeId(), null, volumes, null); EC2Volume[] volSet = volumes.getVolumeSet(); if (0 < volSet.length) snap.setVolumeSize(volSet[0].getSize()); volumes.reset(); @@ -472,7 +475,7 @@ public class EC2Engine { ec2Snapshot.setCreated(snap.getCreated()); ec2Snapshot.setVolumeId(snap.getVolumeId()); - List vols = getApi().listVolumes(null, null, null, snap.getVolumeId(), null, null, null, null, null, null, null); + List vols = getApi().listVolumes(null, null, null, snap.getVolumeId(), null, null, null, null, null, null, null, null); if(vols.size() > 0) { assert(vols.get(0).getSize() != null); @@ -629,17 +632,18 @@ public class EC2Engine { * * @param interestedShots - can be null, should be a subset of all snapshots */ - private EC2DescribeSnapshotsResponse listSnapshots( String[] interestedShots ) throws Exception { + private EC2DescribeSnapshotsResponse listSnapshots( String[] interestedShots, List resourceTagSet ) throws Exception { EC2DescribeSnapshotsResponse snapshots = new EC2DescribeSnapshotsResponse(); List cloudSnaps; if (interestedShots == null || interestedShots.length == 0) { - cloudSnaps = getApi().listSnapshots(null, null, null, null, null, null, null, null, null); + cloudSnaps = getApi().listSnapshots(null, null, null, null, null, null, null, null, null, resourceTagSet); } else { cloudSnaps = new ArrayList(); for(String id : interestedShots) { - List tmpList = getApi().listSnapshots(null, null, id, null, null, null, null, null, null); + List tmpList = getApi().listSnapshots(null, null, id, null, null, null, null, + null, null, resourceTagSet); cloudSnaps.addAll(tmpList); } } @@ -659,6 +663,15 @@ public class EC2Engine { shot.setAccountName(cloudSnapshot.getAccountName()); shot.setDomainId(cloudSnapshot.getDomainId()); + List resourceTags = cloudSnapshot.getTags(); + for(CloudStackKeyValue resourceTag : resourceTags) { + EC2TagKeyValue param = new EC2TagKeyValue(); + param.setKey(resourceTag.getKey()); + if (resourceTag.getValue() != null) + param.setValue(resourceTag.getValue()); + shot.addResourceTag(param); + } + snapshots.addSnapshot(shot); } return snapshots; @@ -870,7 +883,7 @@ public class EC2Engine { public boolean associateAddress( EC2AssociateAddress request ) { try { CloudStackIpAddress cloudIp = getApi().listPublicIpAddresses(null, null, null, null, null, request.getPublicIp(), null, null, null).get(0); - CloudStackUserVm cloudVm = getApi().listVirtualMachines(null, null, true, null, null, null, null, request.getInstanceId(), null, null, null, null, null, null, null, null).get(0); + CloudStackUserVm cloudVm = getApi().listVirtualMachines(null, null, true, null, null, null, null, request.getInstanceId(), null, null, null, null, null, null, null, null, null).get(0); CloudStackInfoResponse resp = getApi().enableStaticNat(cloudIp.getId(), cloudVm.getId()); if (resp != null) { @@ -995,7 +1008,7 @@ public class EC2Engine { // [A] Creating a template from a VM volume should be from the ROOT volume // Also for this to work the VM must be in a Stopped state so we 'reboot' it if its not EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); - volumes = listVolumes( null, request.getInstanceId(), volumes ); + volumes = listVolumes( null, request.getInstanceId(), volumes, null ); EC2Volume[] volSet = volumes.getVolumeSet(); for (EC2Volume vol : volSet) { if (vol.getType().equalsIgnoreCase( "ROOT" )) { @@ -1012,7 +1025,7 @@ public class EC2Engine { // [B] The parameters must be in sorted order for proper signature generation EC2DescribeInstancesResponse instances = new EC2DescribeInstancesResponse(); - instances = lookupInstances( request.getInstanceId(), instances ); + instances = lookupInstances( request.getInstanceId(), instances, null ); EC2Instance[] instanceSet = instances.getInstanceSet(); String templateId = instanceSet[0].getTemplateId(); @@ -1055,9 +1068,8 @@ public class EC2Engine { { try { CloudStackAccount caller = getCurrentAccount(); - if (null == request.getFormat() || null == request.getName() || null == request.getOsTypeName() || - null == request.getLocation() || null == request.getZoneName()) - throw new EC2ServiceException(ServerError.InternalError, "Missing parameter - location/architecture/name"); + if (null == request.getName()) + throw new EC2ServiceException(ClientError.Unsupported, "Missing parameter - name"); List templates = getApi().registerTemplate((request.getDescription() == null ? request.getName() : request.getDescription()), request.getFormat(), request.getHypervisor(), request.getName(), toOSTypeId(request.getOsTypeName()), request.getLocation(), @@ -1106,7 +1118,9 @@ public class EC2Engine { */ public EC2DescribeInstancesResponse describeInstances(EC2DescribeInstances request ) { try { - return listVirtualMachines( request.getInstancesSet(), request.getFilterSet()); + EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet(); + return listVirtualMachines( request.getInstancesSet(), request.getFilterSet(), + getResourceTags(tagKeyValueSet)); } catch( Exception e ) { logger.error( "EC2 DescribeInstances - " ,e); throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? e.getMessage() : "An unexpected error occurred."); @@ -1150,14 +1164,14 @@ public class EC2Engine { public EC2DescribeVolumesResponse handleRequest( EC2DescribeVolumes request ) { EC2DescribeVolumesResponse volumes = new EC2DescribeVolumesResponse(); EC2VolumeFilterSet vfs = request.getFilterSet(); - + EC2TagKeyValue[] tagKeyValueSet = request.getResourceTagSet(); try { String[] volumeIds = request.getVolumeSet(); if ( 0 == volumeIds.length ){ - volumes = listVolumes( null, null, volumes ); + volumes = listVolumes( null, null, volumes, getResourceTags(tagKeyValueSet) ); } else { for (String s : volumeIds) - volumes = listVolumes(s, null, volumes ); + volumes = listVolumes(s, null, volumes, getResourceTags(tagKeyValueSet) ); } if ( null == vfs ) @@ -1311,6 +1325,80 @@ public class EC2Engine { } } + /** + * Create/Delete tags + * + * @param request + * @param operation + * @return + */ + public boolean modifyTags( EC2Tags request, String operation) { + try { + List resourceTagList = new ArrayList(); + for ( EC2TagKeyValue resourceTag : request.getResourceTags()){ + CloudStackKeyValue pair = new CloudStackKeyValue(); + pair.setKeyValue(resourceTag.getKey(), resourceTag.getValue()); + resourceTagList.add(pair); + } + EC2TagTypeId[] resourceTypeSet = request.getResourceTypeSet(); + for (EC2TagTypeId resourceType : resourceTypeSet) { + String cloudStackResourceType = mapToCloudStackResourceType(resourceType.getResourceType()); + List resourceIdList = new ArrayList(); + for ( String resourceId : resourceType.getResourceIds()) + resourceIdList.add(resourceId); + CloudStackInfoResponse resp = new CloudStackInfoResponse(); + if (operation.equalsIgnoreCase("create")) + resp = getApi().createTags(cloudStackResourceType, resourceIdList, resourceTagList); + else if(operation.equalsIgnoreCase("delete")) + resp = getApi().deleteTags(cloudStackResourceType, resourceIdList, resourceTagList); + else + throw new EC2ServiceException( ServerError.InternalError, "Unknown operation." ); + if (resp.getSuccess() == false) + return false; + } + return true; + } catch (Exception e){ + logger.error( "EC2 Create/Delete Tags - ", e); + throw new EC2ServiceException(ServerError.InternalError, e.getMessage() != null ? + e.getMessage() : "An unexpected error occurred."); + } + } + + /** + * Describe tags + * + * @param request + * @return + */ + public EC2DescribeTagsResponse describeTags (EC2DescribeTags request) { + try { + EC2DescribeTagsResponse tagResponse = new EC2DescribeTagsResponse(); + List resourceTagList = getApi().listTags(null, null, null, true, null); + + List tagList = new ArrayList(); + if (resourceTagList != null && resourceTagList.size() > 0) { + for (CloudStackResourceTag resourceTag: resourceTagList) { + EC2ResourceTag tag = new EC2ResourceTag(); + tag.setResourceId(resourceTag.getResourceId()); + tag.setResourceType(mapToAmazonResourceType(resourceTag.getResourceType())); + tag.setKey(resourceTag.getKey()); + if (resourceTag.getValue() != null) + tag.setValue(resourceTag.getValue()); + tagResponse.addTags(tag); + } + } + + EC2TagsFilterSet tfs = request.getFilterSet(); + if (tfs == null) + return tagResponse; + else + return tfs.evaluate(tagResponse); + } catch(Exception e) { + logger.error("EC2 DescribeTags - ", e); + throw new EC2ServiceException(ServerError.InternalError, e.getMessage()); + } + } + /** * Reboot an instance or instances * @@ -1324,7 +1412,7 @@ public class EC2Engine { // -> reboot is not allowed on destroyed (i.e., terminated) instances try { String[] instanceSet = request.getInstancesSet(); - EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null ); + EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null, null ); vms = previousState.getInstanceSet(); // -> send reboot requests for each found VM @@ -1461,7 +1549,7 @@ public class EC2Engine { // -> first determine the current state of each VM (becomes it previous state) try { - EC2DescribeInstancesResponse previousState = listVirtualMachines( request.getInstancesSet(), null ); + EC2DescribeInstancesResponse previousState = listVirtualMachines( request.getInstancesSet(), null, null ); vms = previousState.getInstanceSet(); // -> send start requests for each item @@ -1503,7 +1591,7 @@ public class EC2Engine { try { String[] instanceSet = request.getInstancesSet(); - EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null ); + EC2DescribeInstancesResponse previousState = listVirtualMachines( instanceSet, null, null ); virtualMachines = previousState.getInstanceSet(); // -> send stop requests for each item @@ -1570,7 +1658,7 @@ public class EC2Engine { if (maxAllowed == -1) return -1; // no limit - EC2DescribeInstancesResponse existingVMS = listVirtualMachines( null, null ); + EC2DescribeInstancesResponse existingVMS = listVirtualMachines( null, null, null ); EC2Instance[] vmsList = existingVMS.getInstanceSet(); return (maxAllowed - vmsList.length); } else { @@ -1584,15 +1672,16 @@ public class EC2Engine { * @param virtualMachineIds - an array of instances we are interested in getting information on * @param ifs - filter out unwanted instances */ - private EC2DescribeInstancesResponse listVirtualMachines( String[] virtualMachineIds, EC2InstanceFilterSet ifs ) throws Exception + private EC2DescribeInstancesResponse listVirtualMachines( String[] virtualMachineIds, EC2InstanceFilterSet ifs, + List resourceTags ) throws Exception { EC2DescribeInstancesResponse instances = new EC2DescribeInstancesResponse(); if (null == virtualMachineIds || 0 == virtualMachineIds.length) { - instances = lookupInstances( null, instances ); + instances = lookupInstances( null, instances, resourceTags ); } else { for( int i=0; i < virtualMachineIds.length; i++ ) { - instances = lookupInstances( virtualMachineIds[i], instances ); + instances = lookupInstances( virtualMachineIds[i], instances, resourceTags ); } } @@ -1607,9 +1696,11 @@ public class EC2Engine { * @param volumeId - if interested in one specific volume, null if want to list all volumes * @param instanceId - if interested in volumes for a specific instance, null if instance is not important */ - private EC2DescribeVolumesResponse listVolumes(String volumeId, String instanceId, EC2DescribeVolumesResponse volumes)throws Exception { + private EC2DescribeVolumesResponse listVolumes(String volumeId, String instanceId, EC2DescribeVolumesResponse volumes, + List resourceTagSet)throws Exception { - List vols = getApi().listVolumes(null, null, null, volumeId, null, null, null, null, null, instanceId, null); + List vols = getApi().listVolumes(null, null, null, volumeId, null, null, null, null, null, + instanceId, null, resourceTagSet); if(vols != null && vols.size() > 0) { for(CloudStackVolume vol : vols) { EC2Volume ec2Vol = new EC2Volume(); @@ -1635,6 +1726,15 @@ public class EC2Engine { ec2Vol.setVMState(vol.getVirtualMachineState()); ec2Vol.setZoneName(vol.getZoneName()); + List resourceTags = vol.getTags(); + for(CloudStackKeyValue resourceTag : resourceTags) { + EC2TagKeyValue param = new EC2TagKeyValue(); + param.setKey(resourceTag.getKey()); + if (resourceTag.getValue() != null) + param.setValue(resourceTag.getValue()); + ec2Vol.addResourceTag(param); + } + volumes.addVolume(ec2Vol); } } @@ -1779,12 +1879,13 @@ public class EC2Engine { * @return the same object passed in as the "instances" parameter modified with one or more * EC2Instance objects loaded. */ - private EC2DescribeInstancesResponse lookupInstances( String instanceId, EC2DescribeInstancesResponse instances ) + private EC2DescribeInstancesResponse lookupInstances( String instanceId, EC2DescribeInstancesResponse instances, + List resourceTagSet ) throws Exception { String instId = instanceId != null ? instanceId : null; List vms = getApi().listVirtualMachines(null, null, true, null, null, null, null, - instId, null, null, null, null, null, null, null, null); + instId, null, null, null, null, null, null, null, null, resourceTagSet); if(vms != null && vms.size() > 0) { for(CloudStackUserVm cloudVm : vms) { @@ -1812,7 +1913,16 @@ public class EC2Engine { break; } } - + + List resourceTags = cloudVm.getTags(); + for(CloudStackKeyValue resourceTag : resourceTags) { + EC2TagKeyValue param = new EC2TagKeyValue(); + param.setKey(resourceTag.getKey()); + if (resourceTag.getValue() != null) + param.setValue(resourceTag.getValue()); + ec2Vm.addResourceTag(param); + } + if (cloudVm.getSecurityGroupList() != null && cloudVm.getSecurityGroupList().size() > 0) { // TODO, we have a list of security groups, just return the first one? List securityGroupList = cloudVm.getSecurityGroupList(); @@ -1885,6 +1995,14 @@ public class EC2Engine { ec2Image.setIsPublic(temp.getIsPublic()); ec2Image.setIsReady(temp.getIsReady()); ec2Image.setDomainId(temp.getDomainId()); + List resourceTags = temp.getTags(); + for(CloudStackKeyValue resourceTag : resourceTags) { + EC2TagKeyValue param = new EC2TagKeyValue(); + param.setKey(resourceTag.getKey()); + if (resourceTag.getValue() != null) + param.setValue(resourceTag.getValue()); + ec2Image.addResourceTag(param); + } images.addImage(ec2Image); } } @@ -2245,6 +2363,36 @@ public class EC2Engine { return "error"; } + /** + * Map Amazon resourceType to CloudStack resourceType + * + * @param Amazon resourceType + * @return CloudStack resourceType + */ + private String mapToCloudStackResourceType( String resourceType) { + if (resourceType.equalsIgnoreCase("image")) + return("template"); + else if(resourceType.equalsIgnoreCase("instance")) + return("userVm"); + else + return resourceType; + } + + /** + * Map Amazon resourceType to CloudStack resourceType + * + * @param CloudStack resourceType + * @return Amazon resourceType + */ + private String mapToAmazonResourceType( String resourceType) { + if (resourceType.equalsIgnoreCase("template")) + return("image"); + else if(resourceType.equalsIgnoreCase("userVm")) + return("instance"); + else + return (resourceType.toLowerCase()); + } + /** * Stop an instance * Wait until one specific VM has stopped @@ -2299,4 +2447,15 @@ public class EC2Engine { } return elementList.toString(); } + + private List getResourceTags(EC2TagKeyValue[] tagKeyValueSet) { + List resourceTags = new ArrayList(); + for (EC2TagKeyValue tagKeyValue : tagKeyValueSet) { + CloudStackKeyValue resourceTag = new CloudStackKeyValue(); + resourceTag.setKeyValue(tagKeyValue.getKey(), tagKeyValue.getValue()); + resourceTags.add(resourceTag); + } + return resourceTags; + } + } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Image.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Image.java index 75e792b1a1b..1c30b674f60 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Image.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Image.java @@ -16,6 +16,9 @@ // under the License. package com.cloud.bridge.service.core.ec2; +import java.util.ArrayList; +import java.util.List; + /** * An EC2 Image is a Cloud template. */ @@ -29,6 +32,7 @@ public class EC2Image { private boolean isReady; private String accountName; private String domainId; + private List tagsSet; public EC2Image() { id = null; @@ -39,6 +43,7 @@ public class EC2Image { isReady = false; accountName = null; domainId = null; + tagsSet = new ArrayList(); } public void setId( String id ) { @@ -104,5 +109,13 @@ public class EC2Image { public void setDomainId(String domainId) { this.domainId = domainId; } - + + + public void addResourceTag( EC2TagKeyValue param ) { + tagsSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTags() { + return tagsSet.toArray(new EC2TagKeyValue[0]); + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Instance.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Instance.java index 064d7e077a6..6e2d696aeac 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Instance.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Instance.java @@ -41,6 +41,7 @@ public class EC2Instance { private String rootDeviceType; private String rootDeviceId; private List groupSet; + private List tagsSet; public EC2Instance() { id = null; @@ -60,6 +61,7 @@ public class EC2Instance { rootDeviceType = null; rootDeviceId = null; groupSet = new ArrayList(); + tagsSet = new ArrayList(); } public void setId( String id ) { @@ -197,5 +199,13 @@ public class EC2Instance { public String[] getGroupSet() { return groupSet.toArray(new String[0]); } - + + public void addResourceTag( EC2TagKeyValue param ) { + tagsSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTags() { + return tagsSet.toArray(new EC2TagKeyValue[0]); + } + } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java index 6d5255ab2d8..449d89e2180 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2InstanceFilterSet.java @@ -48,20 +48,21 @@ public class EC2InstanceFilterSet { filterTypes.put( "root-device-name", "string" ); filterTypes.put( "private-ip-address", "string" ); filterTypes.put( "group-id", "string" ); + filterTypes.put( "tag-key", "string" ); + filterTypes.put( "tag-value", "string" ); } public void addFilter( EC2Filter param ) { String filterName = param.getName(); - String value = (String) filterTypes.get( filterName ); - - if (null == value) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); - - if (null != value && value.equalsIgnoreCase( "null" )) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); + String value = (String) filterTypes.get( filterName ); + if (null == value) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); + + if (null != value && value.equalsIgnoreCase( "null" )) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "]", 501 ); // ToDo we could add checks to make sure the type of a filters value is correct (e.g., an integer) filterSet.add( param ); } @@ -162,6 +163,26 @@ public class EC2InstanceFilterSet { for (String group : groupSet) if (containsString(group, valueSet)) return true; return false; + } + else if (filterName.equalsIgnoreCase("tag-key")) + { + EC2TagKeyValue[] tagSet = vm.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) + if (containsString(tag.getKey(), valueSet)) return true; + return false; + } + else if (filterName.equalsIgnoreCase("tag-value")) + { + EC2TagKeyValue[] tagSet = vm.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) { + if (tag.getValue() == null) { + if (containsEmptyValue(valueSet)) return true; + } + else { + if (containsString(tag.getValue(), valueSet)) return true; + } + } + return false; } else return false; } @@ -178,8 +199,14 @@ public class EC2InstanceFilterSet { } return false; } - - + + private boolean containsEmptyValue( String[] set ) + { + for( int i=0; i < set.length; i++ ) + if (set[i].isEmpty()) return true; + return false; + } + private boolean containsInteger( int lookingFor, String[] set ) { for( int i=0; i < set.length; i++ ) diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java index 3fd36ba358b..d71329701ea 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2RegisterImage.java @@ -16,6 +16,9 @@ // under the License. package com.cloud.bridge.service.core.ec2; +import com.cloud.bridge.service.exception.EC2ServiceException; +import com.cloud.bridge.service.exception.EC2ServiceException.ClientError; + public class EC2RegisterImage { private String location; @@ -67,14 +70,19 @@ public class EC2RegisterImage { */ public void setArchitecture( String param ) { if (null != param) { - String parts[] = param.split( ":" ); - if (3 <= parts.length) { - format = parts[0]; - zoneName = parts[1]; - osTypeName = parts[2]; - hypervisor = parts[3]; - } - } + if (!param.contains(":") || param.split(":").length < 4) { + throw new EC2ServiceException( ClientError.InvalidParameterValue, "Supported format for " + + "'architecture' is format:zonename:ostypename:hypervisor" ); + } + String parts[] = param.split( ":" ); + format = parts[0]; + zoneName = parts[1]; + osTypeName = parts[2]; + hypervisor = parts[3]; + } + else { + throw new EC2ServiceException(ClientError.Unsupported, "Missing Parameter -" + " architecture"); + } } public String getFormat() { diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ResourceTag.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ResourceTag.java new file mode 100644 index 00000000000..e3c5881909a --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2ResourceTag.java @@ -0,0 +1,64 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.bridge.service.core.ec2; + +public class EC2ResourceTag { + private String resourceId; + private String resourceType; + private String key; + private String value; + + public EC2ResourceTag() { + resourceId = null; + resourceType = null; + key = null; + value = null; + } + + public void setResourceId( String resourceId ) { + this.resourceId = resourceId; + } + + public String getResourceId() { + return this.resourceId; + } + + public void setResourceType( String resourceType ) { + this.resourceType = resourceType; + } + + public String getResourceType() { + return this.resourceType; + } + + public void setKey( String key ) { + this.key = key; + } + + public String getKey() { + return this.key; + } + + public void setValue( String value ) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java index 339506deda0..9e09b7171b3 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Snapshot.java @@ -16,7 +16,9 @@ // under the License. package com.cloud.bridge.service.core.ec2; +import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import com.cloud.bridge.util.EC2RestAuth; @@ -31,6 +33,7 @@ public class EC2Snapshot { private Calendar created; private String accountName; private String domainId; + private List tagsSet; public EC2Snapshot() { id = null; @@ -42,6 +45,7 @@ public class EC2Snapshot { created = null; accountName = null; domainId = null; + tagsSet = new ArrayList(); } public void setId(String id ) { @@ -116,4 +120,12 @@ public class EC2Snapshot { public void setState(String state) { this.state = state; } + + public void addResourceTag( EC2TagKeyValue param ) { + tagsSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTags() { + return tagsSet.toArray(new EC2TagKeyValue[0]); + } } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java index 1c428f029cc..c2bed3ce161 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2SnapshotFilterSet.java @@ -46,20 +46,23 @@ public class EC2SnapshotFilterSet { filterTypes.put( "status", "string" ); filterTypes.put( "volume-id", "string" ); filterTypes.put( "volume-size", "string" ); + filterTypes.put( "tag-key", "string" ); + filterTypes.put( "tag-value", "string" ); } public void addFilter( EC2Filter param ) { String filterName = param.getName(); - String value = (String) filterTypes.get( filterName ); - - if (null == value) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); - - if (null != value && value.equalsIgnoreCase( "null" )) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + if (!filterName.startsWith("tag:")) { + String value = (String) filterTypes.get( filterName ); + if (null == value) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); + + if (null != value && value.equalsIgnoreCase( "null" )) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + } // ToDo we could add checks to make sure the type of a filters value is correct (e.g., an integer) filterSet.add( param ); } @@ -140,6 +143,26 @@ public class EC2SnapshotFilterSet { { return containsLong( snap.getVolumeSize(), valueSet ); } + else if (filterName.equalsIgnoreCase("tag-key")) + { + EC2TagKeyValue[] tagSet = snap.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) + if (containsString(tag.getKey(), valueSet)) return true; + return false; + } + else if (filterName.equalsIgnoreCase("tag-value")) + { + EC2TagKeyValue[] tagSet = snap.getResourceTags(); + for (EC2TagKeyValue tag : tagSet){ + if (tag.getValue() == null) { + if (containsEmptyValue(valueSet)) return true; + } + else { + if (containsString(tag.getValue(), valueSet)) return true; + } + } + return false; + } else return false; } @@ -155,7 +178,13 @@ public class EC2SnapshotFilterSet { return false; } - + private boolean containsEmptyValue( String[] set ) + { + for( int i=0; i < set.length; i++ ) + if (set[i].isEmpty()) return true; + return false; + } + private boolean containsLong( long lookingFor, String[] set ) { for (String s : set) { diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagKeyValue.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagKeyValue.java new file mode 100644 index 00000000000..beb2af9d99f --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagKeyValue.java @@ -0,0 +1,44 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.bridge.service.core.ec2; + +public class EC2TagKeyValue { + private String key; + private String value; + + public EC2TagKeyValue() { + key = null; + value = null; + } + + public void setKey( String key ) { + this.key = key; + } + + public String getKey() { + return this.key; + } + + public void setValue( String value ) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagTypeId.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagTypeId.java new file mode 100644 index 00000000000..3a0666edf82 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagTypeId.java @@ -0,0 +1,47 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.bridge.service.core.ec2; + +import java.util.ArrayList; +import java.util.List; + +public class EC2TagTypeId { + + private String resourceType; + private List resourceIdSet = new ArrayList(); + + public EC2TagTypeId() { + resourceType = null; + } + + public void setResourceType( String resourceType ) { + this.resourceType = resourceType; + } + + public String getResourceType() { + return this.resourceType; + } + + public void addResourceId( String param ) { + resourceIdSet.add( param ); + } + + public String[] getResourceIds() { + return resourceIdSet.toArray(new String[0]); + } +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Tags.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Tags.java new file mode 100644 index 00000000000..80c9f8a5afc --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Tags.java @@ -0,0 +1,44 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.bridge.service.core.ec2; + +import java.util.ArrayList; +import java.util.List; + +public class EC2Tags { + + private List resourceTypeSet = new ArrayList(); + private List resourceTagSet = new ArrayList(); + + public void addResourceType( EC2TagTypeId param ) { + resourceTypeSet.add( param ); + } + + public EC2TagTypeId[] getResourceTypeSet() { + return resourceTypeSet.toArray(new EC2TagTypeId[0]); + } + + public void addResourceTag( EC2TagKeyValue param ) { + resourceTagSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTags() { + return resourceTagSet.toArray(new EC2TagKeyValue[0]); + } +} + diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagsFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagsFilterSet.java new file mode 100644 index 00000000000..c2d33c39ea1 --- /dev/null +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2TagsFilterSet.java @@ -0,0 +1,107 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.bridge.service.core.ec2; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.log4j.Logger; + +import com.cloud.bridge.service.exception.EC2ServiceException; + +public class EC2TagsFilterSet { + protected final static Logger logger = Logger.getLogger(EC2TagsFilterSet.class); + + protected List filterSet = new ArrayList(); + + private Map filterTypes = new HashMap(); + + public EC2TagsFilterSet() { + filterTypes.put( "resource-id", "String" ); + filterTypes.put( "resource-type", "String" ); + filterTypes.put( "key", "String" ); + filterTypes.put( "value", "String" ); + } + + public void addFilter( EC2Filter param ) { + String filterName = param.getName(); + String value = (String) filterTypes.get( filterName ); + + if (null == value) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); + + if (null != value && value.equalsIgnoreCase( "null" )) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + + filterSet.add( param ); + } + + public EC2Filter[] getFilterSet() { + return filterSet.toArray(new EC2Filter[0]); + } + + public EC2DescribeTagsResponse evaluate( EC2DescribeTagsResponse sampleList) throws ParseException { + EC2DescribeTagsResponse resultList = new EC2DescribeTagsResponse(); + + boolean matched; + + EC2ResourceTag[] tagSet = sampleList.getTagsSet(); + EC2Filter[] filterSet = getFilterSet(); + for (EC2ResourceTag tag : tagSet) { + matched = true; + for (EC2Filter filter : filterSet) { + if (!filterMatched(tag, filter)) { + matched = false; + break; + } + } + if (matched == true) + resultList.addTags(tag); + } + return resultList; + } + + private boolean filterMatched( EC2ResourceTag tag, EC2Filter filter ) throws ParseException { + String filterName = filter.getName(); + String[] valueSet = filter.getValueSet(); + + if ( filterName.equalsIgnoreCase("resource-id")) { + return containsString(tag.getResourceId(), valueSet); + } else if ( filterName.equalsIgnoreCase("resource-type")) { + return containsString(tag.getResourceType(), valueSet); + } else if ( filterName.equalsIgnoreCase("key")) { + return containsString(tag.getKey(), valueSet); + } else if ( filterName.equalsIgnoreCase("value")) { + return containsString(tag.getValue(), valueSet); + } else + return false; + } + + private boolean containsString( String lookingFor, String[] set ){ + if (lookingFor == null) + return false; + + for (String filter: set) { + if (lookingFor.matches( filter )) return true; + } + return false; + } +} diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java index 009c17aa687..23d6d701646 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2Volume.java @@ -16,6 +16,9 @@ // under the License. package com.cloud.bridge.service.core.ec2; +import java.util.ArrayList; +import java.util.List; + public class EC2Volume { @@ -32,6 +35,7 @@ public class EC2Volume { private String hypervisor; private String created; private String attached; + private List tagsSet; public EC2Volume() { id = null; @@ -46,6 +50,7 @@ public class EC2Volume { hypervisor = null; created = null; attached = null; + tagsSet = new ArrayList(); } public void setSize(Long size) { @@ -230,5 +235,13 @@ public class EC2Volume { public void setAttached(String attached) { this.attached = attached; } - + + public void addResourceTag( EC2TagKeyValue param ) { + tagsSet.add( param ); + } + + public EC2TagKeyValue[] getResourceTags() { + return tagsSet.toArray(new EC2TagKeyValue[0]); + } + } diff --git a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java index 95d306f7c00..0594231413e 100644 --- a/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java +++ b/awsapi/src/com/cloud/bridge/service/core/ec2/EC2VolumeFilterSet.java @@ -49,8 +49,8 @@ public class EC2VolumeFilterSet { filterTypes.put( "size", "integer" ); filterTypes.put( "snapshot-id", "string" ); filterTypes.put( "status", "set:creating|available|in-use|deleting|deleted|error" ); - filterTypes.put( "tag-key", "null" ); - filterTypes.put( "tag-value", "null" ); + filterTypes.put( "tag-key", "string" ); + filterTypes.put( "tag-value", "string" ); filterTypes.put( "volume-id", "string" ); // filterTypes.put( "tag:*", "null" ); } @@ -59,14 +59,13 @@ public class EC2VolumeFilterSet { public void addFilter( EC2Filter param ) { String filterName = param.getName(); - String value = (String) filterTypes.get( filterName ); + String value = (String) filterTypes.get( filterName ); - if (null == value) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); - - if (null != value && value.equalsIgnoreCase( "null" )) - throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); + if (null == value) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 1", 501 ); + if (null != value && value.equalsIgnoreCase( "null" )) + throw new EC2ServiceException( "Unsupported filter [" + filterName + "] - 2", 501 ); // ToDo we could add checks to make sure the type of a filters value is correct (e.g., an integer) filterSet.add( param ); } @@ -136,7 +135,27 @@ public class EC2VolumeFilterSet { else if (filterName.equalsIgnoreCase( "attachment.device" )) return containsDevice(vol.getDeviceId(), valueSet ); else if (filterName.equalsIgnoreCase( "attachment.instance-id" )) - return containsString(String.valueOf(vol.getInstanceId()), valueSet ); + return containsString(String.valueOf(vol.getInstanceId()), valueSet ); + else if (filterName.equalsIgnoreCase("tag-key")) + { + EC2TagKeyValue[] tagSet = vol.getResourceTags(); + for (EC2TagKeyValue tag : tagSet) + if (containsString(tag.getKey(), valueSet)) return true; + return false; + } + else if (filterName.equalsIgnoreCase("tag-value")) + { + EC2TagKeyValue[] tagSet = vol.getResourceTags(); + for (EC2TagKeyValue tag : tagSet){ + if (tag.getValue() == null) { + if (containsEmptyValue(valueSet)) return true; + } + else { + if (containsString(tag.getValue(), valueSet)) return true; + } + } + return false; + } else return false; } @@ -150,6 +169,12 @@ public class EC2VolumeFilterSet { return false; } + private boolean containsEmptyValue( String[] set ) + { + for( int i=0; i < set.length; i++ ) + if (set[i].isEmpty()) return true; + return false; + } private boolean containsLong( long lookingFor, String[] set ) { diff --git a/awsapi/src/com/cloud/stack/CloudStackApi.java b/awsapi/src/com/cloud/stack/CloudStackApi.java index e46ebddb546..52c2459e072 100644 --- a/awsapi/src/com/cloud/stack/CloudStackApi.java +++ b/awsapi/src/com/cloud/stack/CloudStackApi.java @@ -42,6 +42,7 @@ import com.cloud.stack.models.CloudStackOsType; import com.cloud.stack.models.CloudStackPasswordData; import com.cloud.stack.models.CloudStackPortForwardingRule; import com.cloud.stack.models.CloudStackResourceLimit; +import com.cloud.stack.models.CloudStackResourceTag; import com.cloud.stack.models.CloudStackSecurityGroup; import com.cloud.stack.models.CloudStackSecurityGroupIngress; import com.cloud.stack.models.CloudStackServiceOffering; @@ -313,7 +314,7 @@ public class CloudStackApi { */ public List listVirtualMachines(String account, String accountId, Boolean listAll, Boolean forVirtualNetwork, String groupId, String hostId, String hypervisor, String id, Boolean isRecursive, String keyWord, String name, String networkId, String podId, String state, String storageId, - String zoneId) throws Exception { + String zoneId, List resourceTags) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_VIRTUAL_MACHINES); if (cmd != null) { if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); @@ -332,6 +333,8 @@ public class CloudStackApi { if (state != null) cmd.setParam(ApiConstants.STATE, state); if (storageId != null) cmd.setParam(ApiConstants.STORAGE_ID, storageId); if (zoneId != null) cmd.setParam(ApiConstants.ZONE_ID, zoneId); + if (resourceTags != null && resourceTags.size() > 0) + cmd = setParams(cmd, null, null, resourceTags); } return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_VIRTUAL_MACHINES_RESPONSE, ApiConstants.VIRTUAL_MACHINE, new TypeToken>() {}.getType()); @@ -934,7 +937,7 @@ public class CloudStackApi { * @throws Exception */ public List listVolumes(String account, String domainId, String hostId, String id, Boolean isRecursive, String keyWord, String name, - String podId, String type, String virtualMachineId, String zoneId) throws Exception { + String podId, String type, String virtualMachineId, String zoneId, List resourceTags) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_VOLUMES); if (cmd != null) { if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); @@ -948,6 +951,8 @@ public class CloudStackApi { if (type != null) cmd.setParam(ApiConstants.TYPE, type); if (virtualMachineId != null) cmd.setParam(ApiConstants.VIRTUAL_MACHINE_ID, virtualMachineId); if (zoneId != null) cmd.setParam(ApiConstants.ZONE_ID, zoneId); + if (resourceTags != null && resourceTags.size() > 0) + cmd = setParams(cmd, null, null, resourceTags); } return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_VOLUMES_RESPONSE, ApiConstants.VOLUME, new TypeToken>() {}.getType()); @@ -973,7 +978,82 @@ public class CloudStackApi { } return _client.call(cmd, apiKey, secretKey, true, ApiConstants.EXTRACT_VOLUME_RESPONSE, ApiConstants.VOLUME, CloudStackExtractTemplate.class); } - + + //Tags + /** + * Create tags + * + * @param resource type + * @param resource id's + * @param tags + * @return + * @throws Exception + * + */ + public CloudStackInfoResponse createTags(String resourceType, ListresourceIds, + List resourceTags) throws Exception { + CloudStackCommand cmd = new CloudStackCommand(ApiConstants.CREATE_TAGS); + cmd = setParams(cmd, resourceType, resourceIds, resourceTags); + return _client.call(cmd, apiKey, secretKey, true, ApiConstants.CREATE_TAGS_RESPONSE, + null, CloudStackInfoResponse.class); + } + + /** + * Delete tags + * + * @param resource type + * @param resource id's + * @param tags + * @return + * @throws Exception + * + */ + public CloudStackInfoResponse deleteTags(String resourceType, ListresourceIds, + List resourceTags) throws Exception { + CloudStackCommand cmd = new CloudStackCommand(ApiConstants.DELETE_TAGS); + cmd = setParams(cmd, resourceType, resourceIds, resourceTags); + return _client.call(cmd, apiKey, secretKey, true, ApiConstants.DELETE_TAGS_RESPONSE, + null, CloudStackInfoResponse.class); + } + + public List listTags(String account, String domainId, + Boolean isRecursive, Boolean listAll, String keyWord) throws Exception { + CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_TAGS); + if (cmd != null) { + if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); + if (domainId != null) cmd.setParam(ApiConstants.DOMAIN_ID, domainId); + if (isRecursive != null) cmd.setParam(ApiConstants.IS_RECURSIVE, isRecursive.toString()); + if (listAll != null) cmd.setParam(ApiConstants.LIST_ALL, listAll.toString()); + if (keyWord != null) cmd.setParam(ApiConstants.KEYWORD, keyWord); + } + return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_TAGS_RESPONSE, + ApiConstants.TAG , new TypeToken>() {}.getType()); + } + + private CloudStackCommand setParams(CloudStackCommand cmd, String resourceType, ListresourceIds, + List resourceTags) { + if (cmd != null) { + if (resourceType != null) + cmd.setParam(ApiConstants.RESOURCE_TYPE, resourceType); + if (resourceIds != null && resourceIds.size() > 0) { + String resourceIdList = resourceIds.get(0); + for (int i=1 ; i 0) { + int i=0; + for (CloudStackKeyValue resourceTag : resourceTags) { + cmd.setParam(ApiConstants.TAGS+"["+i+"].key", resourceTag.getKey()); + if (resourceTag.getValue() != null) + cmd.setParam(ApiConstants.TAGS+"["+i+"].value", resourceTag.getValue()); + i++; + } + } + } + return cmd; + } + // Security Groups /** * Creates a security group @@ -1168,7 +1248,7 @@ public class CloudStackApi { * @throws Exception */ public List listSnapshots(String account, String domainId, String id, String intervalType, Boolean isRecursive, - String keyWord, String name, String snapshotType, String volumeId) throws Exception { + String keyWord, String name, String snapshotType, String volumeId, List resourceTags) throws Exception { CloudStackCommand cmd = new CloudStackCommand(ApiConstants.LIST_SNAPSHOTS); if (cmd != null) { if (account != null) cmd.setParam(ApiConstants.ACCOUNT, account); @@ -1180,6 +1260,8 @@ public class CloudStackApi { if (name != null) cmd.setParam(ApiConstants.NAME, name); if (snapshotType != null) cmd.setParam(ApiConstants.SNAPSHOT_TYPE, snapshotType); if (volumeId != null) cmd.setParam(ApiConstants.VOLUME_ID, volumeId); + if (resourceTags != null && resourceTags.size() > 0) + cmd = setParams(cmd, null, null, resourceTags); } return _client.listCall(cmd, apiKey, secretKey, ApiConstants.LIST_SNAPSHOTS_RESPONSE, ApiConstants.SNAPSHOT, new TypeToken>() {}.getType()); diff --git a/awsapi/src/com/cloud/stack/models/ApiConstants.java b/awsapi/src/com/cloud/stack/models/ApiConstants.java index e00a9b90859..2097ab6f135 100644 --- a/awsapi/src/com/cloud/stack/models/ApiConstants.java +++ b/awsapi/src/com/cloud/stack/models/ApiConstants.java @@ -85,6 +85,8 @@ public class ApiConstants { public static final String CREATE_SNAPSHOT_RESPONSE = "createsnapshotresponse"; public static final String CREATE_SSH_KEY_PAIR = "createSSHKeyPair"; public static final String CREATE_SSH_KEY_PAIR_RESPONSE = "createsshkeypairresponse"; + public static final String CREATE_TAGS = "createTags"; + public static final String CREATE_TAGS_RESPONSE = "createtagsresponse"; public static final String CREATE_TEMPLATE = "createTemplate"; public static final String CREATE_TEMPLATE_RESPONSE = "createtemplateresponse"; public static final String CREATE_VOLUME = "createVolume"; @@ -114,6 +116,8 @@ public class ApiConstants { public static final String DELETE_SNAPSHOT_RESPONSE = "deletesnapshotresponse"; public static final String DELETE_SSH_KEY_PAIR = "deleteSSHKeyPair"; public static final String DELETE_SSH_KEY_PAIR_RESPONSE = "deletesshkeypairresponse"; + public static final String DELETE_TAGS = "deleteTags"; + public static final String DELETE_TAGS_RESPONSE = "deletetagsresponse"; public static final String DELETE_TEMPLATE = "deleteTemplate"; public static final String DELETE_TEMPLATE_RESPONSE = "deletetemplateresponse"; public static final String DELETE_VOLUME = "deleteVolume"; @@ -228,6 +232,7 @@ public class ApiConstants { public static final String ISOLATION_URI = "isolationuri"; public static final String JOB_ID = "jobid"; public static final String JOB_STATUS = "jobstatus"; + public static final String KEY = "key"; public static final String KEY_PAIR = "keypair"; public static final String KEYWORD = "keyword"; public static final String LASTNAME = "lastname"; @@ -290,6 +295,8 @@ public class ApiConstants { public static final String LIST_SSH_KEY_PAIRS = "listSSHKeyPairs"; public static final String LIST_SSH_KEY_PAIRS_RESPONSE = "listsshkeypairsresponse"; public static final String LIST_TEMPLATE_PERMISSIONS = "listTemplatePermissions"; + public static final String LIST_TAGS = "listTags"; + public static final String LIST_TAGS_RESPONSE = "listtagsresponse"; public static final String LIST_TEMPLATE_PERMISSIONS_RESPONSE = "listtemplatepermissionsresponse"; public static final String LIST_TEMPLATES = "listTemplates"; public static final String LIST_TEMPLATES_RESPONSE = "listtemplatesresponse"; @@ -380,6 +387,8 @@ public class ApiConstants { public static final String REQUIRES_HVM = "requireshvm"; public static final String RESET_PASSWORD_FOR_VIRTUAL_MACHINE = "resetPasswordForVirtualMachine"; public static final String RESET_PASSWORD_FOR_VIRTUAL_MACHINE_RESPONSE = "resetpasswordforvirtualmachineresponse"; + public static final String RESOURCE_ID = "resourceid"; + public static final String RESOURCE_IDS = "resourceIds"; public static final String RESOURCE_LIMIT = "resourcelimit"; public static final String RESOURCE_TYPE = "resourcetype"; public static final String RESTART_NETWORK = "restartNetwork"; @@ -433,6 +442,7 @@ public class ApiConstants { public static final String STORAGE_TYPE = "storagetype"; public static final String SUCCESS = "success"; public static final String SYSTEM_VM_TYPE = "systemvmtype"; + public static final String TAG = "tag"; public static final String TAGS = "tags"; public static final String TARGET_IQN = "targetiqn"; public static final String TEMPLATE = "template"; diff --git a/awsapi/src/com/cloud/stack/models/CloudStackResourceTag.java b/awsapi/src/com/cloud/stack/models/CloudStackResourceTag.java new file mode 100644 index 00000000000..8dd75c5a41b --- /dev/null +++ b/awsapi/src/com/cloud/stack/models/CloudStackResourceTag.java @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package com.cloud.stack.models; + +import com.google.gson.annotations.SerializedName; + +public class CloudStackResourceTag { + @SerializedName(ApiConstants.RESOURCE_ID) + private String resourceId; + @SerializedName(ApiConstants.RESOURCE_TYPE) + private String resourceType; + @SerializedName(ApiConstants.KEY) + private String key; + @SerializedName(ApiConstants.VALUE) + private String value; + + public CloudStackResourceTag() { + } + + public String getResourceId() { + return resourceId; + } + + public String getResourceType() { + return resourceType; + } + + public String getKey() { + return key; + } + + public String getValue() { + return value; + } +} diff --git a/awsapi/src/com/cloud/stack/models/CloudStackSnapshot.java b/awsapi/src/com/cloud/stack/models/CloudStackSnapshot.java index 73dc4cd13ae..1273cc1d3fc 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackSnapshot.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackSnapshot.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.stack.models; +import java.util.List; + import com.google.gson.annotations.SerializedName; public class CloudStackSnapshot { @@ -47,6 +49,8 @@ public class CloudStackSnapshot { private String volumeName; @SerializedName(ApiConstants.VOLUME_TYPE) private String volumeType; + @SerializedName(ApiConstants.TAGS) + private List tags; public CloudStackSnapshot() { } @@ -106,4 +110,9 @@ public class CloudStackSnapshot { public String getState() { return state; } + + public List getTags() { + return tags; + } + } diff --git a/awsapi/src/com/cloud/stack/models/CloudStackTemplate.java b/awsapi/src/com/cloud/stack/models/CloudStackTemplate.java index 14d6e823cd4..f0390ac03a7 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackTemplate.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackTemplate.java @@ -17,6 +17,8 @@ package com.cloud.stack.models; +import java.util.List; + import com.google.gson.annotations.SerializedName; public class CloudStackTemplate { @@ -82,6 +84,8 @@ public class CloudStackTemplate { private String zoneId; @SerializedName(ApiConstants.ZONE_NAME) private String zoneName; + @SerializedName(ApiConstants.TAGS) + private List tags; /** * @@ -306,4 +310,10 @@ public class CloudStackTemplate { return zoneName; } + /** + * @return all tags + */ + public List getTags() { + return tags; + } } diff --git a/awsapi/src/com/cloud/stack/models/CloudStackUserVm.java b/awsapi/src/com/cloud/stack/models/CloudStackUserVm.java index f72e1b62b22..e1db2d9ae65 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackUserVm.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackUserVm.java @@ -103,6 +103,8 @@ public class CloudStackUserVm { private List nics; @SerializedName(ApiConstants.SECURITY_GROUP) private List securityGroupList; + @SerializedName(ApiConstants.TAGS) + private List tags; public CloudStackUserVm() { } @@ -394,5 +396,12 @@ public class CloudStackUserVm { return securityGroupList; } + /** + * @return all tags + */ + public List getTags() { + return tags; + } + } diff --git a/awsapi/src/com/cloud/stack/models/CloudStackVolume.java b/awsapi/src/com/cloud/stack/models/CloudStackVolume.java index 13d87f4bec8..ff0b717c72b 100644 --- a/awsapi/src/com/cloud/stack/models/CloudStackVolume.java +++ b/awsapi/src/com/cloud/stack/models/CloudStackVolume.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.stack.models; +import java.util.List; + import com.google.gson.annotations.SerializedName; public class CloudStackVolume { @@ -81,6 +83,8 @@ public class CloudStackVolume { private String zoneId; @SerializedName(ApiConstants.ZONE_NAME) private String zoneName; + @SerializedName(ApiConstants.TAGS) + private List tags; public CloudStackVolume() { @@ -334,4 +338,10 @@ public class CloudStackVolume { return zoneName; } + /** + * @return all tags + */ + public List getTags() { + return tags; + } } diff --git a/build/deploy/production/db/templates-dev.sql b/build/deploy/production/db/templates-dev.sql index b673e44443e..2a96750e707 100644 --- a/build/deploy/production/db/templates-dev.sql +++ b/build/deploy/production/db/templates-dev.sql @@ -1,15 +1,19 @@ -# Copyright 2012 Citrix Systems, Inc. Licensed under the -# Apache License, Version 2.0 (the "License"); you may not use this -# file except in compliance with the License. Citrix Systems, Inc. -# reserves all rights not expressly granted by the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Automatically generated by addcopyright.py at 04/03/2012 +# 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. INSERT INTO `vmops`.`vm_template` (id, unique_name, name, public, path, created, type, hvm, bits, created_by, url, checksum, ready, display_text, enable_password) VALUES (1, 'routing', 'DomR Template', 0, 'tank/volumes/demo/template/private/u000000/os/routing', now(), 'ext3', 0, 64, 1, 'http://vmopsserver.lab.vmops.com/images/routing/vmi-root-fc8-x86_64-domR.img.bz2', 'd00927f863a23b98cc6df6e377c9d0c6', 0, 'DomR Template', 0); INSERT INTO `vmops`.`vm_template` (id, unique_name, name, public, path, created, type, hvm, bits, created_by, url, checksum, ready, display_text, enable_password) diff --git a/build/deploy/production/server/conf/log4j-cloud.xml b/build/deploy/production/server/conf/log4j-cloud.xml index 1b5639641e8..83692bbbbd6 100755 --- a/build/deploy/production/server/conf/log4j-cloud.xml +++ b/build/deploy/production/server/conf/log4j-cloud.xml @@ -24,19 +24,41 @@ - - + + - - - - - + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + @@ -101,7 +123,9 @@ - + + + diff --git a/build/package.xml b/build/package.xml index d61c6983609..30dde943acc 100755 --- a/build/package.xml +++ b/build/package.xml @@ -82,7 +82,7 @@ - + diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties index 35fe56849d9..0ce3d4442c4 100644 --- a/client/WEB-INF/classes/resources/messages.properties +++ b/client/WEB-INF/classes/resources/messages.properties @@ -320,7 +320,7 @@ state.Ready=Ready label.vm.display.name=VM display name label.select-view=Select view label.local.storage=Local Storage -label.direct.ips=Direct IPs +label.direct.ips=Shared Network IPs label.view.all=View all label.zone.details=Zone details message.alert.state.detected=Alert state detected diff --git a/client/distro/opensuse/SYSCONFDIR/init.d/cloud-management.in b/client/distro/opensuse/SYSCONFDIR/init.d/cloud-management.in index 52eb3aa4746..d071b39d2e7 100755 --- a/client/distro/opensuse/SYSCONFDIR/init.d/cloud-management.in +++ b/client/distro/opensuse/SYSCONFDIR/init.d/cloud-management.in @@ -2,17 +2,22 @@ # # /etc/init.d/tomcat6 -- startup script for the Tomcat 6 servlet engine -#Copyright 2012 Citrix Systems, Inc. Licensed under the -#Apache License, Version 2.0 (the "License"); you may not use this -#file except in compliance with the License. Citrix Systems, Inc. -#reserves all rights not expressly granted by the License. -#You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -#Unless required by applicable law or agreed to in writing, software -#distributed under the License is distributed on an "AS IS" BASIS, -#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -#See the License for the specific language governing permissions and -#limitations under the License. - +# 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. ### BEGIN INIT INFO # Provides: tomcat-vmops # Required-Start: $local_fs $remote_fs $network diff --git a/client/distro/sles/SYSCONFDIR/init.d/cloud-management.in b/client/distro/sles/SYSCONFDIR/init.d/cloud-management.in index 52eb3aa4746..d071b39d2e7 100755 --- a/client/distro/sles/SYSCONFDIR/init.d/cloud-management.in +++ b/client/distro/sles/SYSCONFDIR/init.d/cloud-management.in @@ -2,17 +2,22 @@ # # /etc/init.d/tomcat6 -- startup script for the Tomcat 6 servlet engine -#Copyright 2012 Citrix Systems, Inc. Licensed under the -#Apache License, Version 2.0 (the "License"); you may not use this -#file except in compliance with the License. Citrix Systems, Inc. -#reserves all rights not expressly granted by the License. -#You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -#Unless required by applicable law or agreed to in writing, software -#distributed under the License is distributed on an "AS IS" BASIS, -#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -#See the License for the specific language governing permissions and -#limitations under the License. - +# 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. ### BEGIN INIT INFO # Provides: tomcat-vmops # Required-Start: $local_fs $remote_fs $network diff --git a/client/distro/ubuntu/SYSCONFDIR/init.d/cloud-management.in b/client/distro/ubuntu/SYSCONFDIR/init.d/cloud-management.in index 2711ffc6db9..b4f2d3e0312 100755 --- a/client/distro/ubuntu/SYSCONFDIR/init.d/cloud-management.in +++ b/client/distro/ubuntu/SYSCONFDIR/init.d/cloud-management.in @@ -2,17 +2,22 @@ # # /etc/init.d/tomcat6 -- startup script for the Tomcat 6 servlet engine -#Copyright 2012 Citrix Systems, Inc. Licensed under the -#Apache License, Version 2.0 (the "License"); you may not use this -#file except in compliance with the License. Citrix Systems, Inc. -#reserves all rights not expressly granted by the License. -#You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -#Unless required by applicable law or agreed to in writing, software -#distributed under the License is distributed on an "AS IS" BASIS, -#WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -#See the License for the specific language governing permissions and -#limitations under the License. - +# 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. ### BEGIN INIT INFO # Provides: tomcat-vmops # Required-Start: $local_fs $remote_fs $network diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 08c175bbc52..28beadeef85 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -19,6 +19,7 @@ listUsers=com.cloud.api.commands.ListUsersCmd;7 ####lockUser=com.cloud.api.commands.LockUserCmd;7 disableUser=com.cloud.api.commands.DisableUserCmd;7 enableUser=com.cloud.api.commands.EnableUserCmd;7 +getUser=com.cloud.api.commands.GetUserCmd;1 #### Domain commands createDomain=com.cloud.api.commands.CreateDomainCmd;1 diff --git a/client/tomcatconf/components.xml.in b/client/tomcatconf/components.xml.in index 16d7b198367..b31954b0d28 100755 --- a/client/tomcatconf/components.xml.in +++ b/client/tomcatconf/components.xml.in @@ -166,8 +166,8 @@ - - + + diff --git a/cloud-cli/cloudapis/cloud.py b/cloud-cli/cloudapis/cloud.py index 856d81177d3..34b3413ce5e 100644 --- a/cloud-cli/cloudapis/cloud.py +++ b/cloud-cli/cloudapis/cloud.py @@ -167,7 +167,7 @@ def load_dynamic_methods(): code = """ def %s(%s): %s - parms = locals() + parms = dict(locals()) del parms["self"] for arg in %r: if locals()[arg] is None: diff --git a/cloud.spec b/cloud.spec index 7233f0150e2..63a7e8aae71 100644 --- a/cloud.spec +++ b/cloud.spec @@ -201,6 +201,7 @@ Requires: /sbin/service Requires: /sbin/chkconfig Requires: jna Requires: ebtables +Requires: jsvc Group: System Environment/Libraries Requires: kvm @@ -255,6 +256,7 @@ Requires: java >= 1.6.0 Requires: %{name}-utils = %{version}, %{name}-core = %{version}, %{name}-deps = %{version}, %{name}-server = %{version} Requires: %{name}-setup = %{version} Requires: %{name}-client = %{version} +Requires: jsvc License: GPLv3+ Group: System Environment/Libraries %description usage diff --git a/daemonize/COPYING b/daemonize/COPYING deleted file mode 100644 index db2569eea6d..00000000000 --- a/daemonize/COPYING +++ /dev/null @@ -1,16 +0,0 @@ -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. diff --git a/daemonize/daemonize.c b/daemonize/daemonize.c deleted file mode 100644 index 0d3e392fd0f..00000000000 --- a/daemonize/daemonize.c +++ /dev/null @@ -1,351 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on an -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. -*/ - -/* -UNIX daemonizer. Daemonizes any non-interactive console program and watches over it. -Whenever a signal is sent to this process, it halts the daemonized process as well. - -To compile: cc -o daemonize daemonize.c -Usage: ./daemonize -? -Users of this: catalina initscript -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RUNNING_DIR "/" -#define PIDFILE "/var/run/daemonize.pid" -#define VARLOGFILE "/var/log/daemon.log" -#define PROGNAME "daemonized" -#define DEFAULTUSER "root" - -char * pidfile = PIDFILE; -char * varlogfile = VARLOGFILE; -char * progname = PROGNAME; -char * user = PROGNAME; - -void initialize_syslog(const char*pn) { - openlog(pn,LOG_PID,LOG_DAEMON); - syslog(LOG_INFO, "syslog connection opened"); -} - -void cleanup_syslog() { - syslog(LOG_INFO, "syslog connection closed"); - closelog(); -} - -int killed = 0; -int killsignal = 0; -int pidfile_fd; -int varlogfile_fd; -int uid = 0; int gid = 0; -struct passwd *creds; - -void signal_handler(sig) -int sig; -{ - killsignal = sig; - switch(sig) { - case SIGCHLD: - syslog(LOG_INFO,"sigchild signal caught"); - break; - case SIGHUP: - syslog(LOG_INFO,"hangup signal caught"); - killed = 1; - break; - case SIGTERM: - syslog(LOG_INFO,"terminate signal caught"); - killed = 1; - break; - case SIGINT: - syslog(LOG_INFO,"keyboard interrupt signal caught"); - killed = 1; - break; - } -} - -int daemonize(const char*prog_name) -{ - - char str[10]; - int i; - int bufsize=1024; char *buf = malloc(1024); - - umask( S_IWGRP | S_IROTH | S_IWOTH ); /* set newly created file permissions */ - - /* test logfile */ - varlogfile_fd=open(varlogfile,O_RDWR|O_CREAT|O_APPEND,0666); - if (varlogfile_fd == -1) { - snprintf(buf,bufsize,"Could not open output file %s -- exiting",varlogfile); perror(buf); - return 1; /* exitvalue */ - } - if (uid != 0) { - chown(varlogfile,uid,gid); - } - close(varlogfile_fd); - pidfile_fd=open(pidfile,O_RDWR|O_CREAT,0666); - if (pidfile_fd<0) { - snprintf(buf,bufsize,"The PID file %s cannot be opened -- exiting",pidfile); perror(buf); - return 2; /* exitvalue */ - } - if (lockf(pidfile_fd,F_TEST,0)==1) { - snprintf(buf,bufsize,"A daemon is already running (cannot lock PID file %s) -- exiting",pidfile); perror(buf); - return 3; /* exitvalue */ - } - close(pidfile_fd); - - if(getppid()==1) return 0; /* already a daemon */ - i=fork(); - if (i < 0) return 4; /* exitvalue */ /* fork error */ - if (i > 0) exit(0); /* parent exits */ - - /* child (daemon) continues */ - setsid(); /* obtain a new process group */ - - chdir(RUNNING_DIR); /* change running directory */ - - /* close FDs and reopen to logfile */ - for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */ - varlogfile_fd=open(varlogfile,O_RDWR|O_APPEND,0666); dup(varlogfile_fd); dup(varlogfile_fd); /* handle standart I/O */ - initialize_syslog(prog_name); /* set up syslog */ - - /* PID file */ - pidfile_fd=open(pidfile,O_RDWR|O_CREAT,0666); - if (pidfile_fd<0) { - syslog(LOG_ERR,"The PID file %s cannot be opened (%m) -- exiting",pidfile); - return 2; /* exitvalue */ - } - if (lockf(pidfile_fd,F_TLOCK,0)<0) { - syslog(LOG_ERR,"A daemon is already running -- cannot lock PID file %s (%m) -- exiting",pidfile); - return 3; /* exitvalue */ - } - - /* first instance continues */ - - /* record pid to pidfile */ - sprintf(str,"%d\n",getpid()); - if (write(pidfile_fd,str,strlen(str)) < strlen(str)) { - syslog(LOG_ERR,"Could not write PID into PID file %s (%m) -- exiting",pidfile); - return 5; /* exitvalue */ - } - signal(SIGTSTP,SIG_IGN); /* ignore tty signals */ - signal(SIGTTOU,SIG_IGN); - signal(SIGTTIN,SIG_IGN); - signal(SIGHUP,signal_handler); /* catch hangup signal */ - signal(SIGTERM,signal_handler); /* catch kill signal */ - signal(SIGINT,signal_handler); /* catch keyboard interrupt signal */ - - return 0; -} - -void cleanup() { - cleanup_syslog(); - unlink(pidfile); - close(pidfile_fd); - close(varlogfile_fd); -} - -void usage(char * cmdname) { - fprintf (stderr, - "Usage: %s [options...] -- [command-specific arguments...]\n" - "Daemonize any program.\n" - "\n" - "Options:\n" - "\n" - " -l : log stdout/stderr to this *absolute* path (default "VARLOGFILE")\n" - " -u : setuid() to this user name before starting the program (default "DEFAULTUSER")\n" - " -p : lock and write the PID to this *absolute* path (default "PIDFILE")\n" - " -n : name the daemon assumes (default "PROGNAME")\n" - " -h: show this usage guide\n" - "\n" - "Exit status:\n" - " 0 if daemonized correctly\n" - " other if an error took place\n" - "", cmdname); - exit(0); -} - -int parse_args(int argc,char ** argv) { - int index; - int c; - -// pidfile = PIDFILE; -// varlogfile = VARLOGFILE; -// progname = PROGNAME; - - opterr = 0; - - while ((c = getopt (argc, argv, "l:p:n:u:")) != -1) - switch (c) - { - case 'l': - varlogfile = optarg; - break; - case 'p': - pidfile = optarg; - break; - case 'n': - progname = optarg; - break; - case 'u': - if (getuid() != 0) { - fprintf (stderr, "-u can only be used by root.\nSee help with -h\n", user); - exit(64); - } - user = optarg; - creds = getpwnam(user); - if (creds == NULL) { - fprintf (stderr, "User %s was not found in the user database.\nSee help with -h\n", user); - exit(63); - } - uid = creds->pw_uid; gid = creds->pw_gid; - break; -// case 'h': -// break; -// usage(argv[0]); /* halts after this */ - case '?': - if (optopt == '?' || optopt == 'h') - usage(argv[0]); /* halts after this */ - if (optopt == 'l' || optopt == 'p' || optopt == 'n') - fprintf (stderr, "Option -%c requires an argument.\nSee help with -h\n", optopt); - else if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\nSee help with -h\n", optopt); - else - fprintf (stderr, "Unknown option character `\\x%x'.\nSee help with -h\n", optopt); - exit(64); /* exitvalue */ - default: - abort (); - } - - for (index = optind; index < argc; index++); - - if (index == optind) { - fprintf (stderr, "You need to specify a command to run.\nSee help with -h\n", optopt); - exit(64); /* exitvalue */ - } - - return optind; -} - -int main(int argc, char** argv) -{ - /* parse command line arguments, we will use the first non-option one as the starting point */ - int i; - char ** newargv = calloc(argc+1, sizeof(char**)); - int startat = parse_args(argc,argv); - int newargc = argc - startat; - for (i = startat; i < argc; i++) { newargv[i-startat] = argv[i]; } - - /* try and daemonize */ - int daemonret = daemonize(progname); - if (daemonret) exit(daemonret); - syslog(LOG_INFO,"successfully daemonized"); - - /* fork */ - int pid, wpid, status, execret; - syslog(LOG_INFO,"starting %s in subprocess",newargv[0]); - pid = fork(); - if (pid < 0) { - /* failed to fork, damnit! */ - syslog(LOG_ERR,"could not fork to run %s as a child process (%m)",newargv[0]); - exit(4); /* exitvalue */ - } - else if (pid == 0) { - /* child */ - if (uid != 0) { - execret = setgid(gid); - if (execret == -1) { - syslog(LOG_ERR,"could not setgid() to gid %d",gid); - exit(8); /* exitvalue */ - } - execret = setuid(uid); - if (execret == -1) { - syslog(LOG_ERR,"could not setuid() to uid %d",uid); - exit(8); /* exitvalue */ - } - } - execret = execvp(newargv[0],newargv); - if (errno == 2) { - syslog(LOG_ERR,"could not run program: no such file or directory"); - exit(127); - } - if (errno == 13) { - syslog(LOG_ERR,"could not run program: permission denied"); - exit(126); - } - syslog(LOG_ERR,"could not run program: unknown reason"); - exit(255); - } - - /* parent continues here */ - syslog(LOG_INFO,"successfully started subprocess -- PID %d",pid); - int finalexit = 0; - int waitret = 0; - while (1) { - if (killed) { - kill(pid,killsignal); - killed = 0; - } - waitret = waitpid(pid,&status,WNOHANG); - if (waitret == pid) break; - usleep(250000); - } - - - if WIFEXITED(status) { - switch (WEXITSTATUS(status)) { - case 0: - syslog(LOG_INFO,"%s exited normally",newargv[0]); - break; - case 126: - syslog(LOG_ERR,"%s: permission denied",newargv[0]); - finalexit = 126; /* exitvalue */ - break; - case 127: - syslog(LOG_ERR,"%s: command not found",newargv[0]); - finalexit = 127; /* exitvalue */ - break; - default: - syslog(LOG_INFO,"%s exited abnormally with status %d",newargv[0],WEXITSTATUS(status)); - finalexit = 6; /* exitvalue */ - } - } - if WIFSIGNALED(status) { - syslog(LOG_INFO,"%s was killed with signal %d",newargv[0],WTERMSIG(status)); - finalexit = 7; /* exitvalue */ - } - - syslog(LOG_INFO,"shutting down"); - cleanup(); - exit(finalexit); -} - -/* EOF */ - diff --git a/debian/changelog b/debian/changelog index 72698351b20..44fe4b54d58 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +cloud (3.0.2) unstable; urgency=low + + * Bumping the package version to the latest release. + + -- Wido den Hollander Wed, 25 Jul 2012 14:53:31 +0200 + cloud (2.2.2) unstable; urgency=low * Bumping version number for next CloudStack release diff --git a/debian/cloud-agent-deps.install b/debian/cloud-agent-deps.install index 57122ac8ffc..13c444ec96d 100644 --- a/debian/cloud-agent-deps.install +++ b/debian/cloud-agent-deps.install @@ -1,3 +1,3 @@ /usr/share/java/cloud-google-gson-1.7.1.jar -/usr/share/java/cloud-libvirt-0.4.5.jar +/usr/share/java/libvirt-0.4.8.jar /usr/share/java/cloud-log4j-extras.jar diff --git a/debian/cloud-agent.install b/debian/cloud-agent.install index 5ef72ce9d75..aecba304d8b 100644 --- a/debian/cloud-agent.install +++ b/debian/cloud-agent.install @@ -3,6 +3,5 @@ /etc/cloud/agent/environment.properties /etc/cloud/agent/log4j-cloud.xml /etc/init.d/cloud-agent -/usr/bin/agent-runner /usr/bin/cloud-setup-agent /var/log/cloud/agent diff --git a/debian/cloud-usage.install b/debian/cloud-usage.install index 902f42910ff..ce4cb4dc5fe 100644 --- a/debian/cloud-usage.install +++ b/debian/cloud-usage.install @@ -1,6 +1,5 @@ /usr/share/java/cloud-usage.jar /etc/init.d/cloud-usage -/usr/bin/usage-runner /var/log/cloud/usage /etc/cloud/usage/usage-components.xml /etc/cloud/usage/log4j-cloud_usage.xml diff --git a/debian/control b/debian/control index 1ffb93728e4..1bc1848cf01 100644 --- a/debian/control +++ b/debian/control @@ -11,11 +11,11 @@ Provides: vmops-deps Conflicts: vmops-deps Replaces: vmops-deps Architecture: any -Depends: openjdk-6-jre, cloud-agent-deps +Depends: openjdk-6-jre Description: CloudStack library dependencies This package contains a number of third-party dependencies not shipped by distributions, required to run the CloudStack - Cloud Stack. + Management Server. Package: cloud-agent-deps Provides: cloud-agent-deps @@ -26,8 +26,7 @@ Depends: openjdk-6-jre Description: CloudStack agent library dependencies This package contains a number of third-party dependencies not shipped by distributions, required to run the CloudStack - Cloud Stack. - + Agent. Package: cloud-utils Provides: vmops-utils @@ -37,7 +36,7 @@ Architecture: any Depends: openjdk-6-jre, python Description: CloudStack utility library The CloudStack utility libraries provide a set of Java classes used - in the CloudStack Cloud Stack. + in the CloudStack environment. Package: cloud-client-ui Provides: vmops-client-ui @@ -59,7 +58,7 @@ Architecture: any Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-deps (= ${source:Version}), libservlet2.5-java Description: CloudStack server library The CloudStack server libraries provide a set of Java classes used - in the CloudStack Cloud Stack. + in the CloudStack management server. Package: cloud-agent-scripts Provides: vmops-agent-scripts, vmops-console, cloud-console, vmops-console-proxy @@ -68,11 +67,8 @@ Replaces: vmops-agent-scripts, vmops-console, cloud-console, vmops-console-proxy Architecture: any Depends: openjdk-6-jre, python, bash, bzip2, gzip, unzip, nfs-common, openssh-client Description: CloudStack agent scripts - The CloudStack agent is in charge of managing shared computing resources in - a CloudStack Cloud Stack-powered cloud. Install this package if this computer - will participate in your cloud -- this is a requirement for the CloudStack - agent. - + This package contains a number of scripts needed for the CloudStack Agent on KVM + HyperVisor hosts. The CloudStack Agent depends on this package. Package: cloud-core Provides: vmops-core @@ -90,7 +86,7 @@ Provides: vmops-client Conflicts: vmops-client Replaces: vmops-client Architecture: any -Depends: openjdk-6-jre, cloud-deps (= ${source:Version}), cloud-utils (= ${source:Version}), cloud-server (= ${source:Version}), cloud-client-ui (= ${source:Version}), cloud-setup (= ${source:Version}), cloud-agent-scripts (= ${source:Version}), cloud-python (= ${source:Version}), tomcat6, libws-commons-util-java, libcommons-dbcp-java, libcommons-collections-java, libcommons-httpclient-java, sysvinit-utils, chkconfig, sudo, jsvc, python-mysqldb, python-paramiko, augeas-tools, genisoimage, cloud-system-iso +Depends: openjdk-6-jre, cloud-deps (= ${source:Version}), cloud-utils (= ${source:Version}), cloud-server (= ${source:Version}), cloud-client-ui (= ${source:Version}), cloud-setup (= ${source:Version}), cloud-python (= ${source:Version}), tomcat6, libws-commons-util-java, libcommons-dbcp-java, libcommons-collections-java, libcommons-httpclient-java, sysvinit-utils, chkconfig, sudo, jsvc, python-mysqldb, python-paramiko, augeas-tools, genisoimage, cloud-system-iso Description: CloudStack client The CloudStack management server is the central point of coordination, management, and intelligence in the CloudStack Cloud Stack. This package @@ -123,17 +119,17 @@ Provides: vmops-agent Conflicts: vmops-agent Replaces: vmops-agent Architecture: any -Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-agent-deps (= ${source:Version}), python, cloud-python (= ${source:Version}), cloud-agent-libs (= ${source:Version}), cloud-agent-scripts (= ${source:Version}), libcommons-httpclient-java, libcommons-collections-java, libcommons-dbcp-java, libcommons-pool-java, libcommons-logging-java, libvirt0, cloud-daemonize, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, uuid-runtime, rsync, grep, iproute, ebtables, vlan, libcglib-java, libcommons-httpclient-java, libservlet2.5-java, liblog4j1.2-java, libjna-java, wget +Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-agent-deps (= ${source:Version}), python, cloud-python (= ${source:Version}), cloud-agent-libs (= ${source:Version}), cloud-agent-scripts (= ${source:Version}), libcommons-httpclient-java, libcommons-collections-java, libcommons-dbcp-java, libcommons-pool-java, libcommons-logging-java, libvirt0, sysvinit-utils, chkconfig, qemu-kvm, libvirt-bin, uuid-runtime, rsync, grep, iproute, ebtables, vlan, libcglib-java, libcommons-httpclient-java, libservlet2.5-java, liblog4j1.2-java, libjna-java, wget, jsvc, lsb-base (>= 3.2) Description: CloudStack agent The CloudStack agent is in charge of managing shared computing resources in - a CloudStack Cloud Stack-powered cloud. Install this package if this computer - will participate in your cloud. + a CloudStack powered cloud. Install this package if this computer + will participate in your cloud as a KVM HyperVisor. Package: cloud-system-iso Architecture: any Description: CloudStack system iso The CloudStack agent is in charge of managing shared computing resources in - a CloudStack Cloud Stack-powered cloud. Install this package if this computer + a CloudStack powered cloud. Install this package if this computer will participate in your cloud. Package: cloud-usage @@ -141,7 +137,7 @@ Provides: vmops-usage Conflicts: vmops-usage Replaces: vmops-usage Architecture: any -Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-deps (= ${source:Version}), cloud-server (= ${source:Version}), cloud-daemonize (= ${source:Version}), cloud-setup (= ${source:Version}), cloud-client (= ${source:Version}) +Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-deps (= ${source:Version}), cloud-server (= ${source:Version}), cloud-setup (= ${source:Version}), cloud-client (= ${source:Version}), jsvc Description: CloudStack usage monitor The CloudStack usage monitor provides usage accounting across the entire cloud for cloud operators to charge based on usage parameters. @@ -149,6 +145,6 @@ Description: CloudStack usage monitor Package: cloud-cli Provides: cloud-cli Architecture: any -Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-deps (= ${source:Version}), cloud-server (= ${source:Version}), cloud-daemonize (= ${source:Version}), cloud-setup (= ${source:Version}), cloud-client (= ${source:Version}) +Depends: openjdk-6-jre, cloud-utils (= ${source:Version}), cloud-core (= ${source:Version}), cloud-deps (= ${source:Version}), cloud-server (= ${source:Version}), cloud-setup (= ${source:Version}), cloud-client (= ${source:Version}) Description: CloudStack commandline tool The CloudStack commandline tool for invoking APi diff --git a/debian/copyright b/debian/copyright index cee717125ad..13a83393a91 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,10 +1,16 @@ -Copyright 2012 Citrix Systems, Inc. Licensed under the -Apache License, Version 2.0 (the "License"); you may not use this -file except in compliance with the License. Citrix Systems, Inc. -reserves all rights not expressly granted by the License. -You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +# 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. diff --git a/deps/.classpath b/deps/.classpath index b9eb504b959..0ae345797a1 100755 --- a/deps/.classpath +++ b/deps/.classpath @@ -15,7 +15,7 @@ - + diff --git a/deps/cloud-libvirt-0.4.5.jar b/deps/libvirt-0.4.8.jar similarity index 63% rename from deps/cloud-libvirt-0.4.5.jar rename to deps/libvirt-0.4.8.jar index 9d0a1dfbe60..3a30a1ae551 100644 Binary files a/deps/cloud-libvirt-0.4.5.jar and b/deps/libvirt-0.4.8.jar differ diff --git a/patches/systemvm/debian/config/root/savepassword.sh b/patches/systemvm/debian/config/root/savepassword.sh index c2c89e2b318..80a6928df0e 100755 --- a/patches/systemvm/debian/config/root/savepassword.sh +++ b/patches/systemvm/debian/config/root/savepassword.sh @@ -1,17 +1,20 @@ #!/bin/bash -# Copyright 2012 Citrix Systems, Inc. Licensed under the -# Apache License, Version 2.0 (the "License"); you may not use this -# file except in compliance with the License. Citrix Systems, Inc. -# reserves all rights not expressly granted by the License. -# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Automatically generated by addcopyright.py at 04/03/2012 - +# 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. diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index a8c61f6fad8..685a321bcca 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -2465,7 +2465,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (cmd.isAttach()) { vmMo.mountToolsInstaller(); } else { - vmMo.unmountToolsInstaller(); + try{ + vmMo.unmountToolsInstaller(); + }catch(Throwable e){ + vmMo.detachIso(null); + } } return new Answer(cmd); diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java index a8208ae1e8b..3fa61167efa 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/AddExternalLoadBalancerCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import org.apache.log4j.Logger; @@ -102,4 +107,4 @@ public class AddExternalLoadBalancerCmd extends BaseCmd { throw new ServerApiException(BaseCmd.INTERNAL_ERROR, cre.getMessage()); } } -} \ No newline at end of file +} diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/AddF5LoadBalancerCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/AddF5LoadBalancerCmd.java index bec09989abd..13c443e7cf0 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/AddF5LoadBalancerCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/AddF5LoadBalancerCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import org.apache.log4j.Logger; @@ -127,4 +132,4 @@ public class AddF5LoadBalancerCmd extends BaseAsyncCmd { public long getEntityOwnerId() { return UserContext.current().getCaller().getId(); } -} \ No newline at end of file +} diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/ConfigureF5LoadBalancerCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/ConfigureF5LoadBalancerCmd.java index 20b2e5a3b8c..9f5217c3280 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/ConfigureF5LoadBalancerCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/ConfigureF5LoadBalancerCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import org.apache.log4j.Logger; diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteExternalLoadBalancerCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteExternalLoadBalancerCmd.java index c4b903a5c81..2c89a4a6a9d 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteExternalLoadBalancerCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteExternalLoadBalancerCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import org.apache.log4j.Logger; diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteF5LoadBalancerCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteF5LoadBalancerCmd.java index 4fcd734a05f..959819b1588 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteF5LoadBalancerCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/DeleteF5LoadBalancerCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import org.apache.log4j.Logger; diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/ListExternalLoadBalancersCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/ListExternalLoadBalancersCmd.java index 6551985363a..acb71b06c0a 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/ListExternalLoadBalancersCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/ListExternalLoadBalancersCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import java.util.ArrayList; diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java index efa71b554eb..f2fa071b53e 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancerNetworksCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import java.util.ArrayList; diff --git a/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java index 228bab5623a..fe4cb67bd01 100644 --- a/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java +++ b/plugins/network-elements/f5/src/com/cloud/api/commands/ListF5LoadBalancersCmd.java @@ -1,15 +1,20 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + package com.cloud.api.commands; import java.util.ArrayList; diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java index 283293f4db5..1a88de2cb6c 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/AddNetscalerLoadBalancerCmd.java @@ -1,15 +1,18 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 + package com.cloud.api.commands; import org.apache.log4j.Logger; diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/ConfigureNetscalerLoadBalancerCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/ConfigureNetscalerLoadBalancerCmd.java index f5633a34c5d..de1a7c84ef5 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/commands/ConfigureNetscalerLoadBalancerCmd.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/ConfigureNetscalerLoadBalancerCmd.java @@ -1,15 +1,17 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.api.commands; import java.util.List; diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/DeleteNetscalerLoadBalancerCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/DeleteNetscalerLoadBalancerCmd.java index a2cb54058e0..b063fdf6396 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/commands/DeleteNetscalerLoadBalancerCmd.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/DeleteNetscalerLoadBalancerCmd.java @@ -1,15 +1,18 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 + package com.cloud.api.commands; import org.apache.log4j.Logger; diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancerNetworksCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancerNetworksCmd.java index 909956048d3..c0c5950d57e 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancerNetworksCmd.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancerNetworksCmd.java @@ -1,15 +1,17 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.api.commands; import java.util.ArrayList; diff --git a/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancersCmd.java b/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancersCmd.java index daca1112de0..98fe6e95df7 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancersCmd.java +++ b/plugins/network-elements/netscaler/src/com/cloud/api/commands/ListNetscalerLoadBalancersCmd.java @@ -1,15 +1,17 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.api.commands; import java.util.ArrayList; diff --git a/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java b/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java index def048e792f..919270349a9 100644 --- a/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java +++ b/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java @@ -1,15 +1,18 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 + package com.cloud.storage.allocator; import java.util.ArrayList; diff --git a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java index 8a056cc4545..7c6e52f6659 100644 --- a/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java +++ b/plugins/user-authenticators/ldap/src/com/cloud/server/auth/LDAPUserAuthenticator.java @@ -1,15 +1,18 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// package com.cloud.server.auth; import java.util.HashMap; diff --git a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java index 2aec4a7937f..5c5d21fe08f 100644 --- a/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java +++ b/plugins/user-authenticators/md5/src/com/cloud/server/auth/MD5UserAuthenticator.java @@ -1,15 +1,18 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Automatically generated by addcopyright.py at 04/03/2012 +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright ownership. +// The ASF licenses this file to You under the Apache License, Version 2.0 +// (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package com.cloud.server.auth; import java.util.Map; diff --git a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java index f05a8cd815f..006daf98e9b 100644 --- a/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java +++ b/plugins/user-authenticators/plain-text/src/com/cloud/server/auth/PlainTextUserAuthenticator.java @@ -1,15 +1,18 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by the License. -// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 + package com.cloud.server.auth; import java.math.BigInteger; diff --git a/project_admin/templates/committerAnnounce.txt b/project_admin/templates/committerAnnounce.txt index 2dd6ca27ac5..f2450dccea2 100644 --- a/project_admin/templates/committerAnnounce.txt +++ b/project_admin/templates/committerAnnounce.txt @@ -16,3 +16,8 @@ announce that they have accepted. Being a committer enables easier contribution to the project since there is no need to go via the patch submission process. This should enable better productivity. + +Please join me in congratulating ######### + +--#####Name#### +on behalf of the CloudStack PPMC diff --git a/scripts/vm/hypervisor/kvm/kvmheartbeat.sh b/scripts/vm/hypervisor/kvm/kvmheartbeat.sh index c63465554c1..7293b14a531 100755 --- a/scripts/vm/hypervisor/kvm/kvmheartbeat.sh +++ b/scripts/vm/hypervisor/kvm/kvmheartbeat.sh @@ -133,14 +133,14 @@ write_hbLog() { } check_hbLog() { - oldTimeStamp=$(cat $hbFile) - sleep $interval &> /dev/null - newTimeStamp=$(cat $hbFile) - if [ $newTimeStamp -gt $oldTimeStamp ] + now=$(date +%s) + hb=$(cat $hbFile) + diff=`expr $now - $hb` + if [ $diff -gt $interval ] then - return 0 + return 1 fi - return 1 + return 0 } if [ "$rflag" == "1" ] diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 4c88e2b2be6..433d2637e52 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -760,7 +760,9 @@ public class ApiResponseHelper implements ResponseGenerator { ipResponse.setIsSystem(ipAddress.getSystem()); // get account information - populateOwner(ipResponse, ipAddress); + if (ipAddress.getAllocatedToAccountId() != null) { + populateOwner(ipResponse, ipAddress); + } ipResponse.setForVirtualNetwork(forVirtualNetworks); ipResponse.setStaticNat(ipAddress.isOneToOneNat()); diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java index df2fc9ec741..6c0af1b0528 100755 --- a/server/src/com/cloud/configuration/Config.java +++ b/server/src/com/cloud/configuration/Config.java @@ -215,7 +215,7 @@ public enum Config { ApplyAllocationAlgorithmToPods("Advanced", ManagementServer.class, Boolean.class, "apply.allocation.algorithm.to.pods", "false", "If true, deployment planner applies the allocation heuristics at pods first in the given datacenter during VM resource allocation", "true,false"), VmUserDispersionWeight("Advanced", ManagementServer.class, Float.class, "vm.user.dispersion.weight", "1", "Weight for user dispersion heuristic (as a value between 0 and 1) applied to resource allocation during vm deployment. Weight for capacity heuristic will be (1 - weight of user dispersion)", null), VmAllocationAlgorithm("Advanced", ManagementServer.class, String.class, "vm.allocation.algorithm", "random", "'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit' : Order in which hosts within a cluster will be considered for VM/volume allocation.", null), - EndpointeUrl("Advanced", ManagementServer.class, String.class, "endpointe.url", "http://localhost:8080/client/api", "Endpointe Url", "The endpoint callback URL"), + EndpointeUrl("Advanced", ManagementServer.class, String.class, "endpointe.url", "http://localhost:8080/client/api", "Endpointe Url", null), ElasticLoadBalancerEnabled("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.enabled", "false", "Whether the load balancing service is enabled for basic zones", "true,false"), ElasticLoadBalancerNetwork("Advanced", ManagementServer.class, String.class, "network.loadbalancer.basiczone.elb.network", "guest", "Whether the elastic load balancing service public ips are taken from the public or guest network", "guest,public"), ElasticLoadBalancerVmMemory("Advanced", ManagementServer.class, Integer.class, "network.loadbalancer.basiczone.elb.vm.ram.size", "128", "Memory in MB for the elastic load balancer vm", null), diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index d04a14018e7..c96ea52b299 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -3010,6 +3010,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } + sc.addAnd("id", SearchCriteria.Op.SC, accountSC); return _networksDao.search(sc, searchFilter); } diff --git a/server/src/com/cloud/network/guru/ControlNetworkGuru.java b/server/src/com/cloud/network/guru/ControlNetworkGuru.java index 6cbed8dffc2..ec8887f340c 100755 --- a/server/src/com/cloud/network/guru/ControlNetworkGuru.java +++ b/server/src/com/cloud/network/guru/ControlNetworkGuru.java @@ -173,9 +173,15 @@ public class ControlNetworkGuru extends PodBasedNetworkGuru implements NetworkGu DataCenterVO dcVo = _dcDao.findById(dcId); if(dcVo.getNetworkType() != NetworkType.Basic) { super.release(nic, vm, reservationId); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Released nic: " + nic); + } return true; } else { nic.deallocate(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Released nic: " + nic); + } return true; } } @@ -183,6 +189,9 @@ public class ControlNetworkGuru extends PodBasedNetworkGuru implements NetworkGu _dcDao.releaseLinkLocalIpAddress(nic.getId(), reservationId); nic.deallocate(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Released nic: " + nic); + } return true; } diff --git a/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java b/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java index 12f23cca99b..b513325d5ee 100755 --- a/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java +++ b/server/src/com/cloud/network/guru/PodBasedNetworkGuru.java @@ -149,6 +149,10 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru { nic.deallocate(); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Released nic: " + nic); + } + return true; } diff --git a/server/src/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/com/cloud/network/guru/PublicNetworkGuru.java index 46477f375d4..f23ff9af950 100755 --- a/server/src/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/com/cloud/network/guru/PublicNetworkGuru.java @@ -198,6 +198,10 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { txn.commit(); } nic.deallocate(); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Deallocated nic: " + nic); + } } @Override diff --git a/server/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java b/server/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java index 0c9bdc57995..81c20e3ccdb 100644 --- a/server/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java +++ b/server/src/com/cloud/network/security/dao/SecurityGroupDaoImpl.java @@ -113,5 +113,19 @@ public class SecurityGroupDaoImpl extends GenericDaoBase boolean result = super.remove(id); txn.commit(); return result; + } + + @Override + @DB + public boolean expunge(Long id) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + SecurityGroupVO entry = findById(id); + if (entry != null) { + _tagsDao.removeByIdAndType(id, TaggedResourceType.SecurityGroup); + } + boolean result = super.expunge(id); + txn.commit(); + return result; } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 93c2f4ca2a9..bcdafa98cef 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -1691,23 +1691,30 @@ public class ManagementServerImpl implements ManagementServer { Boolean staticNat = cmd.getIsStaticNat(); Map tags = cmd.getTags(); - Account caller = UserContext.current().getCaller(); - List permittedAccounts = new ArrayList(); - + Boolean isAllocated = cmd.isAllocatedOnly(); if (isAllocated == null) { isAllocated = Boolean.TRUE; } - - Ternary domainIdRecursiveListProject = new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); - _accountMgr.buildACLSearchParameters(caller, cmd.getId(), cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); - Long domainId = domainIdRecursiveListProject.first(); - Boolean isRecursive = domainIdRecursiveListProject.second(); - ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); - + Filter searchFilter = new Filter(IPAddressVO.class, "address", false, cmd.getStartIndex(), cmd.getPageSizeVal()); SearchBuilder sb = _publicIpAddressDao.createSearchBuilder(); - _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + Long domainId = null; + Boolean isRecursive = null; + List permittedAccounts = new ArrayList(); + ListProjectResourcesCriteria listProjectResourcesCriteria = null; + if (isAllocated) { + Account caller = UserContext.current().getCaller(); + + Ternary domainIdRecursiveListProject = + new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); + _accountMgr.buildACLSearchParameters(caller, cmd.getId(), cmd.getAccountName(), cmd.getProjectId(), + permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); + domainId = domainIdRecursiveListProject.first(); + isRecursive = domainIdRecursiveListProject.second(); + listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + } sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); sb.and("address", sb.entity().getAddress(), SearchCriteria.Op.EQ); @@ -1758,13 +1765,10 @@ public class ManagementServerImpl implements ManagementServer { vlanType = VlanType.VirtualNetwork; } - // don't show SSVM/CPVM ips - if (vlanType == VlanType.VirtualNetwork && (allocatedOnly)) { - sb.and("associatedNetworkId", sb.entity().getAssociatedWithNetworkId(), SearchCriteria.Op.NNULL); - } - SearchCriteria sc = sb.create(); - _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + if (isAllocated) { + _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + } sc.setJoinParameters("vlanSearch", "vlanType", vlanType); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 27d8cb71e83..d94bada2866 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -3210,10 +3210,25 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag } else { if (assignedPool.getId() != vol.getPoolId()) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + vol + " is not recreatable! Cannot recreate on storagepool: " + assignedPool); + s_logger.debug("Mismatch in storage pool " + assignedPool + " assigned by deploymentPlanner and the one associated with volume " + vol); + } + if (vm.getServiceOffering().getUseLocalStorage()) + { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Local volume " + vol + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner"); + } + recreateVols.add(vol); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Shared volume " + vol + " will be migrated on storage pool " + assignedPool + " assigned by deploymentPlanner"); + } + try { + Volume migratedVol = migrateVolume(vol.getId(), assignedPool.getId()); + vm.addDisk(new VolumeTO(migratedVol, assignedPool)); + } catch (ConcurrentOperationException e) { + throw new StorageUnavailableException("Volume migration failed for " + vol, Volume.class, vol.getId()); + } } - throw new StorageUnavailableException("Volume is not recreatable, Unable to create " + vol, Volume.class, vol.getId()); - // copy volume usecase - not yet developed. } else { StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); vm.addDisk(new VolumeTO(vol, pool)); diff --git a/server/src/com/cloud/storage/dao/VMTemplateDao.java b/server/src/com/cloud/storage/dao/VMTemplateDao.java index ed80aae649b..f5b6913df8a 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDao.java @@ -63,6 +63,7 @@ public interface VMTemplateDao extends GenericDao { public List listByHypervisorType(List hyperTypes); public List publicIsoSearch(Boolean bootable, boolean listRemoved, Map tags); + public List userIsoSearch(boolean listRemoved); VMTemplateVO findSystemVMTemplate(long zoneId); VMTemplateVO findSystemVMTemplate(long zoneId, HypervisorType hType); diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index 3c30076295c..2a0dfc85559 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -84,7 +84,6 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem DomainDao _domainDao; @Inject DataCenterDao _dcDao; - private final String SELECT_TEMPLATE_HOST_REF = "SELECT t.id, h.data_center_id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; @@ -93,7 +92,6 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem private final String SELECT_TEMPLATE_SWIFT_REF = "SELECT t.id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; - protected SearchBuilder TemplateNameSearch; protected SearchBuilder UniqueNameSearch; protected SearchBuilder tmpltTypeSearch; @@ -106,6 +104,7 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem private SearchBuilder PublicSearch; private SearchBuilder NameAccountIdSearch; private SearchBuilder PublicIsoSearch; + private SearchBuilder UserIsoSearch; private GenericSearchBuilder CountTemplatesByAccount; ResourceTagsDaoImpl _tagsDao = ComponentLocator.inject(ResourceTagsDaoImpl.class); @@ -189,6 +188,22 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem return listBy(sc); } + @Override + public List userIsoSearch(boolean listRemoved){ + + SearchBuilder sb = null; + sb = UserIsoSearch; + SearchCriteria sc = sb.create(); + + sc.setParameters("format", Storage.ImageFormat.ISO); + sc.setParameters("type", TemplateType.USER.toString()); + + if (!listRemoved) { + sc.setParameters("removed", (Object)null); + } + + return listBy(sc); + } @Override public List listAllSystemVMTemplates() { SearchCriteria sc = tmpltTypeSearch.create(); @@ -298,7 +313,12 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem PublicIsoSearch.and("type", PublicIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); PublicIsoSearch.and("bootable", PublicIsoSearch.entity().isBootable(), SearchCriteria.Op.EQ); PublicIsoSearch.and("removed", PublicIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); - + + UserIsoSearch = createSearchBuilder(); + UserIsoSearch.and("format", UserIsoSearch.entity().getFormat(), SearchCriteria.Op.EQ); + UserIsoSearch.and("type", UserIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); + UserIsoSearch.and("removed", UserIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); + tmpltTypeHyperSearch = createSearchBuilder(); tmpltTypeHyperSearch.and("templateType", tmpltTypeHyperSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); SearchBuilder hostHyperSearch = _hostDao.createSearchBuilder(); @@ -648,28 +668,44 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem pstmt = txn.prepareStatement(sql); rs = pstmt.executeQuery(); + while (rs.next()) { - Pair templateZonePair = new Pair(rs.getLong(1), rs.getLong(2)); - templateZonePairList.add(templateZonePair); + Pair templateZonePair = new Pair(rs.getLong(1), rs.getLong(2)); + templateZonePairList.add(templateZonePair); } - //for now, defaulting pageSize to a large val if null; may need to revisit post 2.2RC2 if(isIso && templateZonePairList.size() < (pageSize != null ? pageSize : 500) - && templateFilter != TemplateFilter.community + && templateFilter != TemplateFilter.community && !(templateFilter == TemplateFilter.self && !BaseCmd.isRootAdmin(caller.getType())) ){ //evaluates to true If root admin and filter=self - List publicIsos = publicIsoSearch(bootable, false, tags); - for( int i=0; i < publicIsos.size(); i++){ - if (keyword != null && publicIsos.get(i).getName().contains(keyword)) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - continue; - } else if (name != null && publicIsos.get(i).getName().contains(name)) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - continue; - }else if (keyword == null && name == null){ - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); + + List publicIsos = publicIsoSearch(bootable, false, tags); + List userIsos = userIsoSearch(false); + + //Listing the ISOs according to the page size.Restricting the total no. of ISOs on a page + //to be less than or equal to the pageSize parameter + + int i=0; + + if (startIndex > userIsos.size()) { + i=(int) (startIndex - userIsos.size()); + } + + for (; i < publicIsos.size(); i++) { + if(templateZonePairList.size() >= pageSize){ + break; + } else { + if (keyword != null && publicIsos.get(i).getName().contains(keyword)) { + templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); + continue; + } else if (name != null && publicIsos.get(i).getName().contains(name)) { + templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); + continue; + } else if (keyword == null && name == null){ + templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); + } + } } - } - } + } } catch (Exception e) { s_logger.warn("Error listing templates", e); } finally { diff --git a/server/src/com/cloud/storage/upload/UploadMonitorImpl.java b/server/src/com/cloud/storage/upload/UploadMonitorImpl.java index 25ada43f49d..891d44f8912 100755 --- a/server/src/com/cloud/storage/upload/UploadMonitorImpl.java +++ b/server/src/com/cloud/storage/upload/UploadMonitorImpl.java @@ -437,8 +437,6 @@ public class UploadMonitorImpl implements UploadMonitor { @Override public void run() { try { - s_logger.info("Extract Monitor Garbage Collection Thread is running."); - GlobalLock scanLock = GlobalLock.getInternLock("uploadmonitor.storageGC"); try { if (scanLock.lock(3)) { @@ -476,24 +474,26 @@ public class UploadMonitorImpl implements UploadMonitor { if( getTimeDiff(extractJob.getLastUpdated()) > EXTRACT_URL_LIFE_LIMIT_IN_SECONDS ){ String path = extractJob.getInstallPath(); HostVO secStorage = ApiDBUtils.findHostById(extractJob.getHostId()); - s_logger.debug("Sending deletion of extract URL "+extractJob.getUploadUrl()); + // Would delete the symlink for the Type and if Type == VOLUME then also the volume DeleteEntityDownloadURLCommand cmd = new DeleteEntityDownloadURLCommand(path, extractJob.getType(),extractJob.getUploadUrl(), secStorage.getParent()); HostVO ssvm = _ssvmMgr.pickSsvmHost(secStorage); if( ssvm == null ) { - s_logger.warn("There is no secondary storage VM for secondary storage host " + extractJob.getHostId()); - continue; + s_logger.warn("UploadMonitor cleanup: There is no secondary storage VM for secondary storage host " + extractJob.getHostId()); + continue; //TODO: why continue? why not break? + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("UploadMonitor cleanup: Sending deletion of extract URL "+ extractJob.getUploadUrl() + " to ssvm " + ssvm.getId()); } - try { - send(ssvm.getId(), cmd, null); + send(ssvm.getId(), cmd, null); //TODO: how do you know if it was successful? _uploadDao.remove(extractJob.getId()); } catch (AgentUnavailableException e) { - s_logger.warn("Unable to delete the link for " +extractJob.getType()+ " id=" +extractJob.getTypeId()+ " url="+extractJob.getUploadUrl(), e); + s_logger.warn("UploadMonitor cleanup: Unable to delete the link for " + extractJob.getType()+ " id=" + extractJob.getTypeId()+ " url="+ extractJob.getUploadUrl() + " on ssvm " + ssvm.getId(), e); } } } } - + } diff --git a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java index f79eba4a17f..84a26924a71 100644 --- a/server/src/com/cloud/tags/TaggedResourceManagerImpl.java +++ b/server/src/com/cloud/tags/TaggedResourceManagerImpl.java @@ -233,7 +233,7 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager Transaction txn = Transaction.currentTxn(); txn.start(); - for (String tag : tags.keySet()) { + for (String key : tags.keySet()) { for (String resourceId : resourceIds) { Long id = getResourceId(resourceId, resourceType); String resourceUuid = getUuid(resourceId, resourceType); @@ -254,10 +254,16 @@ public class TaggedResourceManagerImpl implements TaggedResourceService, Manager _accountMgr.checkAccess(caller, _domainMgr.getDomain(domainId)); } else { throw new PermissionDeniedException("Account " + caller + " doesn't have permissions to create tags" + - " for resource " + tag); + " for resource " + key); + } + + String value = tags.get(key); + + if (value == null || value.isEmpty()) { + throw new InvalidParameterValueException("Value for the key " + key + " is either null or empty"); } - ResourceTagVO resourceTag = new ResourceTagVO(tag, tags.get(tag), accountDomainPair.first(), + ResourceTagVO resourceTag = new ResourceTagVO(key, value, accountDomainPair.first(), accountDomainPair.second(), id, resourceType, customer, resourceUuid); resourceTag = _resourceTagDao.persist(resourceTag); diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index e66b886839d..0a11dc4d884 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -2225,4 +2225,9 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag } } + + @Override + public UserAccount getUserByApiKey(String apiKey) { + return _userAccountDao.getUserByApiKey(apiKey); + } } diff --git a/server/src/com/cloud/user/dao/UserAccountDao.java b/server/src/com/cloud/user/dao/UserAccountDao.java index f0907192c46..eb4e0cdf517 100644 --- a/server/src/com/cloud/user/dao/UserAccountDao.java +++ b/server/src/com/cloud/user/dao/UserAccountDao.java @@ -23,4 +23,5 @@ import com.cloud.utils.db.GenericDao; public interface UserAccountDao extends GenericDao { UserAccount getUserAccount(String username, Long domainId); boolean validateUsernameInDomain(String username, Long domainId); + UserAccount getUserByApiKey(String apiKey); } diff --git a/server/src/com/cloud/user/dao/UserAccountDaoImpl.java b/server/src/com/cloud/user/dao/UserAccountDaoImpl.java index 5cc7434c886..663e58fba4f 100644 --- a/server/src/com/cloud/user/dao/UserAccountDaoImpl.java +++ b/server/src/com/cloud/user/dao/UserAccountDaoImpl.java @@ -21,10 +21,20 @@ import javax.ejb.Local; import com.cloud.user.UserAccount; import com.cloud.user.UserAccountVO; import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @Local(value={UserAccountDao.class}) public class UserAccountDaoImpl extends GenericDaoBase implements UserAccountDao { + + protected final SearchBuilder userAccountSearch; + + protected UserAccountDaoImpl() { + userAccountSearch = createSearchBuilder(); + userAccountSearch.and("apiKey", userAccountSearch.entity().getApiKey(), SearchCriteria.Op.EQ); + userAccountSearch.done(); + } + @Override public UserAccount getUserAccount(String username, Long domainId) { if ((username == null) || (domainId == null)) { @@ -45,4 +55,11 @@ public class UserAccountDaoImpl extends GenericDaoBase impl } return false; } + + @Override + public UserAccount getUserByApiKey(String apiKey) { + SearchCriteria sc = userAccountSearch.create(); + sc.setParameters("apiKey",apiKey); + return findOneBy(sc); + } } diff --git a/server/test/com/cloud/user/MockAccountManagerImpl.java b/server/test/com/cloud/user/MockAccountManagerImpl.java index f4342a3146c..8f6d4fa21a5 100644 --- a/server/test/com/cloud/user/MockAccountManagerImpl.java +++ b/server/test/com/cloud/user/MockAccountManagerImpl.java @@ -336,4 +336,13 @@ public class MockAccountManagerImpl implements Manager, AccountManager { // TODO Auto-generated method stub } + /* (non-Javadoc) + * @see com.cloud.user.AccountService#getUserByApiKey(java.lang.String) + */ + @Override + public UserAccount getUserByApiKey(String apiKey) { + // TODO Auto-generated method stub + return null; + } + } diff --git a/tools/devcloud/veewee/README b/tools/devcloud/veewee/README new file mode 100644 index 00000000000..c9299e504b4 --- /dev/null +++ b/tools/devcloud/veewee/README @@ -0,0 +1,5 @@ +Install DevCloud Base system: +1. get code from https://github.com/jedi4ever/veewee, and install +2. veewee vbox define devcloud ubuntu-12.04-server-i386 +3. put these two files(definition.rb and preseed.cfg) under ./definition/devcloud/ +3. veewee vbox build devcloud diff --git a/tools/devcloud/veewee/definition.rb b/tools/devcloud/veewee/definition.rb new file mode 100644 index 00000000000..d025ce9a4ea --- /dev/null +++ b/tools/devcloud/veewee/definition.rb @@ -0,0 +1,56 @@ +# 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. + + +Veewee::Session.declare({ + :cpu_count => '1', + :memory_size=> '2048', + :disk_size => '20000', + :disk_format => 'VMDK', + :hostiocache => 'off', + :os_type_id => 'Ubuntu', + :iso_file => "ubuntu-12.04-server-i386.iso", + :iso_src => "http://releases.ubuntu.com/12.04/ubuntu-12.04-server-i386.iso", + :iso_md5 => '32184a83c8b5e6031e1264e5c499bc03', + :iso_download_timeout => "1000", + :boot_wait => "4", + :ioapic => "on", + :nestedpaging => "on", + :hwvirtex => "on", + :boot_cmd_sequence => [ + '', + '/install/vmlinuz noapic preseed/url=http://%IP%:%PORT%/preseed.cfg ', + 'debian-installer=en_US auto locale=en_US kbd-chooser/method=us ', + 'hostname=%NAME% ', + 'fb=false debconf/frontend=noninteractive ', + 'keyboard-configuration/layout=USA keyboard-configuration/variant=USA console-setup/ask_detect=false ', + 'initrd=/install/initrd.gz -- ' +], + :kickstart_port => "7122", + :kickstart_timeout => "10000", + :kickstart_file => "preseed.cfg", + :ssh_login_timeout => "10000", + :ssh_user => "devcloud", + :ssh_password => "devcloud", + :ssh_key => "", + :ssh_host_port => "2222", + :ssh_guest_port => "22", + :sudo_cmd => "echo '%p'|sudo -S sh '%f'", + :shutdown_cmd => "shutdown -P now", + :postinstall_files => [ "postinstall.sh"], + :postinstall_timeout => "10000" +}) diff --git a/tools/devcloud/veewee/preseed.cfg b/tools/devcloud/veewee/preseed.cfg new file mode 100644 index 00000000000..4a97171e76f --- /dev/null +++ b/tools/devcloud/veewee/preseed.cfg @@ -0,0 +1,122 @@ +# 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. + +## Options to set on the command line +d-i debian-installer/locale string en_US.utf8 +d-i console-setup/ask_detect boolean false +d-i console-setup/layout string USA + +#d-i netcfg/get_hostname string dummy +d-i netcfg/get_hostname string devcloud +d-i netcfg/get_domain string cloudstack.org + +# Continue without a default route +# Not working , specify a dummy in the DHCP +#d-i netcfg/no_default_route boolean + +d-i time/zone string UTC +d-i clock-setup/utc-auto boolean true +d-i clock-setup/utc boolean true + +d-i kbd-chooser/method select American English + +d-i netcfg/wireless_wep string + +d-i base-installer/kernel/override-image string linux-server +#d-i base-installer/kernel/override-image string linux-image-2.6.32-21-generic + +# Choices: Dialog, Readline, Gnome, Kde, Editor, Noninteractive +d-i debconf debconf/frontend select Noninteractive + +d-i pkgsel/install-language-support boolean false +tasksel tasksel/first multiselect standard, ubuntu-server + +#d-i partman-auto/method string regular +d-i partman-auto/method string lvm +d-i partman-auto-lvm/no_boot boolean true +d-i partman-auto/disk string /dev/sda +d-i partman-auto-lvm/new_vg_name string devcloud +d-i partman-auto/purge_lvm_from_device boolean true +d-i partman-basicfilesystems/no_swap boolean false + +d-i partman-lvm/confirm boolean true +d-i partman-lvm/device_remove_lvm boolean true +d-i partman-auto/choose_recipe select devcloud + +d-i partman/confirm_write_new_label boolean true +d-i partman/confirm_nooverwrite boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman-auto/expert_recipe string \ +devcloud :: \ +4000 4500 4500 ext4 method{ lvm } \ +$lvmok{ } mountpoint{ / } lv_name{ root } \ +format{ } use_filesystem{ } filesystem{ ext4 } \ +.\ +15000 15000 15000 ext4 method{ lvm } \ +$lvmok{ } mountpoint{ /opt } lv_name{ data } \ +format{ } use_filesystem{ } filesystem{ ext4 } \ +. + +#http://ubuntu-virginia.ubuntuforums.org/showthread.php?p=9626883 +#Message: "write the changes to disk and configure lvm preseed" +#http://serverfault.com/questions/189328/ubuntu-kickstart-installation-using-lvm-waits-for-input +#preseed partman-lvm/confirm_nooverwrite boolean true + +# Write the changes to disks and configure LVM? +d-i partman-lvm/confirm boolean true +d-i partman-lvm/confirm_nooverwrite boolean true +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select Finish +d-i partman/confirm_nooverwrite boolean true +d-i partman/confirm boolean true +d-i partman-auto-lvm/guided_size string max + +## Default user, we can get away with a recipe to change this +d-i passwd/user-fullname string devcloud +d-i passwd/username string devcloud +d-i passwd/user-password password devcloud +d-i passwd/user-password-again password devcloud +d-i user-setup/encrypt-home boolean false +d-i user-setup/allow-password-weak boolean true + +## minimum is puppet and ssh and ntp +# Individual additional packages to install +d-i pkgsel/include string openssh-server ntp + +# Whether to upgrade packages after debootstrap. +# Allowed values: none, safe-upgrade, full-upgrade +d-i pkgsel/upgrade select full-upgrade + +d-i grub-installer/only_debian boolean true +d-i grub-installer/with_other_os boolean true +d-i finish-install/reboot_in_progress note + +#For the update +d-i pkgsel/update-policy select none + +# debconf-get-selections --install +#Use mirror +#d-i apt-setup/use_mirror boolean true +#d-i mirror/country string manual +#choose-mirror-bin mirror/protocol string http +#choose-mirror-bin mirror/http/hostname string 192.168.4.150 +#choose-mirror-bin mirror/http/directory string /ubuntu +#choose-mirror-bin mirror/suite select maverick +#d-i debian-installer/allow_unauthenticated string true + +choose-mirror-bin mirror/http/proxy string diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index ef81697e464..a60e4807ca2 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -8952,6 +8952,210 @@ div.panel.ui-dialog div.list-view div.fixed-header { background: #DFE1E3; } +/*Tagger*/ +.tagger { + width: 94%; + margin: auto; + padding-bottom: 12px; + background: #F2F0F0; + border: 1px solid #CFC9C9; + /*+placement:shift -4px 0px;*/ + position: relative; + left: -4px; + top: 0px; +} + +.tagger .field { + width: 35%; + float: left; + position: relative; +} + +.tagger .tag-info { + font-size: 11px; + color: #757575; + margin-top: 12px; + margin-left: 8px; +} + +.tagger .tag-info.title { + font-size: 11px; + color: #6F9BF0; + margin-bottom: 5px; +} + +.tagger form { + margin: 12px 9px 0px; +} + +.tagger.readonly form { + display: none; +} + +.tagger form label { + display: block; + float: left; + width: 25px; + text-align: right; + font-size: 10px; + color: #394552; + margin-right: 9px; + /*+placement:shift 5px 8px;*/ + position: relative; + left: 5px; + top: 8px; +} + +.tagger form label.error { + position: absolute; + color: #FF0000; + left: 42px; + top: 29px; + /*[empty]background-color:;*/ +} + +.tagger form input { + padding: 4px; + background: #FFFFFF; + border: 1px solid #808080; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; +} + +.tagger form input { + width: 45%; + margin-left: 9px; +} + +.tagger form input[type=submit] { + background: url(../images/bg-gradients.png) repeat-x 0px -220px; + cursor: pointer; + color: #FFFFFF; + /*+text-shadow:0px -1px 2px #000000;*/ + -moz-text-shadow: 0px -1px 2px #000000; + -webkit-text-shadow: 0px -1px 2px #000000; + -o-text-shadow: 0px -1px 2px #000000; + text-shadow: 0px -1px 2px #000000; + border: none; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + padding: 7px 25px 7px 26px; + margin-left: 16px; + width: auto; +} + +.tagger form input[type=submit]:hover { + background-position: 0px -946px; +} + +.tagger ul { + display: block; + width: 96%; + margin: 16px auto auto; + /*+border-radius:2px;*/ + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + -khtml-border-radius: 2px; + border-radius: 2px; + overflow: auto; + padding-bottom: 10px; + border: 1px solid #D2D2D2; + background: #FFFFFF; + /*+box-shadow:inset 0px 0px 10px #DCDCDC;*/ + -moz-box-shadow: inset 0px 0px 10px #DCDCDC; + -webkit-box-shadow: inset 0px 0px 10px #DCDCDC; + -o-box-shadow: inset 0px 0px 10px #DCDCDC; + box-shadow: inset 0px 0px 10px #DCDCDC; +} + +.tagger.readonly ul { +} + +.tagger ul li { + background: #DFDFDF 0px 4px; + height: 15px; + padding: 0px 18px 0 7px; + display: inline-block; + float: left; + margin-left: 7px; + margin-right: 2px; + margin-top: 5px; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + /*+placement:shift 0px 2px;*/ + position: relative; + left: 0px; + top: 2px; +} + +.tagger ul li span { + color: #000000; +} + +.tagger ul li span.label { + font-size: 10px; + position: relative; + left: 15px; + top: -2px; +} + +.tagger.readonly ul li span.label { + left: 6px; +} + +.tagger ul li span.remove { + width: 15px !important; + overflow: hidden !important; + height: 11px !important; + background: #DFDFDF url(../images/sprites.png) no-repeat -596px -1183px; + display: block; + top: 0px !important; + left: -3px !important; + text-indent: 4px; + padding: 4px 0px 0px 8px; + font-size: 8px; + font-weight: bold; + cursor: pointer; + position: absolute !important; + color: #5B5B5B; +} + +.tagger.readonly ul li span.remove { + display: none; +} + +.tagger ul li span.remove:hover { + color: #000000; +} + +/** Dialog tagger*/ +.ui-dialog .tagger { +} + +.ui-dialog .tagger .field { + width: 119px !important; +} + +.ui-dialog .tagger input.key, +.ui-dialog .tagger input.value { + width: 66px !important; + height: 15px; + font-size: 11px !important; +} + +.ui-dialog .tagger input[type=submit] { + padding: 6px 15px; +} + /*VPC / vApps*/ .vpc-chart { width: 100%; @@ -9763,3 +9967,7 @@ div.panel.ui-dialog div.list-view div.fixed-header { background-position: -230px -615px; } +.label-hovered { + cursor: pointer; + color: blue !important; +} \ No newline at end of file diff --git a/ui/images/sprites.png b/ui/images/sprites.png index 71674d13b77..f1f5b8c5820 100644 Binary files a/ui/images/sprites.png and b/ui/images/sprites.png differ diff --git a/ui/index.jsp b/ui/index.jsp index af05f4a652d..1ee8f0bc1b9 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -273,7 +273,7 @@
- +
@@ -347,7 +347,7 @@
- +
@@ -396,7 +396,20 @@
- + +
+
+ +
+ + + +
+
+ +
+
+
@@ -1614,7 +1627,8 @@ - + + diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 15c8efc563d..bca405b2d5b 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -1150,6 +1150,8 @@ id: { label: 'label.id' } } ], + + tags: cloudStack.api.tags({ resourceType: 'UserVm', contextId: 'instances' }), dataProvider: function(args) { $.ajax({ diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 6699d163d97..0a8f970f8f7 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -177,7 +177,7 @@ } }); - var sectionsToShow = ['networks', 'vpc']; + var sectionsToShow = ['networks']; if(havingSecurityGroupNetwork == true) sectionsToShow.push('securityGroups'); @@ -757,6 +757,10 @@ account: { label: 'label.account' } } ], + + tags: cloudStack.api.tags({ resourceType: 'Network', contextId: 'networks' }), + + dataProvider: function(args) { $.ajax({ url: createURL("listNetworks&id=" + args.context.networks[0].id + "&listAll=true"), //pass "&listAll=true" to "listNetworks&id=xxxxxxxx" for now before API gets fixed. @@ -1472,6 +1476,8 @@ vlanname: { label: 'label.vlan' } } ], + + tags: cloudStack.api.tags({ resourceType: 'PublicIpAddress', contextId: 'ipAddresses' }), dataProvider: function(args) { var items = args.context.ipAddresses; @@ -1689,6 +1695,9 @@ addButton: true } }, + + tags: cloudStack.api.tags({ resourceType: 'FirewallRule', contextId: 'multiRule' }), + add: { label: 'label.add', action: function(args) { @@ -1716,6 +1725,19 @@ } }, actions: { + edit: { + label: 'label.edit', + + // Blank -- edit is just for tags right now + action: function(args) { + args.response.success({ + notification: { + label: 'Edit firewall rule', + poll: function(args) { args.complete(); } + } + }); + } + }, destroy: { label: 'label.action.delete.firewall', action: function(args) { @@ -2014,6 +2036,9 @@ addButton: true } }, + + tags: cloudStack.api.tags({ resourceType: 'LoadBalancer', contextId: 'multiRule' }), + add: { label: 'label.add.vms', action: function(args) { @@ -2411,6 +2436,9 @@ addButton: true } }, + + tags: cloudStack.api.tags({ resourceType: 'PortForwardingRule', contextId: 'multiRule' }), + add: { label: 'label.add.vm', action: function(args) { @@ -2444,6 +2472,19 @@ } }, actions: { + edit: { + label: 'label.edit', + + // Blank -- edit is just for tags right now + action: function(args) { + args.response.success({ + notification: { + label: 'label.edit.pf', + poll: function(args) { args.complete(); } + } + }); + } + }, destroy: { label: 'label.remove.pf', action: function(args) { @@ -2763,6 +2804,9 @@ } ], + tags: cloudStack.api.tags({ resourceType: 'SecurityGroup', contextId: 'securityGroups' }), + + dataProvider: function(args) { $.ajax({ url: createURL("listSecurityGroups&id="+args.id), @@ -3179,91 +3223,6 @@ } } } - }, - vpc: { - type: 'select', - title: 'VPC', - id: 'vpc', - listView: { - id: 'vpc', - label: 'VPC', - fields: { - name: { label: 'Name' }, - zone: { label: 'Zone' }, - cidr: { label: 'CIDR' } - }, - dataProvider: function(args) { - args.response.success({ - data: [ - { - name: 'VPC 1', - zone: 'San Jose', - cidr: '0.0.0.0/0', - networkdomain: 'testdomain', - accountdomain: 'testdomain' - }, - { - name: 'VPC 2', - zone: 'San Jose', - cidr: '0.0.0.0/0', - networkdomain: 'testdomain', - accountdomain: 'testdomain' - }, - { - name: 'VPC 3', - zone: 'Cupertino', - cidr: '0.0.0.0/0', - networkdomain: 'testdomain', - accountdomain: 'testdomain' - }, - { - name: 'VPC 4', - zone: 'San Jose', - cidr: '0.0.0.0/0', - networkdomain: 'testdomain', - accountdomain: 'testdomain' - } - ] - }); - }, - actions: { - add: { - label: 'Add VPC', - createForm: { - title: 'Add new VPC', - fields: { - name: { label: 'Name', validation: { required: true } }, - zone: { - label: 'Zone', - validation: { required: true }, - select: function(args) { - args.response.success({ - data: [ - { id: 'zone1', description: 'Zone 1' }, - { id: 'zone2', description: 'Zone 2' }, - { id: 'zone3', description: 'Zone 3' } - ] - }); - } - } - } - }, - messages: { - notification: function(args) { return 'Add new VPC'; } - }, - action: function(args) { - args.response.success(); - }, - notification: { poll: function(args) { args.complete(); } } - }, - editVpc: { - label: 'Edit VPC', - action: { - custom: cloudStack.uiCustom.vpc(cloudStack.vpc) - } - } - } - } } } }; diff --git a/ui/scripts/projects.js b/ui/scripts/projects.js index 6a99939d45b..2ece194e014 100644 --- a/ui/scripts/projects.js +++ b/ui/scripts/projects.js @@ -756,6 +756,7 @@ } } }, + tabFilter: function(args) { var project = args.context.projects[0]; var projectOwner = project.account; @@ -791,6 +792,9 @@ state: { label: 'label.state' } } ], + + tags: cloudStack.api.tags({ resourceType: 'Project', contextId: 'projects' }), + dataProvider: function(args) { var projectID = args.context.projects[0].id; diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js index cf437afed52..12d3498350c 100644 --- a/ui/scripts/sharedFunctions.js +++ b/ui/scripts/sharedFunctions.js @@ -617,5 +617,87 @@ cloudStack.api = { } } } + }, + + tags: function(args) { + var resourceType = args.resourceType; + var contextId = args.contextId; + + return { + actions: { + add: function(args) { + var data = args.data; + var resourceId = args.context[contextId][0].id; + + $.ajax({ + url: createURL( + 'createTags&tags[0].key=' + data.key + '&tags[0].value=' + data.value + ), + data: { + resourceIds: resourceId, + resourceType: resourceType + }, + success: function(json) { + args.response.success({ + _custom: { jobId: json.createtagsresponse.jobid }, + notification: { + desc: 'Add tag for ' + resourceType, + poll: pollAsyncJobResult + } + }); + } + }); + }, + + remove: function(args) { + var data = args.context.tagItems[0]; + var resourceId = args.context[contextId][0].id; + + $.ajax({ + url: createURL( + 'deleteTags&tags[0].key=' + data.key + '&tags[0].value=' + data.value + ), + data: { + resourceIds: resourceId, + resourceType: resourceType + }, + success: function(json) { + args.response.success({ + _custom: { jobId: json.deletetagsresponse.jobid }, + notification: { + desc: 'Remove tag for ' + resourceType, + poll: pollAsyncJobResult + } + }); + } + }); + } + }, + dataProvider: function(args) { + var resourceId = args.context[contextId][0].id; + var data = { + resourceId: resourceId, + resourceType: resourceType + }; + + if (args.context.projects) { + data.projectid=args.context.projects[0].id; + } + + $.ajax({ + url: createURL('listTags'), + data: data, + success: function(json) { + args.response.success({ + data: json.listtagsresponse ? + json.listtagsresponse.tag : [] + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }; } }; diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js index c0ac3b2f2d2..01901d3a583 100644 --- a/ui/scripts/storage.js +++ b/ui/scripts/storage.js @@ -1004,6 +1004,9 @@ } ], + tags: cloudStack.api.tags({ resourceType: 'Volume', contextId: 'volumes' }), + + dataProvider: function(args) { $.ajax({ url: createURL("listVolumes&id=" + args.context.volumes[0].id), @@ -1269,6 +1272,8 @@ } ], + tags: cloudStack.api.tags({ resourceType: 'Snapshot', contextId: 'snapshots' }), + dataProvider: function(args) { $.ajax({ url: createURL("listSnapshots&id=" + args.context.snapshots[0].id), diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 6d3b765871a..712c122f68a 100644 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -3494,14 +3494,14 @@ fields: [ { - name: { label: 'label.zone', isEditable: true } + name: { label: 'label.zone', isEditable: true, validation: { required: true } } }, { id: { label: 'label.id' }, allocationstate: { label: 'label.allocation.state' }, - dns1: { label: 'label.dns.1', isEditable: true }, + dns1: { label: 'label.dns.1', isEditable: true, validation: { required: true } }, dns2: { label: 'label.dns.2', isEditable: true }, - internaldns1: { label: 'label.internal.dns.1', isEditable: true }, + internaldns1: { label: 'label.internal.dns.1', isEditable: true, validation: { required: true } }, internaldns2: { label: 'label.internal.dns.2', isEditable: true }, domainname: { label: 'label.domain' }, networktype: { label: 'label.network.type' }, @@ -5922,14 +5922,14 @@ title: 'label.details', fields: [ { - name: { label: 'label.name', isEditable: true } + name: { label: 'label.name', isEditable: true, validation: { required: true } } }, { id: { label: 'label.id' }, - netmask: { label: 'label.netmask', isEditable: true }, - startip: { label: 'label.start.IP', isEditable: true }, + netmask: { label: 'label.netmask', isEditable: true, validation: { required: true } }, + startip: { label: 'label.start.IP', isEditable: true, validation: { required: true } }, endip: { label: 'label.end.IP', isEditable: true }, - gateway: { label: 'label.gateway', isEditable: true }, + gateway: { label: 'label.gateway', isEditable: true, validation: { required: true } }, allocationstate: { converter: function(str) { // For localization diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index 811a27a7c66..d926d05b821 100644 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -204,11 +204,42 @@ } }, - osTypeId: { - label: 'label.os.type', + osCategory: { + label: 'OS Category', select: function(args) { $.ajax({ - url: createURL("listOsTypes"), + url: createURL("listOsCategories"), + dataType: "json", + async: true, + success: function(json) { + var osCats = json.listoscategoriesresponse.oscategory; + var items = []; + if (isAdmin()) + items.push({id: -1, description: "All OS"}); + $(osCats).each(function() { + items.push({id: this.id, description: this.name}); + }); + args.response.success({data: items}); + } + }); + } + }, + + osTypeId: { + label: 'label.os.type', + dependsOn: 'osCategory', + select: function(args) { + if(args.osCategory == null) + return; + + var apiCmd; + if(args.osCategory == -1) + apiCmd = "listOsTypes"; + else + apiCmd = "listOsTypes&oscategoryid=" + args.osCategory; + + $.ajax({ + url: createURL(apiCmd), dataType: "json", async: true, success: function(json) { @@ -678,9 +709,12 @@ account: { label: 'label.account' }, created: { label: 'label.created', converter: cloudStack.converters.toLocalDate } } - ], + ], + + tags: cloudStack.api.tags({ resourceType: 'Template', contextId: 'templates' }), + - dataProvider: function(args) { + dataProvider: function(args) { var jsonObj = args.context.templates[0]; var apiCmd = "listTemplates&templatefilter=self&id=" + jsonObj.id; if(jsonObj.zoneid != null) @@ -780,15 +814,46 @@ isBoolean: true, isChecked: true }, - + + osCategory: { + label: 'OS Category', + dependsOn: 'isBootable', + select: function(args) { + $.ajax({ + url: createURL("listOsCategories"), + dataType: "json", + async: true, + success: function(json) { + var osCats = json.listoscategoriesresponse.oscategory; + var items = []; + if (isAdmin()) + items.push({id: -1, description: "All OS"}); + $(osCats).each(function() { + items.push({id: this.id, description: this.name}); + }); + args.response.success({data: items}); + } + }); + } + }, + osTypeId: { label: 'label.os.type', - dependsOn: 'isBootable', + dependsOn: ['isBootable','osCategory'], isHidden: false, validation: { required: true }, select: function(args) { + if(args.osCategory == null) + return; + + var apiCmd; + if(args.osCategory == -1) + apiCmd = "listOsTypes"; + else + apiCmd = "listOsTypes&oscategoryid=" + args.osCategory; + $.ajax({ - url: createURL("listOsTypes"), + url: createURL(apiCmd), dataType: "json", async: true, success: function(json) { @@ -822,6 +887,7 @@ } } }, + action: function(args) { var array1 = []; @@ -1192,8 +1258,10 @@ created: { label: 'label.created', converter: cloudStack.converters.toLocalDate } } ], + + tags: cloudStack.api.tags({ resourceType: 'ISO', contextId: 'isos' }), - dataProvider: function(args) { + dataProvider: function(args) { var jsonObj = args.context.isos[0]; var apiCmd = "listIsos&isofilter=self&id="+jsonObj.id; if(jsonObj.zoneid != null) diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js index 13719d45b45..b94e5877b41 100644 --- a/ui/scripts/ui-custom/instanceWizard.js +++ b/ui/scripts/ui-custom/instanceWizard.js @@ -134,7 +134,8 @@ $('') .attr({ type: options.secondary.type, - name: options.secondary.name + name: options.secondary.name, + 'wizard-field': options.secondary['wizard-field'] }) .val(id) .click(function() { @@ -513,7 +514,8 @@ secondary: { desc: 'Default', name: 'defaultNetwork', - type: 'radio' + type: 'radio', + 'wizard-field': 'default-network' } }) ); @@ -525,7 +527,8 @@ desc: 'description', id: 'id' }, { - type: 'checkbox' + type: 'checkbox', + 'wizard-field': 'security-groups' }) ); @@ -536,37 +539,55 @@ }, 'review': function($step, formData) { - return { - response: { - success: function(args) { - $step.find('[wizard-field]').each(function() { - var field = $(this).attr('wizard-field'); - var fieldName; - var $input = $wizard.find('[wizard-field=' + field + ']').filter(function() { - return $(this).is(':selected') || $(this).is(':checked'); - }); + $step.find('[wizard-field]').each(function() { + var field = $(this).attr('wizard-field'); + var fieldName; + var $input = $wizard.find('[wizard-field=' + field + ']').filter(function() { + return $(this).is(':selected') || $(this).is(':checked'); + }); - if ($input.is('option')) { - fieldName = $input.html(); - } else if ($input.is('input[type=radio]')) { - fieldName = $input.parent().find('.select-desc .name').html(); - } + if ($input.is('option')) { + fieldName = $input.html(); + } else if ($input.is('input[type=radio]')) { + // Choosen New network as default + if ($input.parents('div.new-network').size()) { + fieldName = $input.closest('div.new-network').find('input[name="new-network-name"]').val(); + // Choosen Network from existed + } else if ($input.parents('div.my-networks').size()) { + fieldName = $input.closest('div.select').find('.select-desc .name').html(); + } else { + fieldName = $input.parent().find('.select-desc .name').html(); + } + } else if ($input.eq(0).is('input[type=checkbox]')) { + fieldName = ''; + $input.each(function(index) { + if (index != 0) fieldName += '
'; + fieldName += $(this).next('div.select-desc').find('.name').html(); + }); + } - if (fieldName) { - $(this).html(fieldName); - } else { - $(this).html('(' + _l('label.none') + ')'); - } - }); + if (fieldName) { + $(this).html(fieldName); + } else { + $(this).html('(' + _l('label.none') + ')'); + } + + var conditionalFieldFrom = $(this).attr('conditional-field'); + if (conditionalFieldFrom) { + if ($wizard.find('.'+conditionalFieldFrom).css('display') == 'block') { + $(this).closest('div.select').show(); + } else { + $(this).closest('div.select').hide(); } } - }; + }); } }; // Go to specified step in wizard, // updating nav items and diagram - var showStep = function(index) { + var showStep = function(index, options) { + if (!options) options = {}; var targetIndex = index - 1; if (index <= 1) targetIndex = 0; @@ -651,17 +672,17 @@ return false; } } - - //step 6 - review (spcifiy displyname, group as well) - if ($activeStep.hasClass('review')) { - if($activeStep.find('input[name=displayname]').size() > 0 && $activeStep.find('input[name=displayname]').val().length > 0) { - //validate - var b = cloudStack.validate.vmHostName($activeStep.find('input[name=displayname]').val()); - if(b == false) - return false; - } - } - + + //step 6 - review (spcifiy displyname, group as well) + if ($activeStep.hasClass('review')) { + if($activeStep.find('input[name=displayname]').size() > 0 && $activeStep.find('input[name=displayname]').val().length > 0) { + //validate + var b = cloudStack.validate.vmHostName($activeStep.find('input[name=displayname]').val()); + if(b == false) + return false; + } + } + if (!$form.valid()) { if ($form.find('input.error:visible, select.error:visible').size()) { return false; diff --git a/ui/scripts/ui-custom/projects.js b/ui/scripts/ui-custom/projects.js index e10a8f16f3a..221d834d29f 100644 --- a/ui/scripts/ui-custom/projects.js +++ b/ui/scripts/ui-custom/projects.js @@ -171,7 +171,8 @@ var $input = $('').attr({ type: 'text', name: resource.type, - value: resource.value + value: resource.value, + id: resource.type }).addClass('required'); $field.append($label, $input); @@ -305,13 +306,15 @@ .append($('