/*************************************************************************
* Copyright 2009-2012 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; version 3 of the License.
*
* This program 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., 6755 Hollister Ave., Goleta
* CA 93117, 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.
************************************************************************/
package com.eucalyptus.ws;
import java.lang.Object;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;
import javax.persistence.Entity;
import javax.persistence.PersistenceContext;
import javax.persistence.Table;
import org.apache.log4j.Logger;
import com.eucalyptus.bootstrap.BillOfMaterials;
import com.eucalyptus.bootstrap.Databases;
import com.eucalyptus.configurable.ConfigurableClass;
import com.eucalyptus.configurable.ConfigurableField;
import com.eucalyptus.configurable.ConfigurableProperty;
import com.eucalyptus.configurable.ConfigurablePropertyException;
import com.eucalyptus.configurable.PropertyChangeListener;
import com.eucalyptus.entities.AbstractPersistent;
import edu.ucsb.eucalyptus.cloud.entities.SystemConfiguration;
@Entity
@PersistenceContext( name = "eucalyptus_cloud" )
@Table( name = "cloud_image_configuration" )
@ConfigurableClass( root = "bootstrap.webservices",
description = "Parameters controlling the web services endpoint." )
public class StackConfiguration extends AbstractPersistent {
@ConfigurableField( description = "Channel connect timeout (ms).",
changeListener = WebServices.CheckNonNegativeIntegerPropertyChangeListener.class,
initial = "500" )
public static Integer CHANNEL_CONNECT_TIMEOUT = 500;
@ConfigurableField( changeListener = TimeChangeListener.class,
description = "Time interval duration (in seconds) during which duplicate signatures will be accepted to accommodate collisions.",
initial = "0" )
public static Integer REPLAY_SKEW_WINDOW_SEC = 0;
@ConfigurableField( description = "A max clock skew value (in seconds) between client and server accepted when validating timestamps in Query/REST protocol.",
changeListener = TimeChangeListener.class,
initial = "20" )
public static Integer CLOCK_SKEW_SEC = 20;
@ConfigurableField( description = "Server socket reuse address.",
changeListener = WebServices.CheckBooleanPropertyChangeListener.class,
initial = "true" )
public static Boolean SERVER_CHANNEL_REUSE_ADDRESS = true;
@ConfigurableField( description = "Server socket TCP_NODELAY.",
changeListener = WebServices.CheckBooleanPropertyChangeListener.class,
initial = "true" )
public static Boolean SERVER_CHANNEL_NODELAY = true;
@ConfigurableField( description = "Socket reuse address.",
changeListener = WebServices.CheckBooleanPropertyChangeListener.class,
initial = "true" )
public static Boolean CHANNEL_REUSE_ADDRESS = true;
@ConfigurableField( description = "Socket keep alive.",
changeListener = WebServices.CheckBooleanPropertyChangeListener.class,
initial = "true" )
public static Boolean CHANNEL_KEEP_ALIVE = true;
@ConfigurableField( description = "Server socket TCP_NODELAY.",
changeListener = WebServices.CheckBooleanPropertyChangeListener.class,
initial = "true" )
public static Boolean CHANNEL_NODELAY = true;
@ConfigurableField( description = "Server worker thread pool max.",
changeListener = WebServices.CheckNonNegativeIntegerPropertyChangeListener.class,
initial = "32" )
public static Integer SERVER_POOL_MAX_THREADS = 32;
@ConfigurableField( description = "Server max worker memory per connection.",
changeListener = WebServices.CheckNonNegativeLongPropertyChangeListener.class,
initial = "0" )
public static Long SERVER_POOL_MAX_MEM_PER_CONN = 0L;
@ConfigurableField( description = "Server max worker memory total.",
changeListener = WebServices.CheckNonNegativeIntegerPropertyChangeListener.class,
initial = "0" )
public static Long SERVER_POOL_TOTAL_MEM = 0L;
@ConfigurableField( description = "Service socket select timeout (ms).",
changeListener = WebServices.CheckNonNegativeLongPropertyChangeListener.class,
initial = "500" )
public static Long SERVER_POOL_TIMEOUT_MILLIS = 500L;
@ConfigurableField( description = "Server selector thread pool max.",
changeListener = WebServices.CheckNonNegativeIntegerPropertyChangeListener.class,
initial = "128" )
public static Integer SERVER_BOSS_POOL_MAX_THREADS = 128;
@ConfigurableField( description = "Server max selector memory per connection.",
changeListener = WebServices.CheckNonNegativeLongPropertyChangeListener.class,
initial = "0" )
public static Long SERVER_BOSS_POOL_MAX_MEM_PER_CONN = 0L;
@ConfigurableField( description = "Server worker thread pool max.",
changeListener = WebServices.CheckNonNegativeLongPropertyChangeListener.class,
initial = "0" )
public static Long SERVER_BOSS_POOL_TOTAL_MEM = 0L;
@ConfigurableField( description = "Service socket select timeout (ms).",
changeListener = WebServices.CheckNonNegativeLongPropertyChangeListener.class,
initial = "500" )
public static Long SERVER_BOSS_POOL_TIMEOUT_MILLIS = 500L;
@ConfigurableField( description = "Port to bind (note: port 8773 is always bound regardless).",
changeListener = WebServices.CheckNonNegativeIntegerPropertyChangeListener.class,
initial = "8773" )
public static Integer PORT = 8773;
public static final Integer INTERNAL_PORT = 8773;
@ConfigurableField( description = "CIDRs matching addresses to bind on (note: default interface is always bound regardless).",
initial = "0.0.0.0",
changeListener = WebServices.CheckCidrListPropertyChangeListener.class )
public static volatile String LISTENER_ADDRESS_MATCH = "0.0.0.0";
@ConfigurableField( description = "Record and report service times.", initial = "false" )
public static Boolean STATISTICS = Boolean.FALSE;
@ConfigurableField( description = "Execute service specific pipeline handlers from a separate thread pool (with respect to I/O).",
initial = "false" )
public static Boolean ASYNC_PIPELINE = Boolean.FALSE;
@ConfigurableField( description = "Execute service operations from a separate thread pool (with respect to I/O).",
initial = "false" )
public static Boolean ASYNC_OPERATIONS = Boolean.FALSE;
@ConfigurableField( description = "Execute internal service operations from a separate thread pool (with respect to I/O).",
initial = "false" )
public static Boolean ASYNC_INTERNAL_OPERATIONS = Boolean.FALSE;
@ConfigurableField( description = "Execute internal service operations out of band from the normal service bus.",
initial = "true" )
public static Boolean OOB_INTERNAL_OPERATIONS = Boolean.TRUE;
@ConfigurableField( description = "Client idle timeout (secs).", initial = "60" )
public static Integer CLIENT_INTERNAL_TIMEOUT_SECS = 60;
@ConfigurableField( description = "Client connection timeout (ms).", initial = "3000" )
public static Integer CLIENT_INTERNAL_CONNECT_TIMEOUT_MILLIS = 3000;
@ConfigurableField( description = "Client HMAC signature version 4 enabled", initial = "true" )
public static Boolean CLIENT_INTERNAL_HMAC_SIGNATURE_ENABLED = true;
@ConfigurableField( description = "Cluster connect timeout (ms).", initial = "3000" )
public static Integer CLUSTER_CONNECT_TIMEOUT_MILLIS = 3000;
@ConfigurableField( description = "Server socket idle time-out.", initial = "60" )
public static Integer PIPELINE_IDLE_TIMEOUT_SECONDS = 60;
@ConfigurableField( description = "Server http chunk max.", initial = "1048576000" )
public static Integer CLIENT_HTTP_CHUNK_BUFFER_MAX = 1048576000;
@ConfigurableField( description = "Client http pool acquire timeout.", initial = "60000" )
public static Long CLIENT_HTTP_POOL_ACQUIRE_TIMEOUT = 60_000L;
@ConfigurableField( description = "Client worker thread pool max.", initial = "32" )
public static Integer CLIENT_POOL_MAX_THREADS = 32;
@ConfigurableField( description = "Client message patterns to match for logging" )
public static String CLIENT_MESSAGE_LOG_WHITELIST = "";
@ConfigurableField( description = "Maximum HTTP chunk size (bytes).",
initial = "102400")
public static Integer HTTP_MAX_CHUNK_BYTES = 10 * 10 * 1024;
@ConfigurableField( description = "Maximum Query Pipeline http chunk size (bytes).",
initial = "307200")
public static Integer PIPELINE_MAX_QUERY_REQUEST_SIZE = 30 * 10 * 1024;
@ConfigurableField( description = "Maximum HTTP initial line size (bytes).", initial = "4096" )
public static Integer HTTP_MAX_INITIAL_LINE_BYTES = 4 * 1024;
@ConfigurableField( description = "Maximum HTTP headers size (bytes).", initial = "8192" )
public static Integer HTTP_MAX_HEADER_BYTES = 8 * 1024;
@ConfigurableField( description = "Maximum HTTP requests per persistent connection.", initial = "100" )
public static Integer HTTP_MAX_REQUESTS_PER_CONNECTION = 100;
@ConfigurableField( description = "HTTP server header for responses (use 'default' for standard)", initial = "default" )
public static String HTTP_SERVER_HEADER = "default";
@ConfigurableField( description = "Use DNS delegation for eucarc.", initial = "false" )
@Deprecated //GRZE: this field will be superceded by new DNS and eucarc support in 3.4: DO NOT USE IT!
public static Boolean USE_DNS_DELEGATION = Boolean.FALSE;
@ConfigurableField( description = "Use DNS names for instances.", initial = "false" )
@Deprecated //GRZE: this field will be superceded by new DNS support in 3.4: DO NOT USE IT!
public static Boolean USE_INSTANCE_DNS = Boolean.FALSE;
@ConfigurableField( description = "Default scheme prefix in eucarc.",
changeListener = TemporarySchemeUpdater.class,
initial = "false" )
@Deprecated //GRZE: this field will be superceded by new eucarc support in 3.4: DO NOT USE IT!
public static Boolean DEFAULT_HTTPS_ENABLED = Boolean.FALSE;
@ConfigurableField( description = "Default scheme for EC2_URL in eucarc.",
changeListener = UriChangeListener.class,
initial = "http" )
@Deprecated //GRZE: this field will be superceded by new eucarc support in 3.4: DO NOT USE IT!
public static String DEFAULT_EC2_URI_SCHEME = "http"; //GRZE: there references to specific services are not in the right scope here.
@ConfigurableField( description = "Default scheme for S3_URL in eucarc.",
changeListener = UriChangeListener.class,
initial = "http" )
@Deprecated //GRZE: this field will be superceded by new eucarc support in 3.4: DO NOT USE IT!
public static String DEFAULT_S3_URI_SCHEME = "http"; //GRZE: there references to specific services are not in the right scope here.
@ConfigurableField( description = "Default scheme for AWS_SNS_URL in eucarc.",
changeListener = UriChangeListener.class,
initial = "http" )
@Deprecated //GRZE: this field will be superceded by new eucarc support in 3.4: DO NOT USE IT!
public static String DEFAULT_AWS_SNS_URI_SCHEME = "http"; //GRZE: there references to specific services are not in the right scope here.
@ConfigurableField( description = "Default scheme for EUARE_URL in eucarc.",
changeListener = UriChangeListener.class,
initial = "http" )
@Deprecated //GRZE: this field will be superceded by new eucarc support in 3.4: DO NOT USE IT!
public static String DEFAULT_EUARE_URI_SCHEME = "http"; //GRZE: there references to specific services are not in the right scope here.
@ConfigurableField( description = "Default EUSTORE_URL in eucarc.",
changeListener = UriChangeListener.class,
initial = "http://emis.eucalyptus.com/" )
@Deprecated //GRZE: this field will be superceded by new eucarc support in 3.4: DO NOT USE IT!
public static String DEFAULT_EUSTORE_URL = "http://emis.eucalyptus.com/"; //GRZE: there references to specific services are not in the right scope here.
@ConfigurableField( description = "Request unknown parameter handling (default|ignore|error).", initial = "default" )
public static String UNKNOWN_PARAMETER_HANDLING = "default";
@ConfigurableField( description = "Enable request logging.", initial = "true",
changeListener = WebServices.CheckBooleanPropertyChangeListener.class )
public static volatile Boolean LOG_REQUESTS = true;
@ConfigurableField( description = "List of services with disabled SOAP APIs.", initial = "",
changeListener = WebServices.ComponentListPropertyChangeListener.class )
public static volatile String DISABLED_SOAP_API_COMPONENTS = "";
private static final String DEFAULT_SERVER_HEADER = "Eucalyptus/" + BillOfMaterials.getVersion( );
private static Logger LOG = Logger.getLogger( StackConfiguration.class );
public static Optional<String> getServerHeader( ) {
String headerValue = HTTP_SERVER_HEADER.trim( );
if ( "default".equals( headerValue ) ) {
headerValue = DEFAULT_SERVER_HEADER;
} else if ( headerValue.isEmpty( ) ) {
headerValue = null;
}
return Optional.ofNullable( headerValue );
}
public enum BasicTransport implements TransportDefinition {
HTTP {
@Override
public String getScheme( ) {
return "http";
}
@Override
public String getSecureScheme( ) {
return "https";
}
},
JMX {
@Override
public String getSecureScheme( ) {
return getScheme( );
}
@Override
public String getScheme( ) {
return "service:jmx:rmi:///jndi/rmi://";
}
},
JDBC {
@Override
public String getSecureScheme( ) {
return getScheme( );
}
@Override
public String getScheme( ) {
return Databases.getJdbcScheme( );
}
};
@Override
public abstract String getScheme( );
@Override
public abstract String getSecureScheme( );
}
@Deprecated //GRZE: this field will be superceded by new DNS support in 3.4: DO NOT USE IT!
public static String lookupDnsDomain( ) {
return SystemConfiguration.getSystemConfiguration( ).getDnsDomain( );//TODO:GRZE: sigh.
}
public static class TimeChangeListener implements PropertyChangeListener {
/**
* @see PropertyChangeListener#fireChange(ConfigurableProperty,
* Object)
*
* Validates that the new value is >= 0
*/
@Override
public void fireChange( ConfigurableProperty t, Object newValue ) throws ConfigurablePropertyException {
int time = -1;
try {
if ( newValue instanceof String ) {
time = Integer.parseInt( ( String ) newValue );
}
} catch ( NumberFormatException e ) {
LOG.debug( "Failed to parse int from " + newValue );
}
if ( time < 0 )
throw new ConfigurablePropertyException( "An integer >= 0 is expected for " + t.getFieldName( ) );
}
}
public static class TemporarySchemeUpdater implements PropertyChangeListener {
@Override
public void fireChange( ConfigurableProperty t, Object newValue ) throws ConfigurablePropertyException {
String scheme = Boolean.TRUE.equals( Boolean.parseBoolean("" + newValue ))
? "https"
: "http";
DEFAULT_AWS_SNS_URI_SCHEME = DEFAULT_EC2_URI_SCHEME = DEFAULT_EUARE_URI_SCHEME = DEFAULT_S3_URI_SCHEME = scheme;
}
}
public static class UriChangeListener implements PropertyChangeListener {
/**
* @see PropertyChangeListener#fireChange(ConfigurableProperty,
* Object)
*
* Validates that the new value is >= 0
*/
@Override
public void fireChange( ConfigurableProperty t, Object newValue ) throws ConfigurablePropertyException {
String prefix = null;
if ( newValue instanceof String ) {
prefix = ( String ) newValue;
if ( "http".equals( prefix ) || "https".equals( prefix ) )
return;
}
try {
URL url = new URL( (String) newValue );
} catch ( MalformedURLException e ) {
throw new ConfigurablePropertyException( "Invalid URL or URL prefix: " + t.getFieldName( ) + e);
}
}
}
}