/*******************************************************************************
*Copyright (c) 2009 Eucalyptus Systems, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, only version 3 of the License.
*
*
* This file is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Please contact Eucalyptus Systems, Inc., 130 Castilian
* Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
* if you need additional information or have any questions.
*
* This file may incorporate work covered under the following copyright and
* permission notice:
*
* Software License Agreement (BSD License)
*
* Copyright (c) 2008, Regents of the University of California
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with
* or without modification, are permitted provided that the following
* conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
* THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
* LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
* SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
* IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
* BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
* THE REGENTS’ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
* OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
* WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
* ANY SUCH LICENSES OR RIGHTS.
*******************************************************************************/
/*
*
* Author: Dmitrii Zagorodnov dmitrii@cs.ucsb.edu
*/
package edu.ucsb.eucalyptus.admin.server;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.ProxyHost;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.log4j.Logger;
import com.eucalyptus.auth.Groups;
import com.eucalyptus.auth.NoSuchGroupException;
import com.eucalyptus.auth.NoSuchUserException;
import com.eucalyptus.auth.UserExistsException;
import com.eucalyptus.auth.UserInfo;
import com.eucalyptus.auth.UserInfoStore;
import com.eucalyptus.auth.Users;
import com.eucalyptus.auth.crypto.Crypto;
import com.eucalyptus.auth.principal.Authorization;
import com.eucalyptus.auth.principal.AvailabilityZonePermission;
import com.eucalyptus.auth.principal.Group;
import com.eucalyptus.auth.principal.User;
import com.eucalyptus.auth.WrappedUser;
import com.eucalyptus.bootstrap.HttpServerBootstrapper;
import com.eucalyptus.entities.EntityWrapper;
import com.eucalyptus.entities.NetworkRulesGroup;
import com.eucalyptus.event.EventVetoedException;
import com.eucalyptus.event.ListenerRegistry;
import com.eucalyptus.event.SystemConfigurationEvent;
import com.eucalyptus.images.Image;
import com.eucalyptus.images.ImageInfo;
import com.eucalyptus.images.Images;
import com.eucalyptus.network.NetworkGroupUtil;
import com.eucalyptus.util.Composites;
import com.eucalyptus.util.DNSProperties;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.Tx;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gwt.user.client.rpc.SerializableException;
import edu.ucsb.eucalyptus.admin.client.CloudInfoWeb;
import edu.ucsb.eucalyptus.admin.client.ImageInfoWeb;
import edu.ucsb.eucalyptus.admin.client.SystemConfigWeb;
import edu.ucsb.eucalyptus.admin.client.UserInfoWeb;
import edu.ucsb.eucalyptus.cloud.entities.SystemConfiguration;
public class EucalyptusManagement {
private static Logger LOG = Logger.getLogger( EucalyptusManagement.class );
//grze: see Groups.{ALL,DEFAULT}
// private static final String GROUP_ALL = "all";
// private static final String GROUP_DEFAULT = "default";
public static String getError( String message )
{
return "<html><title>HTTP/1.0 403 Forbidden</title><body><div align=\"center\"><p><h1>403: Forbidden</h1></p><p><img src=\"themes/active/logo.png\" /></p><p><h3 style=\"font-color: red;\">" + message + "</h3></p></div></body></html>";
}
/* TODO: for now 'pattern' is ignored and all users are returned */
public static List <UserInfoWeb> getWebUsers (String pattern) throws SerializableException
{
final List<UserInfoWeb> webUsersList = Lists.newArrayList();
for( User u : Users.listAllUsers( ) ) {
try {
UserInfo userInfo = (( WrappedUser ) u).getUserInfo( );
webUsersList.add( Composites.composeNew( UserInfoWeb.class, userInfo, u ) );
} catch ( Exception e ) {
LOG.debug( e, e );
}
}
return webUsersList;
}
/* TODO: for now 'pattern' is ignored and all images are returned */
public static List <ImageInfoWeb> getWebImages (String pattern) throws SerializableException {
List<ImageInfoWeb> ret = Lists.newArrayList( );
for( Image i : Images.listAllImages( ) ) {
ret.add( Composites.update( i, new ImageInfoWeb( ) ) );
}
return ret;
}
public static UserInfoWeb getWebUser( String userName ) throws SerializableException {
return EucalyptusManagement.getWebUserByExample( new UserInfo( userName ) );
}
public static UserInfoWeb getWebUserByEmail( String emailAddress ) throws SerializableException {
UserInfo s = new UserInfo( );
s.setEmail( emailAddress );
return EucalyptusManagement.getWebUserByExample( s );
}
public static UserInfoWeb getWebUserByCode( String confCode ) throws SerializableException {
UserInfo s = new UserInfo( );
s.setConfirmationCode( confCode );
return EucalyptusManagement.getWebUserByExample( s );
}
private static UserInfoWeb getWebUserByExample( UserInfo ex ) throws SerializableException {
try {
UserInfo userInfo = UserInfoStore.getUserInfo( ex );
User user = Users.lookupUser( userInfo.getUserName( ) );
UserInfoWeb webUser = Composites.composeNew( UserInfoWeb.class, userInfo, user );
return webUser;
} catch ( NoSuchUserException e ) {
throw EucalyptusManagement.makeFault( "User does not exist" );
}
}
public static synchronized void addWebUser( UserInfoWeb webUser ) throws SerializableException
{
User user = null;
try {
user = Users.lookupUser( webUser.getUserName( ) );
throw EucalyptusManagement.makeFault("User already exists" );
} catch ( NoSuchUserException e ) {
try {
user = Users.addUser( webUser.getUserName( ), webUser.isAdministrator( ), webUser.isEnabled( ) );
try {
UserInfo userInfo = Composites.updateNew( webUser, UserInfo.class );
try {
NetworkGroupUtil.createUserNetworkRulesGroup( userInfo.getUserName( ), NetworkRulesGroup.NETWORK_DEFAULT_NAME, "default group" );
} catch ( EucalyptusCloudException e1 ) {
LOG.debug( e1, e1 );
}
UserInfoStore.addUserInfo( userInfo );
} catch ( Exception e1 ) {
LOG.error( e1, e1 );
throw EucalyptusManagement.makeFault("Error adding user: " + e1.getMessage( ) );
}
} catch ( UserExistsException e1 ) {
LOG.error( e1, e1 );
throw EucalyptusManagement.makeFault("User already exists" );
} catch ( UnsupportedOperationException e1 ) {
LOG.error( e1, e1 );
throw EucalyptusManagement.makeFault("Error adding user: " + e1.getMessage( ) );
}
}
}
private static SerializableException makeFault(String message)
{
SerializableException e = new SerializableException( message );
LOG.error(e);
return e;
}
public static void deleteWebUser( UserInfoWeb webUser ) throws SerializableException
{
String userName = webUser.getUserName();
deleteUser( userName );
}
public static void deleteUser( String userName ) throws SerializableException
{
try {
Users.deleteUser( userName );
UserInfoStore.deleteUserInfo( userName );
} catch ( NoSuchUserException e1 ) {
LOG.debug( e1, e1 );
throw EucalyptusManagement.makeFault( "Unable to delete user" );
} catch ( UnsupportedOperationException e1 ) {
LOG.debug( e1, e1 );
throw EucalyptusManagement.makeFault("Error while deleting user: " + e1.getMessage( ) );
}
}
public static void commitWebUser( final UserInfoWeb webUser ) throws SerializableException
{
String userName = webUser.getUserName( );
try {
Users.updateUser( userName, new Tx<User>( ) {
public void fire( User user ) throws Throwable {
Composites.project( webUser, user );
}
});
UserInfoStore.updateUserInfo( userName, new Tx<UserInfo>( ) {
public void fire( UserInfo info ) throws Throwable {
Composites.project( webUser, info );
}
});
} catch ( NoSuchUserException e1 ) {
LOG.error( e1, e1 );
throw EucalyptusManagement.makeFault( "Unable to update user" );
} catch ( UnsupportedOperationException e1 ) {
LOG.error( e1, e1 );
throw EucalyptusManagement.makeFault("Error while updating user: " + e1.getMessage( ) );
}
}
public static String getAdminEmail() throws SerializableException
{
String addr = null;
try {
UserInfo adminUser = UserInfoStore.getUserInfo( new UserInfo("admin") );
addr = adminUser.getEmail( );
} catch ( NoSuchUserException e ) {
throw EucalyptusManagement.makeFault("Administrator account not found" );
}
if (addr==null || addr.equals("")) {
throw EucalyptusManagement.makeFault( "Email address is not set" );
}
return addr;
}
public static void deleteImage(String imageId)
throws SerializableException
{
ImageInfo searchImg = new ImageInfo( );
searchImg.setImageId( imageId );
EntityWrapper<ImageInfo> db = new EntityWrapper<ImageInfo>();
List<ImageInfo> imgList= db.query( searchImg );
if ( imgList.size() > 0 && !imgList.isEmpty() )
{
Image foundimgSearch = imgList.get( 0 );
foundimgSearch.setImageState( "deregistered" );
db.commit();
}
else
{
db.rollback();
throw EucalyptusManagement.makeFault ("Specified image was not found, sorry.");
}
}
public static void disableImage(String imageId)
throws SerializableException
{
try {
new Images._byId( imageId ) {{ new _mutator() {
@Override public void set( ImageInfo e ) {
e.setImageState( "deregistered" );
}}.set( );
}};
} catch ( EucalyptusCloudException e ) {
throw EucalyptusManagement.makeFault ("Specified image was not found, sorry.");
}
}
public static void enableImage(String imageId)
throws SerializableException
{
try {
new Images._byId( imageId ) {{ new _mutator() {
@Override public void set( ImageInfo e ) {
e.setImageState( "available" );
}}.set( );
}};
} catch ( EucalyptusCloudException e ) {
throw EucalyptusManagement.makeFault ("Specified image was not found, sorry.");
}
}
public static SystemConfigWeb getSystemConfig() throws SerializableException
{
SystemConfiguration sysConf = SystemConfiguration.getSystemConfiguration();
LOG.debug( "Sending cloud host: " + sysConf.getCloudHost( ) );
return new SystemConfigWeb(
sysConf.getDefaultKernel(),
sysConf.getDefaultRamdisk(),
sysConf.getMaxUserPublicAddresses(),
sysConf.isDoDynamicPublicAddresses(),
sysConf.getSystemReservedPublicAddresses(),
sysConf.getDnsDomain(),
sysConf.getNameserver(),
sysConf.getNameserverAddress(),
sysConf.getCloudHost( ));
}
public static void setSystemConfig( final SystemConfigWeb systemConfig )
{
EntityWrapper<SystemConfiguration> db = new EntityWrapper<SystemConfiguration>();
SystemConfiguration sysConf = null;
try
{
sysConf = db.getUnique( new SystemConfiguration() );
sysConf.setCloudHost( systemConfig.getCloudHost() );
sysConf.setDefaultKernel( systemConfig.getDefaultKernelId() );
sysConf.setDefaultRamdisk( systemConfig.getDefaultRamdiskId() );
sysConf.setDnsDomain(systemConfig.getDnsDomain());
sysConf.setNameserver(systemConfig.getNameserver());
sysConf.setNameserverAddress(systemConfig.getNameserverAddress());
sysConf.setMaxUserPublicAddresses( systemConfig.getMaxUserPublicAddresses() );
sysConf.setDoDynamicPublicAddresses( systemConfig.isDoDynamicPublicAddresses() );
sysConf.setSystemReservedPublicAddresses( systemConfig.getSystemReservedPublicAddresses() );
db.commit();
DNSProperties.update();
}
catch ( EucalyptusCloudException e )
{
sysConf = new SystemConfiguration(
systemConfig.getDefaultKernelId(),
systemConfig.getDefaultRamdiskId(),
systemConfig.getMaxUserPublicAddresses(),
systemConfig.isDoDynamicPublicAddresses(),
systemConfig.getSystemReservedPublicAddresses(),
systemConfig.getDnsDomain(),
systemConfig.getNameserver(),
systemConfig.getNameserverAddress(),
systemConfig.getCloudHost( ));
db.add(sysConf);
db.commit();
DNSProperties.update();
}
try {
ListenerRegistry.getInstance( ).fireEvent( new SystemConfigurationEvent( sysConf ) );
} catch ( EventVetoedException e ) {
LOG.debug( e, e );
}
}
private static String getExternalIpAddress ()
{
String ipAddr = null;
HttpClient httpClient = new HttpClient();
//support for http proxy
if(HttpServerBootstrapper.httpProxyHost != null && (HttpServerBootstrapper.httpProxyHost.length() > 0)) {
String proxyHost = HttpServerBootstrapper.httpProxyHost;
if(HttpServerBootstrapper.httpProxyPort != null && (HttpServerBootstrapper.httpProxyPort.length() > 0)) {
int proxyPort = Integer.parseInt(HttpServerBootstrapper.httpProxyPort);
httpClient.getHostConfiguration().setProxy(proxyHost, proxyPort);
} else {
httpClient.getHostConfiguration().setProxyHost(new ProxyHost(proxyHost));
}
}
// Use Rightscale's "whoami" service
GetMethod method = new GetMethod("https://my.rightscale.com/whoami?api_version=1.0&cloud=0");
Integer timeoutMs = new Integer(3 * 1000); // TODO: is this working?
method.getParams().setSoTimeout(timeoutMs);
try {
httpClient.executeMethod(method);
String str = "";
InputStream in = method.getResponseBodyAsStream();
byte[] readBytes = new byte[1024];
int bytesRead = -1;
while((bytesRead = in.read(readBytes)) > 0) {
str += new String(readBytes, 0, bytesRead);
}
Matcher matcher = Pattern.compile(".*your ip is (.*)").matcher(str);
if (matcher.find()) {
ipAddr = matcher.group(1);
}
} catch (MalformedURLException e) {
LOG.warn ("Malformed URL exception: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
LOG.warn ("I/O exception: " + e.getMessage());
e.printStackTrace();
} finally {
method.releaseConnection();
}
return ipAddr;
}
public static CloudInfoWeb getCloudInfo (boolean setExternalHostPort) throws SerializableException
{
String cloudRegisterId = null;
cloudRegisterId = SystemConfiguration.getSystemConfiguration().getRegistrationId();
CloudInfoWeb cloudInfo = new CloudInfoWeb();
cloudInfo.setInternalHostPort (SystemConfiguration.getInternalIpAddress() + ":8443");
if (setExternalHostPort) {
String ipAddr = getExternalIpAddress();
if (ipAddr!=null) {
cloudInfo.setExternalHostPort ( ipAddr + ":8443");
}
}
cloudInfo.setServicePath ("/register"); // TODO: what is the actual cloud registration service?
cloudInfo.setCloudId ( cloudRegisterId ); // TODO: what is the actual cloud registration ID?
return cloudInfo;
}
private static List<String> getGroupZones(Group group) {
List<String> zones = new ArrayList<String>();
for (Authorization auth : group.getAuthorizations()) {
if (auth instanceof AvailabilityZonePermission) {
zones.add(auth.getValue());
}
}
return zones;
}
}