~ubuntu-branches/ubuntu/raring/eucalyptus/raring

« back to all changes in this revision

Viewing changes to clc/modules/walrus/src/main/java/edu/ucsb/eucalyptus/storage/fs/DRBDStorageManager.java

  • Committer: Package Import Robot
  • Author(s): Brian Thomason
  • Date: 2011-11-29 13:17:52 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 185.
  • Revision ID: package-import@ubuntu.com-20111129131752-rq31al3ntutv2vvl
Tags: upstream-3.0.999beta1
ImportĀ upstreamĀ versionĀ 3.0.999beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*******************************************************************************
 
2
 *Copyright (c) 2009  Eucalyptus Systems, Inc.
 
3
 * 
 
4
 *  This program is free software: you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation, only version 3 of the License.
 
7
 * 
 
8
 * 
 
9
 *  This file is distributed in the hope that it will be useful, but WITHOUT
 
10
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
12
 *  for more details.
 
13
 * 
 
14
 *  You should have received a copy of the GNU General Public License along
 
15
 *  with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 * 
 
17
 *  Please contact Eucalyptus Systems, Inc., 130 Castilian
 
18
 *  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
 
19
 *  if you need additional information or have any questions.
 
20
 * 
 
21
 *  This file may incorporate work covered under the following copyright and
 
22
 *  permission notice:
 
23
 * 
 
24
 *    Software License Agreement (BSD License)
 
25
 * 
 
26
 *    Copyright (c) 2008, Regents of the University of California
 
27
 *    All rights reserved.
 
28
 * 
 
29
 *    Redistribution and use of this software in source and binary forms, with
 
30
 *    or without modification, are permitted provided that the following
 
31
 *    conditions are met:
 
32
 * 
 
33
 *      Redistributions of source code must retain the above copyright notice,
 
34
 *      this list of conditions and the following disclaimer.
 
35
 * 
 
36
 *      Redistributions in binary form must reproduce the above copyright
 
37
 *      notice, this list of conditions and the following disclaimer in the
 
38
 *      documentation and/or other materials provided with the distribution.
 
39
 * 
 
40
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
41
 *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
42
 *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
43
 *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 
44
 *    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
45
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
46
 *    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
47
 *    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
48
 *    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
49
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
50
 *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
 
51
 *    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
 
52
 *    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
 
53
 *    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
 
54
 *    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
 
55
 *    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
 
56
 *    THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
 
57
 *    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
 
58
 *    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
 
59
 *    ANY SUCH LICENSES OR RIGHTS.
 
60
 *******************************************************************************/
 
61
/*
 
62
 *
 
63
 * Author: Neil Soman neil@eucalyptus.com
 
64
 */
 
65
 
 
66
package edu.ucsb.eucalyptus.storage.fs;
 
67
 
 
68
import java.io.File;
 
69
import java.util.NavigableSet;
 
70
 
 
71
import org.apache.log4j.Logger;
 
72
 
 
73
import com.eucalyptus.component.Component;
 
74
import com.eucalyptus.component.Components;
 
75
import com.eucalyptus.component.Service;
 
76
import com.eucalyptus.component.ServiceConfiguration;
 
77
import com.eucalyptus.component.id.Walrus;
 
78
import com.eucalyptus.util.EucalyptusCloudException;
 
79
import java.util.concurrent.ExecutionException;
 
80
import com.eucalyptus.util.WalrusProperties;
 
81
 
 
82
import edu.ucsb.eucalyptus.cloud.entities.DRBDInfo;
 
83
import edu.ucsb.eucalyptus.cloud.entities.WalrusInfo;
 
84
import edu.ucsb.eucalyptus.storage.fs.FileSystemStorageManager;
 
85
import edu.ucsb.eucalyptus.util.SystemUtil;
 
86
 
 
87
public class DRBDStorageManager extends FileSystemStorageManager {
 
88
 
 
89
        private static Logger LOG = Logger.getLogger( DRBDStorageManager.class );
 
90
        private static final String PRIMARY_ROLE = "Primary";
 
91
        private static final String SECONDARY_ROLE = "Secondary";
 
92
        private static final String DSTATE_UPTODATE = "UpToDate";
 
93
        private static final String DSTATE_UNKNOWN = "Unknown";
 
94
        private static final String CSTATE_WFCONNECTION = "WFConnection";
 
95
        private static final String CSTATE_CONNECTED = "Connected";
 
96
 
 
97
        public DRBDStorageManager() {
 
98
        }
 
99
 
 
100
        private String getConnectionStatus() throws ExecutionException, EucalyptusCloudException {
 
101
                String returnValue = SystemUtil.run(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "cstate", DRBDInfo.getDRBDInfo().getResource()});
 
102
                if(returnValue.length() == 0) {
 
103
                        throw new EucalyptusCloudException("Unable to get connection status for resource: " + DRBDInfo.getDRBDInfo().getResource());
 
104
                }
 
105
                return returnValue;
 
106
        }
 
107
 
 
108
        private String getDataStatus() throws ExecutionException, EucalyptusCloudException {
 
109
                String returnValue = SystemUtil.run(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "dstate", DRBDInfo.getDRBDInfo().getResource()});
 
110
                if(returnValue.length() == 0) {
 
111
                        throw new EucalyptusCloudException("Unable to get data status for resource: " + DRBDInfo.getDRBDInfo().getResource());
 
112
                }
 
113
                return returnValue;
 
114
        }
 
115
 
 
116
        /**
 
117
         * @return
 
118
         * @throws ExecutionException
 
119
         * @throws EucalyptusCloudException
 
120
         */
 
121
        private String getRole() throws ExecutionException, EucalyptusCloudException {
 
122
                String returnValue = SystemUtil.run(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "role", DRBDInfo.getDRBDInfo().getResource()});
 
123
                if(returnValue.length() == 0) {
 
124
                        throw new EucalyptusCloudException("Unable to get role for resource: " + DRBDInfo.getDRBDInfo().getResource());
 
125
                }
 
126
                return returnValue;
 
127
        }
 
128
 
 
129
        /*This method does not check if resource is already primary*/
 
130
        /**
 
131
         * @throws ExecutionException
 
132
         * @throws EucalyptusCloudException
 
133
         */
 
134
        private void makePrimary() throws ExecutionException, EucalyptusCloudException {
 
135
                if(SystemUtil.runAndGetCode(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "primary", DRBDInfo.getDRBDInfo().getResource()}) != 0) {
 
136
                        throw new EucalyptusCloudException("Unable to make resource " + DRBDInfo.getDRBDInfo().getResource() + " primary");
 
137
                }
 
138
        }
 
139
 
 
140
        /*This method does not check if resource is already secondary*/
 
141
        /**
 
142
         * @throws ExecutionException
 
143
         * @throws EucalyptusCloudException
 
144
         */
 
145
        private void makeSecondary() throws ExecutionException, EucalyptusCloudException {              
 
146
                if(SystemUtil.runAndGetCode(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "secondary", DRBDInfo.getDRBDInfo().getResource()}) != 0) {
 
147
                        throw new EucalyptusCloudException("Unable to make resource " + DRBDInfo.getDRBDInfo().getResource() + " secondary");
 
148
                }
 
149
        }
 
150
 
 
151
        private void connectResource() throws ExecutionException, EucalyptusCloudException {
 
152
                if(SystemUtil.runAndGetCode(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "connect", DRBDInfo.getDRBDInfo().getResource()}) != 0) {
 
153
                        throw new EucalyptusCloudException("Unable to connect resource: " + DRBDInfo.getDRBDInfo().getResource());
 
154
                }
 
155
        }
 
156
 
 
157
        private void disconnectResource() throws ExecutionException, EucalyptusCloudException {
 
158
                if(SystemUtil.runAndGetCode(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "disconnect", DRBDInfo.getDRBDInfo().getResource()}) != 0) {
 
159
                        throw new EucalyptusCloudException("Unable to disconnect resource: " + DRBDInfo.getDRBDInfo().getResource());
 
160
                }
 
161
        }
 
162
 
 
163
        //create config
 
164
        private void generateConfig() {
 
165
 
 
166
        }
 
167
 
 
168
        private void mountPrimary() throws ExecutionException, EucalyptusCloudException {
 
169
                if(SystemUtil.runAndGetCode(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_MOUNT_WRAPPER, "mount", DRBDInfo.getDRBDInfo().getBlockDevice(), WalrusInfo.getWalrusInfo().getStorageDir(), WalrusProperties.EUCA_USER}) != 0) {
 
170
                        throw new EucalyptusCloudException("Unable to mount " + DRBDInfo.getDRBDInfo().getBlockDevice() + " as " + WalrusInfo.getWalrusInfo().getStorageDir());
 
171
                }
 
172
                SystemUtil.setEucaReadWriteOnly(WalrusInfo.getWalrusInfo().getStorageDir());
 
173
        }
 
174
 
 
175
        private void unmountPrimary() throws ExecutionException, EucalyptusCloudException {
 
176
                if(SystemUtil.runAndGetCode(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_MOUNT_WRAPPER, "umount", WalrusInfo.getWalrusInfo().getStorageDir()}) != 0) {
 
177
                        throw new EucalyptusCloudException("Unable to unmount " + DRBDInfo.getDRBDInfo().getBlockDevice());
 
178
                }
 
179
        }
 
180
 
 
181
        /**
 
182
         * We use /proc/mounts because EUCA_ROOT_WRAPPER uses a syscall and does not update /etc/mtab
 
183
         * @return
 
184
         * @throws ExecutionException
 
185
         */
 
186
        private boolean isMounted() throws EucalyptusCloudException {
 
187
                String returnValue = SystemUtil.run(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "cat", "/proc/mounts"});
 
188
                if(returnValue.length() > 0) {
 
189
                        if(returnValue.contains(DRBDInfo.getDRBDInfo().getBlockDevice())) {
 
190
                                return true;
 
191
                        }
 
192
                }
 
193
                return false;
 
194
        }
 
195
 
 
196
        private boolean isPrimary() throws EucalyptusCloudException, ExecutionException {
 
197
                String roleString = getRole();
 
198
                String[] roleParts = roleString.split("/");
 
199
                if(roleParts.length > 1) {
 
200
                        if(roleParts[0].startsWith(PRIMARY_ROLE)) {
 
201
                                return true;
 
202
                        } else {
 
203
                                return false;
 
204
                        }                        
 
205
                } else {
 
206
                        throw new EucalyptusCloudException("Unable to parse role.");
 
207
                }
 
208
        }
 
209
 
 
210
        private boolean isSecondary() throws EucalyptusCloudException, ExecutionException {
 
211
                String roleString = getRole();
 
212
                String[] roleParts = roleString.split("/");
 
213
                if(roleParts.length > 1) {
 
214
                        if(roleParts[0].startsWith(SECONDARY_ROLE)) {
 
215
                                return true;
 
216
                        } else {
 
217
                                return false;
 
218
                        }                        
 
219
                } else {
 
220
                        throw new EucalyptusCloudException("Unable to parse role.");
 
221
                }
 
222
        }
 
223
 
 
224
        private boolean isPeerPrimary() throws EucalyptusCloudException, ExecutionException {
 
225
                String roleString = getRole();
 
226
                String[] roleParts = roleString.split("/");
 
227
                if(roleParts.length > 1) {
 
228
                        if(roleParts[1].startsWith(PRIMARY_ROLE)) {
 
229
                                return true;
 
230
                        } else {
 
231
                                return false;
 
232
                        }                        
 
233
                } else {
 
234
                        throw new EucalyptusCloudException("Unable to parse role.");
 
235
                }
 
236
        }
 
237
 
 
238
        private boolean isPeerSecondary() throws EucalyptusCloudException, ExecutionException {
 
239
                String roleString = getRole();
 
240
                String[] roleParts = roleString.split("/");
 
241
                if(roleParts.length > 1) {
 
242
                        if(roleParts[1].startsWith(SECONDARY_ROLE)) {
 
243
                                return true;
 
244
                        } else {
 
245
                                return false;
 
246
                        }                        
 
247
                } else {
 
248
                        throw new EucalyptusCloudException("Unable to parse role.");
 
249
                }
 
250
        }
 
251
 
 
252
        private boolean isConnected() throws ExecutionException, EucalyptusCloudException {
 
253
                String cstateString = getConnectionStatus();
 
254
                if((cstateString != null) && cstateString.startsWith(CSTATE_CONNECTED)) {
 
255
                        return true;
 
256
                } else {
 
257
                        return false;
 
258
                }
 
259
        }
 
260
 
 
261
        private boolean isUpToDate() throws EucalyptusCloudException, ExecutionException {
 
262
                String dstateString = getDataStatus();
 
263
                String[] dstateParts = dstateString.split("/");
 
264
                if(dstateParts.length > 1) {
 
265
                        if(dstateParts[0].startsWith(DSTATE_UPTODATE) && (dstateParts[1].startsWith(DSTATE_UPTODATE))) {
 
266
                                return true;
 
267
                        } else {
 
268
                                return false;
 
269
                        }
 
270
                } else {
 
271
                        throw new EucalyptusCloudException("Unable to get resource dstate.");
 
272
                }               
 
273
        }
 
274
 
 
275
        private void checkLocalDisk() throws EucalyptusCloudException {         
 
276
                String blockDevice = DRBDInfo.getDRBDInfo().getBlockDevice();
 
277
                File mount = new File(blockDevice);
 
278
                if(!mount.exists()) {
 
279
                        throw new EucalyptusCloudException("Block device " + blockDevice + " not found."); 
 
280
                }
 
281
                String storageDir = WalrusInfo.getWalrusInfo().getStorageDir();
 
282
                File root = new File(storageDir);
 
283
                if(!root.exists()) {
 
284
                        throw new EucalyptusCloudException("Storage directory " + storageDir + " not found.");                  
 
285
                }
 
286
        }
 
287
 
 
288
        public void becomeMaster() throws EucalyptusCloudException, ExecutionException {                
 
289
                checkLocalDisk();
 
290
                //role, cstate, dstate
 
291
                if(!isPrimary()) {
 
292
                        //make primary
 
293
                        if(isPeerPrimary()) {
 
294
                                throw new EucalyptusCloudException("Peer is primary and I am supposed to be master! Unable to proceed!");
 
295
                        }
 
296
                        makePrimary();
 
297
                }
 
298
                if(!isConnected()) {
 
299
                        try {
 
300
                                connectResource();
 
301
                        } catch (Exception e) {
 
302
                                LOG.error(e);
 
303
                        }
 
304
                }
 
305
                //mount
 
306
                if(!isMounted()) {
 
307
                        try {
 
308
                                mountPrimary();
 
309
                        } catch(Exception e) {
 
310
                                //undo
 
311
                                if(isPrimary()) {
 
312
                                        makeSecondary();
 
313
                                }
 
314
                        }
 
315
                }
 
316
                //verify state
 
317
                if(!isPrimary()) {
 
318
                        throw new EucalyptusCloudException("Unable to make resource primary.");
 
319
                }
 
320
        }
 
321
 
 
322
        public void becomeSlave() throws EucalyptusCloudException, ExecutionException {
 
323
                checkLocalDisk();
 
324
                //check mount point, block device, role, cstate, dstate
 
325
                if(isMounted()) {
 
326
                        unmountPrimary();
 
327
                }
 
328
                if(!isSecondary()) {
 
329
                        //make secondary
 
330
                        makeSecondary();
 
331
                }
 
332
                if(!isConnected()) {
 
333
                        try {
 
334
                                connectResource();
 
335
                        } catch(Exception e) {
 
336
                                LOG.error(e);
 
337
                        }
 
338
                }
 
339
                //verify state
 
340
                if(!isSecondary()) {
 
341
                        throw new EucalyptusCloudException("Unable to make resource secondary.");
 
342
                }
 
343
                if(!isPeerPrimary()) {
 
344
                        LOG.warn("Warning! Peer is not primary. No usable component?");
 
345
                }
 
346
        }
 
347
        //check status
 
348
 
 
349
        public void secondaryDrasticRecovery() throws ExecutionException, EucalyptusCloudException {
 
350
                if(SystemUtil.runAndGetCode(new String[]{WalrusProperties.eucaHome + WalrusProperties.EUCA_ROOT_WRAPPER, "drbdadm", "--", "--discard-my-data", "connect", DRBDInfo.getDRBDInfo().getResource()}) != 0) {
 
351
                        throw new EucalyptusCloudException("Unable to recover from split brain for resource: " + DRBDInfo.getDRBDInfo().getResource());
 
352
                }
 
353
        }
 
354
 
 
355
        @Override
 
356
        public void enable() throws EucalyptusCloudException {
 
357
                try {
 
358
                        becomeMaster();
 
359
                } catch (ExecutionException e) {
 
360
                        throw new EucalyptusCloudException(e);
 
361
                }
 
362
        }
 
363
 
 
364
        @Override
 
365
        public void disable() throws EucalyptusCloudException {
 
366
                try {
 
367
                        becomeSlave();
 
368
                } catch (ExecutionException e) {
 
369
                        throw new EucalyptusCloudException(e);
 
370
                }
 
371
        }
 
372
        //verify consistency
 
373
 
 
374
        @Override
 
375
        public void check() throws EucalyptusCloudException {
 
376
                try {
 
377
                        boolean notConnected = false;
 
378
                        if(!isConnected()) {
 
379
                                try {
 
380
                                        connectResource();
 
381
                                } catch(Exception e) {
 
382
                                        LOG.error(e);
 
383
                                }
 
384
                        }
 
385
                        if (Component.State.ENABLED.equals(Components.lookup(Walrus.class).getState())) {
 
386
                                if(!isPrimary()) {
 
387
                                        throw new EucalyptusCloudException("I am the master, but not DRBD primary. Please make me primary. Aborting!");
 
388
                                }
 
389
                        } else {
 
390
                                if((isConnected()) && (!isUpToDate())) {
 
391
                                        throw new EucalyptusCloudException("Resource connected but not up to date!");
 
392
                                }
 
393
                                if (Component.State.DISABLED.equals(Components.lookup(Walrus.class).getState())) {
 
394
                                        if(!isSecondary()) {
 
395
                                                LOG.warn("I am the slave, but not DRBD secondary. Trying to become secondary...");
 
396
                                                if(isMounted()) {
 
397
                                                        unmountPrimary();
 
398
                                                }
 
399
                                                //make secondary
 
400
                                                makeSecondary();
 
401
                                                if(!isSecondary()) {
 
402
                                                        throw new EucalyptusCloudException("Attempt to set secondary failed. Unable to proceed!");
 
403
                                                }
 
404
                                        }
 
405
                                }
 
406
                        }
 
407
                } catch(ExecutionException ex) {
 
408
                        throw new EucalyptusCloudException(ex);
 
409
                }
 
410
        }
 
411
 
 
412
        @Override
 
413
        public void start() throws EucalyptusCloudException {
 
414
                try {
 
415
                        becomeSlave();
 
416
                } catch (ExecutionException e) {
 
417
                        throw new EucalyptusCloudException(e);
 
418
                }
 
419
        }
 
420
 
 
421
        @Override
 
422
        public void stop() throws EucalyptusCloudException {
 
423
                try {
 
424
                        if(isMounted()) {
 
425
                                unmountPrimary();
 
426
                        }
 
427
                        if(!isSecondary()) {
 
428
                                //make secondary
 
429
                                makeSecondary();
 
430
                        }
 
431
                } catch(ExecutionException ex) {
 
432
                        throw new EucalyptusCloudException(ex);
 
433
                }
 
434
        }
 
435
 
 
436
}