use of org.jvnet.solaris.libzfs.ZFSException in project hudson-2.x by hudson.
the class ZFSInstaller method migrate.
/**
* Migrates $HUDSON_HOME to a new ZFS file system.
*
* TODO: do this in a separate JVM to elevate the privilege.
*
* @param listener
* Log of migration goes here.
* @param target
* Dataset to move the data to.
* @return
* false if a migration failed.
*/
private static boolean migrate(TaskListener listener, String target) throws IOException, InterruptedException {
PrintStream out = listener.getLogger();
File home = Hudson.getInstance().getRootDir();
// do the migration
LibZFS zfs = new LibZFS();
ZFSFileSystem existing = zfs.getFileSystemByMountPoint(home);
if (existing != null) {
out.println(home + " is already on ZFS. Doing nothing");
return true;
}
File tmpDir = Util.createTempDir();
// mount a new file system to a temporary location
out.println("Opening " + target);
ZFSFileSystem hudson = zfs.open(target, ZFSFileSystem.class);
hudson.setMountPoint(tmpDir);
// mark this file system as "managed by Hudson"
hudson.setProperty("hudson:managed-by", "hudson");
hudson.mount();
// copy all the files
out.println("Copying all existing data files");
if (system(home, listener, "/usr/bin/cp", "-pR", ".", tmpDir.getAbsolutePath()) != 0) {
out.println("Failed to copy " + home + " to " + tmpDir);
return false;
}
// unmount
out.println("Unmounting " + target);
hudson.unmount(MountFlags.MS_FORCE);
// move the original directory to the side
File backup = new File(home.getPath() + ".backup");
out.println("Moving " + home + " to " + backup);
if (backup.exists())
Util.deleteRecursive(backup);
if (!home.renameTo(backup)) {
out.println("Failed to move your current data " + home + " out of the way");
}
// update the mount point
out.println("Creating a new mount point at " + home);
if (!home.mkdir())
throw new IOException("Failed to create mount point " + home);
out.println("Mounting " + target);
hudson.setMountPoint(home);
hudson.mount();
out.println("Sharing " + target);
try {
hudson.setProperty("sharesmb", "on");
hudson.setProperty("sharenfs", "on");
hudson.share();
} catch (ZFSException e) {
listener.error("Failed to share the file systems: " + e.getCode());
}
// delete back up
out.println("Deleting " + backup);
if (system(new File("/"), listener, "/usr/bin/rm", "-rf", backup.getAbsolutePath()) != 0) {
out.println("Failed to delete " + backup.getAbsolutePath());
return false;
}
out.println("Migration completed");
return true;
}
use of org.jvnet.solaris.libzfs.ZFSException in project hudson-2.x by hudson.
the class ZFSInstaller method createZfsFileSystem.
/**
* Creates a ZFS file system to migrate the data to.
*
* <p>
* This has to be done while we still have an interactive access with the user, since it involves the password.
*
* <p>
* An exception will be thrown if the operation fails. A normal completion means a success.
*
* @return
* The ZFS dataset name to migrate the data to.
*/
private String createZfsFileSystem(final TaskListener listener, String rootUsername, String rootPassword) throws IOException, InterruptedException, ZFSException {
// capture the UID that Hudson runs under
// so that we can allow this user to do everything on this new partition
final int uid = LIBC.geteuid();
final int gid = LIBC.getegid();
passwd pwd = LIBC.getpwuid(uid);
if (pwd == null)
throw new IOException("Failed to obtain the current user information for " + uid);
final String userName = pwd.pw_name;
final File home = Hudson.getInstance().getRootDir();
// return true indicating a success
return SU.execute(listener, rootUsername, rootPassword, new Callable<String, IOException>() {
public String call() throws IOException {
PrintStream out = listener.getLogger();
LibZFS zfs = new LibZFS();
ZFSFileSystem existing = zfs.getFileSystemByMountPoint(home);
if (existing != null) {
// no need for migration
out.println(home + " is already on ZFS. Doing nothing");
return existing.getName();
}
String name = computeHudsonFileSystemName(zfs, zfs.roots().get(0));
out.println("Creating " + name);
ZFSFileSystem hudson = zfs.create(name, ZFSFileSystem.class);
// mount temporarily to set the owner right
File dir = Util.createTempDir();
hudson.setMountPoint(dir);
hudson.mount();
if (LIBC.chown(dir.getPath(), uid, gid) != 0)
throw new IOException("Failed to chown " + dir);
hudson.unmount();
try {
// mark this file system as "managed by Hudson"
hudson.setProperty("hudson:managed-by", "hudson");
ACLBuilder acl = new ACLBuilder();
acl.user(userName).withEverything();
hudson.allow(acl);
} catch (ZFSException e) {
// revert the file system creation
try {
hudson.destory();
} catch (Exception _) {
// but ignore the error and let the original error thrown
}
throw e;
}
return hudson.getName();
}
});
}
use of org.jvnet.solaris.libzfs.ZFSException in project hudson-2.x by hudson.
the class ZFSInstaller method doStart.
/**
* Called from the confirmation screen to actually initiate the migration.
*/
public void doStart(StaplerRequest req, StaplerResponse rsp, @QueryParameter String username, @QueryParameter String password) throws ServletException, IOException {
requirePOST();
Hudson hudson = Hudson.getInstance();
hudson.checkPermission(Hudson.ADMINISTER);
final String datasetName;
ByteArrayOutputStream log = new ByteArrayOutputStream();
StreamTaskListener listener = new StreamTaskListener(log);
try {
datasetName = createZfsFileSystem(listener, username, password);
} catch (Exception e) {
e.printStackTrace(listener.error(e.getMessage()));
if (e instanceof ZFSException) {
ZFSException ze = (ZFSException) e;
if (ze.getCode() == ErrorCode.EZFS_PERM) {
// permission problem. ask the user to give us the root password
req.setAttribute("message", log.toString());
rsp.forward(this, "askRootPassword", req);
return;
}
}
// for other kinds of problems, report and bail out
req.setAttribute("pre", true);
sendError(log.toString(), req, rsp);
return;
}
// file system creation successful, so restart
WebAppController.get().install(new HudsonIsRestarting());
// redirect the user to the manage page
rsp.sendRedirect2(req.getContextPath() + "/manage");
// asynchronously restart, so that we can give a bit of time to the browser to load "restarting..." screen.
new Thread("restart thread") {
@Override
public void run() {
try {
Thread.sleep(5000);
// close all descriptors on exec except stdin,out,err
int sz = LIBC.getdtablesize();
for (int i = 3; i < sz; i++) {
int flags = LIBC.fcntl(i, F_GETFD);
if (flags < 0)
continue;
LIBC.fcntl(i, F_SETFD, flags | FD_CLOEXEC);
}
// re-exec with the system property to indicate where to migrate the data to.
// the 2nd phase is implemented in the migrate method.
JavaVMArguments args = JavaVMArguments.current();
args.setSystemProperty(ZFSInstaller.class.getName() + ".migrate", datasetName);
Daemon.selfExec(args);
} catch (InterruptedException e) {
LOGGER.log(Level.SEVERE, "Restart failed", e);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Restart failed", e);
}
}
}.start();
}
Aggregations