1
1
package com.eucalyptus.cluster;
4
import java.io.FileWriter;
5
import java.io.IOException;
7
import java.security.KeyPair;
8
import java.security.cert.X509Certificate;
10
3
import java.util.NoSuchElementException;
11
4
import org.apache.log4j.Logger;
12
import com.eucalyptus.auth.Authentication;
13
import com.eucalyptus.auth.ClusterCredentials;
14
import com.eucalyptus.auth.Groups;
15
import com.eucalyptus.auth.SystemCredentialProvider;
16
import com.eucalyptus.auth.X509Cert;
17
import com.eucalyptus.auth.crypto.Certs;
18
import com.eucalyptus.auth.crypto.Hmacs;
19
import com.eucalyptus.auth.principal.Authorization;
20
import com.eucalyptus.auth.principal.AvailabilityZonePermission;
21
import com.eucalyptus.auth.principal.Group;
22
import com.eucalyptus.auth.util.PEMFiles;
23
import com.eucalyptus.bootstrap.Component;
24
import com.eucalyptus.component.Components;
25
import com.eucalyptus.component.DatabaseServiceBuilder;
26
import com.eucalyptus.component.DiscoverableServiceBuilder;
5
import com.eucalyptus.bootstrap.Handles;
6
import com.eucalyptus.component.AbstractServiceBuilder;
7
import com.eucalyptus.component.ComponentId;
8
import com.eucalyptus.component.ComponentId.ComponentPart;
9
import com.eucalyptus.component.ComponentIds;
10
import com.eucalyptus.component.Faults;
11
import com.eucalyptus.component.Partition;
12
import com.eucalyptus.component.Partitions;
27
13
import com.eucalyptus.component.ServiceConfiguration;
28
import com.eucalyptus.component.ServiceConfigurations;
29
14
import com.eucalyptus.component.ServiceRegistrationException;
30
import com.eucalyptus.config.ClusterConfiguration;
31
import com.eucalyptus.config.Configuration;
32
import com.eucalyptus.config.Handles;
33
import com.eucalyptus.config.RemoteConfiguration;
34
import com.eucalyptus.entities.EntityWrapper;
15
import com.eucalyptus.component.ServiceUris;
16
import com.eucalyptus.component.id.ClusterController;
17
import com.eucalyptus.config.DeregisterClusterType;
18
import com.eucalyptus.config.DescribeClustersType;
19
import com.eucalyptus.config.ModifyClusterAttributeType;
20
import com.eucalyptus.config.RegisterClusterType;
35
21
import com.eucalyptus.records.EventRecord;
36
22
import com.eucalyptus.records.EventType;
37
import com.eucalyptus.system.SubDirectory;
38
import com.eucalyptus.util.EucalyptusCloudException;
39
import edu.ucsb.eucalyptus.msgs.DeregisterClusterType;
40
import edu.ucsb.eucalyptus.msgs.DescribeClustersType;
41
import edu.ucsb.eucalyptus.msgs.RegisterClusterType;
23
import com.eucalyptus.records.Logs;
43
@DiscoverableServiceBuilder( com.eucalyptus.bootstrap.Component.cluster )
44
@Handles( { RegisterClusterType.class, DeregisterClusterType.class, DescribeClustersType.class } )
45
public class ClusterBuilder extends DatabaseServiceBuilder<ClusterConfiguration> {
46
private static Logger LOG = Logger.getLogger( ClusterBuilder.class );
25
@ComponentPart( ClusterController.class )
26
@Handles( { RegisterClusterType.class,
27
DeregisterClusterType.class,
28
DescribeClustersType.class,
29
ModifyClusterAttributeType.class } )
30
public class ClusterBuilder extends AbstractServiceBuilder<ClusterConfiguration> {
31
static Logger LOG = Logger.getLogger( ClusterBuilder.class );
34
public Boolean checkAdd( final String partition, final String name, final String host, final Integer port ) throws ServiceRegistrationException {
36
final Partition part = Partitions.lookup( this.newInstance( partition, name, host, port ) );
37
part.syncKeysToDisk( );
38
} catch ( final Exception ex ) {
39
Logs.extreme( ).error( ex, ex );
40
throw new ServiceRegistrationException( String.format( "Unexpected error caused cluster registration to fail for: partition=%s name=%s host=%s port=%d",
41
partition, name, host, port ), ex );
43
return super.checkAdd( partition, name, host, port );
49
47
public ClusterConfiguration newInstance( ) {
54
public ClusterConfiguration newInstance( String name, String host, Integer port ) {
55
return new ClusterConfiguration( name, host, port );
59
public com.eucalyptus.component.Component getComponent( ) {
60
return Components.lookup( Component.cluster );
64
public Boolean checkAdd( String name, String host, Integer port ) throws ServiceRegistrationException {
65
if ( !testClusterCredentialsDirectory( name ) ) {
66
throw new ServiceRegistrationException( "Cluster registration failed because the key directory cannot be created." );
68
return super.checkAdd( name, host, port );
73
public ClusterConfiguration add( String name, String host, Integer port ) throws ServiceRegistrationException {
74
ClusterConfiguration config = this.newInstance( name, host, port );
75
removeCredentials( config );
77
/** generate the Component keys **/
78
addCredentials( config );
79
addAuthorizations( config );
80
ServiceConfigurations.getInstance( ).store( config );
81
} catch ( EucalyptusCloudException e ) {
82
throw new ServiceRegistrationException( e.getMessage( ), e );
88
public void fireStart( ServiceConfiguration config ) throws ServiceRegistrationException {
89
EventRecord.here( ClusterBuilder.class, EventType.COMPONENT_SERVICE_START, config.getComponent( ).name( ), config.getName( ), config.getUri( ) ).info( );
91
if ( Components.lookup( Components.delegate.eucalyptus ).isLocal( ) ) {
52
public ClusterConfiguration newInstance( final String partition, final String name, final String host, final Integer port ) {
53
return new ClusterConfiguration( partition, name, host, port );
57
public ComponentId getComponentId( ) {
58
return ComponentIds.lookup( ClusterController.class );
62
public void fireStart( final ServiceConfiguration config ) throws ServiceRegistrationException {
63
LOG.info( "Starting cluster: " + config );
64
EventRecord.here( ClusterBuilder.class, EventType.COMPONENT_SERVICE_START, config.getComponentId( ).name( ), config.getName( ),
65
ServiceUris.remote( config ).toASCIIString( ) ).info( );
67
if ( !Clusters.getInstance( ).contains( config.getName( ) ) ) {
68
final Cluster newCluster = new Cluster( ( ClusterConfiguration ) config );//TODO:GRZE:fix the type issue here.
93
Clusters.start( ( ClusterConfiguration ) config );
94
} catch ( EucalyptusCloudException ex ) {
96
throw new ServiceRegistrationException( "Registration failed: " + ex.getMessage( ), ex );
72
final Cluster newCluster = Clusters.getInstance( ).lookupDisabled( config.getName( ) );
73
Clusters.getInstance( ).deregister( config.getName( ) );
75
} catch ( final NoSuchElementException ex ) {
76
final Cluster newCluster = Clusters.getInstance( ).lookup( config.getName( ) );
77
Clusters.getInstance( ).deregister( config.getName( ) );
98
super.fireStart( config );
100
} catch ( NoSuchElementException ex ) {
81
} catch ( final NoSuchElementException ex ) {
101
82
LOG.error( ex, ex );
106
public Boolean checkRemove( String name ) throws ServiceRegistrationException {
87
public void fireEnable( final ServiceConfiguration config ) throws ServiceRegistrationException {
88
LOG.info( "Enabling cluster: " + config );
89
EventRecord.here( ClusterBuilder.class, EventType.COMPONENT_SERVICE_ENABLED, config.getComponentId( ).name( ), config.getName( ),
90
ServiceUris.remote( config ).toASCIIString( ) ).info( );
108
Configuration.getStorageControllerConfiguration( name );
109
throw new ServiceRegistrationException( "Cannot deregister a cluster controller when there is a storage controller registered." );
110
} catch ( EucalyptusCloudException e ) {
117
public ClusterConfiguration remove( ServiceConfiguration removeConfig ) throws ServiceRegistrationException {
118
ClusterConfiguration config = ( ClusterConfiguration ) removeConfig;
119
removeAuthorizations( config );
120
removeKeys( config );
121
removeCredentials( config );
122
ServiceConfigurations.getInstance( ).remove( config );
123
return ( ClusterConfiguration ) config;
127
public void fireStop( ServiceConfiguration config ) throws ServiceRegistrationException {
128
Clusters.stop( config.getName( ) );
129
super.fireStop( config );
133
public ServiceConfiguration toConfiguration( URI uri ) throws ServiceRegistrationException {
134
return new RemoteConfiguration( this.getComponent( ).getPeer( ), uri );
137
private static void addAuthorizations( ClusterConfiguration config ) {
138
Groups.DEFAULT.addAuthorization( new AvailabilityZonePermission( config.getName( ) ) );
141
private static void addCredentials( ClusterConfiguration config ) throws ServiceRegistrationException {
142
String directory = SubDirectory.KEYS.toString( ) + File.separator + config.getName( );
143
File keyDir = new File( directory );
144
LOG.info( "creating keys in " + directory );
145
if ( !keyDir.mkdir( ) && !keyDir.exists( ) ) {
146
throw new ServiceRegistrationException( "Failed to create cluster key directory: " + keyDir.getAbsolutePath( ) );
147
} else if ( !keyDir.canWrite( ) ) {
148
throw new ServiceRegistrationException( "Cluster key directory is not writeable: " + keyDir.getAbsolutePath( ) );
93
final Cluster newCluster = Clusters.getInstance( ).lookupDisabled( config.getName( ) );
95
} catch ( final NoSuchElementException ex ) {
96
final Cluster newCluster = Clusters.getInstance( ).lookup( config.getName( ) );
99
} catch ( final NoSuchElementException ex ) {
151
KeyPair clusterKp = Certs.generateKeyPair( );
152
X509Certificate clusterX509 = Certs.generateServiceCertificate( clusterKp, "cc-" + config.getName( ) );
153
KeyPair nodeKp = Certs.generateKeyPair( );
154
X509Certificate nodeX509 = Certs.generateServiceCertificate( nodeKp, "nc-" + config.getName( ) );
155
FileWriter out = null;
106
public void fireDisable( final ServiceConfiguration config ) throws ServiceRegistrationException {
107
LOG.info( "Disabling cluster: " + config );
108
EventRecord.here( ClusterBuilder.class, EventType.COMPONENT_SERVICE_DISABLED, config.getComponentId( ).name( ), config.getName( ),
109
ServiceUris.remote( config ).toASCIIString( ) ).info( );
157
PEMFiles.write( directory + File.separator + "cluster-pk.pem", clusterKp.getPrivate( ) );
158
PEMFiles.write( directory + File.separator + "cluster-cert.pem", clusterX509 );
159
PEMFiles.write( directory + File.separator + "node-pk.pem", nodeKp.getPrivate( ) );
160
PEMFiles.write( directory + File.separator + "node-cert.pem", nodeX509 );
161
X509Certificate systemX509 = SystemCredentialProvider.getCredentialProvider( Component.eucalyptus ).getCertificate( );
162
String hexSig = Hmacs.generateSystemToken( "vtunpass".getBytes( ) );
163
PEMFiles.write( directory + File.separator + "cloud-cert.pem", systemX509 );
164
out = new FileWriter( directory + File.separator + "vtunpass" );
168
} catch ( IOException ex ) {
170
throw new ServiceRegistrationException( "Failed to store cluster keys: " + ex.getMessage( ), ex );
111
if ( Clusters.getInstance( ).contains( config.getName( ) ) ) {
175
} catch ( IOException e ) {
180
EntityWrapper<ClusterCredentials> credDb = Authentication.getEntityWrapper( );
182
ClusterCredentials componentCredentials = new ClusterCredentials( config.getName( ) );
184
componentCredentials = credDb.getUnique( componentCredentials );
185
componentCredentials.setClusterCertificate( X509Cert.fromCertificate( clusterX509 ) );
186
componentCredentials.setNodeCertificate( X509Cert.fromCertificate( nodeX509 ) );
187
credDb.merge( componentCredentials );
188
} catch ( Exception ex ) {
189
componentCredentials.setClusterCertificate( X509Cert.fromCertificate( clusterX509 ) );
190
componentCredentials.setNodeCertificate( X509Cert.fromCertificate( nodeX509 ) );
191
credDb.add( componentCredentials );
194
} catch ( Exception e ) {
200
private static void removeAuthorizations( ServiceConfiguration config ) {
201
for ( Group g : Groups.listAllGroups( ) ) {
202
for ( Authorization auth : g.getAuthorizations( ) ) {
203
if ( auth instanceof AvailabilityZonePermission && config.getName( ).equals( auth.getValue( ) ) ) {
204
g.removeAuthorization( auth );
210
private static void removeCredentials( ClusterConfiguration config ) {
211
EntityWrapper<ClusterCredentials> credDb = EntityWrapper.get( ClusterCredentials.class );
213
for ( ClusterCredentials ccert : credDb.query( new ClusterCredentials( ) ) ) {
214
LOG.debug( "Checking cluster certificate: " + ccert.getClusterName( ) + "\n" + X509Cert.toCertificate( ccert.getClusterCertificate( ) ) + "\n" + X509Cert.toCertificate( ccert.getNodeCertificate( ) ) );
215
if( config.getName( ).equals( ccert.getClusterName( ) ) ) {
216
credDb.recast( X509Cert.class ).delete( ccert.getClusterCertificate( ) );
217
credDb.recast( X509Cert.class ).delete( ccert.getNodeCertificate( ) );
218
credDb.delete( ccert );
219
LOG.debug( "Deleting cluster certificate: " + ccert.getClusterName( ) + "\n" + X509Cert.toCertificate( ccert.getClusterCertificate( ) ) + "\n" + X509Cert.toCertificate( ccert.getNodeCertificate( ) ) );
223
} catch ( Exception e ) {
229
private static synchronized void removeKeys( ServiceConfiguration config ) {
230
String directory = SubDirectory.KEYS.toString( ) + File.separator + config.getName( );
231
File keyDir = new File( directory );
232
if ( keyDir.exists( ) ) {
233
for ( File f : keyDir.listFiles( ) ) {
235
LOG.info( "Removing cluster key file: " + f.getAbsolutePath( ) );
237
LOG.info( "Failed to remove cluster key file: " + f.getAbsolutePath( ) );
240
if ( keyDir.delete( ) ) {
241
LOG.info( "Removing cluster key directory: " + keyDir.getAbsolutePath( ) );
243
LOG.info( "Failed to remove cluster key directory: " + keyDir.getAbsolutePath( ) );
248
static boolean testClusterCredentialsDirectory( String name ) {
249
String directory = SubDirectory.KEYS.toString( ) + File.separator + name;
250
File keyDir = new File( directory );
251
if ( !keyDir.exists( ) ) {
253
return keyDir.mkdir( ) && keyDir.canWrite( );
254
} catch ( Exception e ) {
258
return keyDir.canWrite( );
113
final Cluster newCluster = Clusters.getInstance( ).lookup( config.getName( ) );
114
newCluster.disable( );
115
} catch ( final NoSuchElementException ex ) {
116
final Cluster newCluster = Clusters.getInstance( ).lookupDisabled( config.getName( ) );
117
newCluster.disable( );
120
} catch ( final NoSuchElementException ex ) {
126
public void fireStop( final ServiceConfiguration config ) throws ServiceRegistrationException {
128
LOG.info( "Tearing down cluster: " + config );
129
final Cluster cluster = Clusters.getInstance( ).lookupDisabled( config.getName( ) );
130
EventRecord.here( ClusterBuilder.class, EventType.COMPONENT_SERVICE_STOPPED, config.getComponentId( ).name( ), config.getName( ),
131
ServiceUris.remote( config ).toASCIIString( ) ).info( );
133
} catch ( final NoSuchElementException ex ) {
135
} catch ( final Exception ex ) {
141
public void fireCheck( final ServiceConfiguration config ) throws ServiceRegistrationException {
143
Clusters.lookup( config ).check( );
144
} catch ( final NoSuchElementException ex ) {
145
throw Faults.failure( config, ex );
146
} catch ( final IllegalStateException ex ) {
147
Logs.exhaust( ).error( ex, ex );
148
throw Faults.failure( config, ex );
149
} catch ( final Exception ex ) {
150
Logs.exhaust( ).error( ex, ex );
151
throw Faults.failure( config, ex );