use of org.platformlayer.ops.MachineCreationRequest in project platformlayer by platformlayer.
the class PersistentInstanceMapper method handler.
@Handler
public void handler(PersistentInstance model) throws OpsException {
Machine machine = null;
Tag tagForInstance = Tag.buildParentTag(model.getKey());
// boolean instanceIsTagged = false;
// See if we have an instance id tag
{
// String instanceKey = model.getTags().findUnique(Tag.INSTANCE_KEY);
// if (instanceKey != null) {
// InstanceBase foundInstance = cloud.findInstanceByInstanceKey(PlatformLayerKey.parse(instanceKey));
// if (foundInstance == null) {
// throw new IllegalStateException("Tagged with instance id, but instance not found: " + instanceKey);
// }
// if (foundInstance.getState() == ManagedItemState.DELETED) {
// log.warn("Found deleted instance: " + foundInstance);
// } else {
// machine = cloudHelpers.toMachine(foundInstance);
// if (machine == null) {
// throw new IllegalStateException();
// }
// }
//
// // instanceIsTagged = true;
// }
}
if (machine == null) {
// We may have created a machine, but failed to tag the instance
machine = cloud.findMachine(tagForInstance);
}
if (!OpsContext.isDelete()) {
// We always PUT the machine
// TODO: Check if unchanged??
MachineCreationRequest request = buildMachineCreationRequest(model);
request.tags.add(tagForInstance);
machine = cloudHelpers.putInstanceByTag(request, model.getKey(), tagForInstance);
// if (machine == null) {
// // No machine
// MachineCreationRequest request = buildMachineCreationRequest(model);
// request.tags.add(tagForInstance);
//
// machine = cloudHelpers.createInstance(request, model.getKey(), tagForInstance);
// }
} else {
if (machine != null) {
cloudHelpers.terminateMachine(machine);
}
}
getRecursionState().pushChildScope(Machine.class, machine);
}
use of org.platformlayer.ops.MachineCreationRequest in project platformlayer by platformlayer.
the class CloudInstanceMapper method doOperation.
@Handler
public void doOperation() throws OpsException, IOException {
Tags instanceTags = instance.getTags();
GoogleCloud cloud = findCloud();
if (cloud == null) {
throw new OpsException("Could not find cloud");
}
GoogleComputeClient computeClient = googleComputeClientFactory.getComputeClient(cloud);
getRecursionState().pushChildScope(cloud);
List<String> assignedInstanceIds = instanceTags.findAll(Tag.ASSIGNED);
if (assignedInstanceIds.isEmpty()) {
if (createInstance && !OpsContext.isDelete()) {
MachineCreationRequest request = buildMachineCreationRequest();
PlatformLayerKey instanceKey = instance.getKey();
request.tags.add(Tag.buildParentTag(instanceKey));
PublicKey servicePublicKey = service.getSshKey().getKeyPair().getPublic();
Instance created = computeClient.createInstance(cloud, request, servicePublicKey);
{
Tag instanceTag = Tag.build(Tag.ASSIGNED, created.getName());
platformLayer.addTag(instance.getKey(), instanceTag);
}
assignedInstanceIds.add(created.getName());
}
}
if (assignedInstanceIds.isEmpty() && !OpsContext.isDelete()) {
throw new OpsException("Instance not yet assigned");
}
GoogleComputeMachine machine = null;
OpsTarget target = null;
if (!assignedInstanceIds.isEmpty()) {
if (assignedInstanceIds.size() != 1) {
log.warn("Multiple instance ids found: " + assignedInstanceIds);
}
// We just take the first instance id
String assignedInstanceId = Iterables.getFirst(assignedInstanceIds, null);
Instance server = computeClient.findInstanceByName(assignedInstanceId);
if (server == null) {
if (OpsContext.isConfigure()) {
throw new OpsException("Unable to find assigned server: " + assignedInstanceId);
}
} else {
server = computeClient.ensureHasPublicIp(server);
machine = new GoogleComputeMachine(computeClient, cloud, server);
SshKey sshKey = service.getSshKey();
target = machine.getTarget(GoogleComputeClient.USER_NAME, sshKey.getKeyPair());
// We need to use sudo while we set up root access
((SshOpsTarget) target).setEnsureRunningAsRoot(true);
}
}
if (!assignedInstanceIds.isEmpty() && OpsContext.isDelete()) {
for (String instanceId : assignedInstanceIds) {
Instance server = computeClient.findInstanceByName(instanceId);
if (server == null) {
log.warn("Could not find assigned server: " + instanceId + ", ignoring");
continue;
}
// TODO: Remove associated firewall rules
log.warn("Deleting firewall rules not yet implemented");
// SecurityGroup securityGroup = null;
// if (supportsSecurityGroups) {
// securityGroup = openstackHelpers.getMachineSecurityGroup(computeClient, server);
// }
Operation terminateOperation = computeClient.terminateInstance(instanceId);
try {
computeClient.waitComplete(terminateOperation, 5, TimeUnit.MINUTES);
} catch (TimeoutException e) {
throw new OpsException("Timeout while waiting for instance termination", e);
}
// if (securityGroup != null) {
// // We need to terminate the instance before we delete the security group it uses
// if (terminateOperation != null) {
// waitOperation(terminateOperation);
// }
//
// try {
// log.info("Deleting security group: " + securityGroup.getId());
// computeClient.root().securityGroups().securityGroup(securityGroup.getId()).delete();
// } catch (OpenstackNotFoundException e) {
// log.info("Ignoring not-found error while deleting security group: " + securityGroup.getId());
// }
// }
}
if (machine != null) {
machine.refreshState();
}
}
RecursionState recursion = getRecursionState();
if (OpsContext.isDelete() && machine == null) {
recursion.setPreventRecursion(true);
} else {
recursion.pushChildScope(machine);
recursion.pushChildScope(target);
}
}
use of org.platformlayer.ops.MachineCreationRequest in project platformlayer by platformlayer.
the class CloudInstanceMapper method buildMachineCreationRequest.
private MachineCreationRequest buildMachineCreationRequest() throws IOException {
MachineCreationRequest request = new MachineCreationRequest();
request.sshPublicKey = OpenSshUtils.readSshPublicKey(instance.sshPublicKey);
request.minimumMemoryMB = instance.minimumMemoryMb;
request.recipeId = instance.recipeId;
// request.securityGroups;
request.hostPolicy = instance.hostPolicy;
request.hostname = instance.hostname;
request.publicPorts = instance.publicPorts;
Tags tags = new Tags();
request.tags = tags;
return request;
}
use of org.platformlayer.ops.MachineCreationRequest in project platformlayer by platformlayer.
the class DiskImageController method buildImage.
public void buildImage(DiskImage image) throws OpsException, IOException {
// Assume the worst...
opsContext.setFailure(true);
MachineProvider targetCloud = cloudHelpers.getCloud(image.cloud);
DiskImageRecipe recipe = platformLayer.getItem(image.recipeId, DiskImageRecipe.class);
OperatingSystem operatingSystem = getRequestedOperatingSystem(recipe);
String kernelPackage = packageHelpers.getDefaultKernelPackage(operatingSystem);
String filesystem = "ext3";
ImageFormat imageFormat = EnumUtils.valueOfCaseInsensitive(ImageFormat.class, image.format);
boolean buildTar = imageFormat == ImageFormat.Tar;
// TODO: This logic is not intrinsically correct
// boolean supportCloudConfigDisk = imageFormat != ImageFormat.DiskQcow2;
boolean supportCloudConfigDisk = true;
boolean useConfigDriveSymlinks = false;
String configDriveLabel = "config";
List<String> packages = Lists.newArrayList();
packages.add("openssh-server");
// Needed for preseeding
packages.add("debconf-utils");
if (operatingSystem.getDistribution() == Distribution.Debian) {
packages.add("locales");
}
// We always want some basics available in our images
packages.add("curl");
String hostname = "openstack";
MachineCreationRequest request = new MachineCreationRequest();
SshKey sshKey = service.getSshKey();
// There are problems using LXC with debootstrap
request.hostPolicy = new HostPolicy();
request.hostPolicy.allowRunInContainer = false;
// Null means 'use bootstrap image'
request.recipeId = null;
request.sshPublicKey = sshKey.getKeyPair().getPublic();
request.sshPublicKeyName = service.getSshKeyName();
request.securityGroups = Lists.newArrayList();
String securityGroup = service.getSecurityGroupName();
request.securityGroups.add(securityGroup);
// We don't need a lot of memory to build a disk image (I think!)
request.minimumMemoryMB = 256;
Machine machine = cloud.createInstance(request, image.getKey());
opsContext.takeOwnership(machine);
machine = waitForAddress(machine);
OpsTarget target = machine.getTarget(sshKey);
waitForTarget(target);
File tempDir = target.createTempDir();
apt.update(target, true);
// We need to install curl first so we can detect the performance of our proxies
// Needed for proxy testing at least
apt.install(target, "curl");
CommandEnvironment httpProxyEnv = httpProxies.getHttpProxyEnvironment(target, Usage.SoftwarePackages, null);
// For now, we assume that this image doesn't have debootstrap pre-installed
apt.install(target, "debootstrap");
// For transferring the file to a direct image server
// debootstrap with LXC seems to have serious problems...
boolean supportLxc = false;
if (supportLxc) {
apt.install(target, "fakechroot", "fakeroot");
}
Command command;
File rootfsDir;
File imageFile;
File loopbackPartition = null;
if (!buildTar) {
apt.install(target, "mbr");
apt.install(target, "parted");
apt.install(target, "kpartx");
apt.install(target, "extlinux");
// Same with qemu-kvm
// (needed for qemu-img convert ... a lot of extra stuff for just the
// utils!)
// packageHelpers.getPackageFor("qemu-img", operatingSystem);
String qemuImgPackage = "qemu-utils";
apt.install(target, qemuImgPackage);
// Use local ephemeral storage...
imageFile = new File(tempDir, "image.raw");
command = Command.build("dd if=/dev/null bs=1M seek=8180 of={0}", imageFile);
target.executeCommand(command);
// Create partitions
target.executeCommand(Command.build("parted -s {0} mklabel msdos", imageFile));
target.executeCommand(Command.build("parted -s {0} mkpart primary 0% 100%", imageFile));
target.executeCommand(Command.build("parted -s {0} set 1 boot on", imageFile));
// Install Master Boot Record
target.executeCommand(Command.build("install-mbr {0}", imageFile));
// Mount the partitions
// Hopefully it’s loop0p1...
target.executeCommand(Command.build("modprobe dm-mod"));
// boolean isMounted = false;
//
// {
// ProcessExecution mountExecution = target.executeCommand(Command.build("mount", imageFile));
// String stdout = mountExecution.getStdOut();
// System.out.println(stdout);
//
// for (String line : Splitter.on('\n').split(stdout)) {
// line = line.trim();
// if (line.isEmpty()) {
// continue;
// }
//
// List<String> tokens = Lists.newArrayList(Splitter.on(' ').split(line));
// if (tokens.size() < 3) {
// throw new IllegalStateException("Cannot parse mount line: " + line);
// }
//
// String mountDir = tokens.get(2);
// if (mountDir.equals(mntDir.getAbsolutePath())) {
// isMounted = true;
// loopbackPartition = new File(tokens.get(0));
// break;
// }
// }
//
// // /dev/sda1 on / type ext4 (rw,errors=remount-ro)
// // tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
// // proc on /proc type proc (rw,noexec,nosuid,nodev)
// // sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
// // udev on /dev type tmpfs (rw,mode=0755)
// // tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
// // devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
// // /dev/mapper/loop0p1 on /tmp/8389210e66cd0df6/mnt type ext3 (rw)
// // proc on /tmp/8389210e66cd0df6/mnt/proc type proc (rw)
// }
//
// if (!isMounted)
{
ProcessExecution kpartxExecution = target.executeCommand(Command.build("kpartx -av {0}", imageFile));
String stdout = kpartxExecution.getStdOut();
List<String> tokens = Lists.newArrayList(Splitter.on(' ').split(stdout));
if (tokens.size() != 9) {
throw new IllegalStateException("Cannot parse kpartx stdout: " + stdout);
}
// add map loop6p1 (253:6): 0 16750592 linear /dev/loop6 2048
String partitionDevice = tokens.get(2);
if (!partitionDevice.startsWith("loop")) {
throw new IllegalStateException("kpartx output does not look like a partition: " + stdout);
}
loopbackPartition = new File("/dev/mapper/" + partitionDevice);
}
// Format filesystem
command = Command.build("yes | mkfs." + filesystem + " {0}", loopbackPartition);
command.setTimeout(TimeSpan.FIVE_MINUTES);
target.executeCommand(command);
// Get this onto disk now, so we don't delay later commands
target.executeCommand(Command.build("sync").setTimeout(TimeSpan.FIVE_MINUTES));
// Don’t force a check based on dates
target.executeCommand(Command.build("tune2fs -i 0 {0}", loopbackPartition).setTimeout(TimeSpan.FIVE_MINUTES));
// Get this onto disk now, so we don't delay later commands
target.executeCommand(Command.build("sync").setTimeout(TimeSpan.FIVE_MINUTES));
// Mount on mnt/
File mntDir = new File(tempDir, "mnt");
target.executeCommand("mkdir {0}", mntDir);
target.executeCommand(Command.build("mount {0} {1}", loopbackPartition, mntDir).setTimeout(TimeSpan.FIVE_MINUTES));
rootfsDir = mntDir;
} else {
rootfsDir = new File(tempDir, "rootfs");
imageFile = new File(tempDir, "image.tar.bz2");
}
if (buildTar) {
apt.install(target, "bzip2");
}
if (supportLxc) {
command = Command.build("fakechroot fakeroot debootstrap");
} else {
command = Command.build("debootstrap");
}
command.addLiteral("--verbose");
command.addLiteral("--resolve-deps");
if (supportLxc) {
// Lxc has problems with mounting etc; fakechroot avoids this
command.addLiteral("--variant=fakechroot");
// command.addLiteral("--variant=minbase");
}
command.addQuoted("--include=", Joiner.on(",").join(packages));
command.addLiteral(operatingSystem.getVersion());
command.addFile(rootfsDir);
// command.addQuoted(aptSource);
command.setEnvironment(httpProxyEnv);
command.setTimeout(TimeSpan.THIRTY_MINUTES);
try {
target.executeCommand(command);
} catch (ProcessExecutionException e) {
String debootstrapLog = target.readTextFile(new File(rootfsDir, "debootstrap/debootstrap.log"));
log.warn("Debootstrap log: " + debootstrapLog);
throw new OpsException("Error running debootstrap", e);
}
// TODO: Switch to ChrootOpsTarget, so we can move this stuff into utility functions
ChrootOpsTarget chrootTarget = new ChrootOpsTarget(rootfsDir, new File("/tmp"), target);
FileUpload.upload(target, new File(rootfsDir, "etc/hostname"), hostname);
{
// Stop services being started in the chroot
String policy = ResourceUtils.get(getClass(), "usr.sbin.policy-rc.d");
File policyFile = new File(rootfsDir, "usr/sbin/policy-rc.d");
FileUpload.upload(target, policyFile, policy);
target.chmod(policyFile, "755");
}
target.executeCommand("mount -t proc proc {0}", new File(rootfsDir, "proc"));
apt.update(chrootTarget, true);
target.executeCommand("chroot {0} locale-gen en_US.utf8", rootfsDir);
target.executeCommand("chroot {0} /bin/bash -c \"DEBIAN_FRONTEND=noninteractive dpkg-reconfigure locales\"", rootfsDir);
if (!buildTar) {
{
File kernelImgConf = new File(rootfsDir, "etc/kernel-img.conf");
String preseedData = ResourceUtils.get(getClass(), "kernel-img.conf");
FileUpload.upload(target, kernelImgConf, preseedData);
}
{
File preseedTmpDir = target.createTempDir();
File preseedFile = new File(preseedTmpDir, "kernel.preseed");
String preseedData = ResourceUtils.get(getClass(), "kernel.preseed");
FileUpload.upload(target, preseedFile, preseedData);
target.executeCommand(Command.build("cat {0} | chroot {1} debconf-set-selections", preseedFile, rootfsDir));
apt.install(chrootTarget, kernelPackage);
}
}
preconfigurePackages(chrootTarget, recipe.configurePackage);
if (recipe.repositoryKey != null) {
addRepositoryKeys(chrootTarget, recipe.repositoryKey);
}
if (recipe.repository != null) {
addRepositories(chrootTarget, recipe.repository);
apt.update(chrootTarget, true);
}
if (recipe.addPackage != null) {
apt.install(chrootTarget, recipe.addPackage);
if (recipe.addPackage.contains("jenkins")) {
// It looks like jenkins doesn't honor policy-rc.d (?)
// TODO: Fix this monstrosity...
log.warn("Hard-coding service stop after jenkins installation");
target.executeCommand(Command.build("chroot {0} /etc/init.d/jenkins stop", rootfsDir));
}
}
apt.upgrade(chrootTarget);
apt.clean(chrootTarget);
if (!buildTar) {
String uuid;
{
ProcessExecution uuidExecution = target.executeCommand("blkid -o value -s UUID {0}", loopbackPartition);
uuid = uuidExecution.getStdOut().trim();
}
// Set up /etc/fstab
String fstab = "# /etc/fstab: static file system information.\n";
// TODO: Swap
fstab += "proc\t/proc\tproc\tnodev,noexec,nosuid\t0\t0\n";
// fstab += "/dev/sda1\t/\t" + filesystem +
// "\terrors=remount-ro\t0\t1\n";
fstab += String.format("UUID=%s\t/\t%s\terrors=remount-ro\t0\t1\n", uuid, filesystem);
if (supportCloudConfigDisk) {
if (useConfigDriveSymlinks) {
// Use configuration from cloud_config mount
target.mkdir(new File(rootfsDir, "media/config"));
fstab += "/dev/disk/by-label/" + configDriveLabel + "\t/media/config\tudf,iso9660\tro\t0\t0\n";
}
}
FileUpload.upload(target, new File(rootfsDir, "etc/fstab"), fstab);
log.info("fstab = " + fstab);
// Set up extlinux
{
ProcessExecution kernelExecution = target.executeCommand("chroot {0} find boot/ -name \"vmlinuz-*\"", rootfsDir);
List<String> kernels = Lists.newArrayList();
for (String kernel : kernelExecution.getStdOut().split("\n")) {
kernel = kernel.trim();
if (kernel.isEmpty()) {
continue;
}
kernels.add(kernel);
}
if (kernels.size() > 1) {
throw new IllegalStateException("Multiple kernels found");
} else if (kernels.size() != 1) {
throw new IllegalStateException("No kernels found");
}
ProcessExecution initrdExecution = target.executeCommand("chroot {0} find boot/ -name \"initrd*\"", rootfsDir);
List<String> initrds = Lists.newArrayList();
for (String initrd : initrdExecution.getStdOut().split("\n")) {
initrd = initrd.trim();
if (initrd.isEmpty()) {
continue;
}
if (initrd.endsWith(".bak")) {
continue;
}
initrds.add(initrd);
}
if (initrds.size() > 1) {
throw new IllegalStateException("Multiple initrds found");
} else if (initrds.size() != 1) {
throw new IllegalStateException("No initrds found");
}
String conf = String.format("default linux\ntimeout 1\n\nlabel linux\nkernel %s\nappend initrd=%s root=UUID=%s ro quiet", kernels.get(0), initrds.get(0), uuid);
FileUpload.upload(target, new File(rootfsDir, "extlinux.conf"), conf);
log.info("extlinux.conf = " + conf);
}
target.executeCommand(Command.build("extlinux --install {0}", rootfsDir).setTimeout(TimeSpan.FIVE_MINUTES));
}
if (supportCloudConfigDisk) {
if (useConfigDriveSymlinks) {
target.rm(new File(rootfsDir, "etc/network/interfaces"));
target.executeCommand("ln -s /media/config/etc/network/interfaces {0}", new File(rootfsDir, "etc/network/interfaces"));
target.mkdir(new File(rootfsDir, "root/.ssh"));
target.executeCommand("ln -s /media/config/root/.ssh/authorized_keys {0}", new File(rootfsDir, "root/.ssh/authorized_keys"));
} else {
String initScript = ResourceUtils.get(getClass(), "openstack-config");
File initScriptFile = new File(rootfsDir, "etc/init.d/openstack-config");
FileUpload.upload(target, initScriptFile, initScript);
target.executeCommand("chmod +x {0}", initScriptFile);
chrootTarget.executeCommand("/usr/sbin/update-rc.d openstack-config defaults");
}
}
{
// Remove policy file
File policyFile = new File(rootfsDir, "usr/sbin/policy-rc.d");
target.rm(policyFile);
}
target.executeCommand("sync");
target.executeCommand("umount {0}", new File(rootfsDir, "proc"));
if (!buildTar) {
target.executeCommand("sync");
target.executeCommand("umount {0}", rootfsDir);
target.executeCommand("sync");
target.executeCommand("kpartx -d {0}", imageFile);
target.executeCommand("sync");
}
if (buildTar) {
Command compress = Command.build("cd {0}; tar jcf {1} .", rootfsDir, imageFile);
target.executeCommand(compress.setTimeout(TimeSpan.FIFTEEN_MINUTES));
}
FilesystemInfo imageInfo = target.getFilesystemInfoFile(imageFile);
File uploadImageFile;
if (!buildTar) {
boolean isQcow2 = imageFormat == ImageFormat.DiskQcow2;
if (isQcow2) {
// We create the image as a raw image (making use of sparse files)
// and then convert it to qcow2. This is a little less efficient, but
// has a few advantages...
// 1) We can support different formats
// 2) The final image is defragmented
// 3) Mounting a qcow2 image (or other image formats) is tricky vs
// loopback mount
uploadImageFile = new File(imageFile.getParentFile(), "image.qcow2");
command = Command.build("qemu-img convert -f raw -O qcow2 {0} {1}", imageFile, uploadImageFile);
command.setTimeout(TimeSpan.THIRTY_MINUTES);
target.executeCommand(command);
} else {
uploadImageFile = new File(imageFile.getParentFile(), "image.raw.gz");
command = Command.build("gzip -c --best {0} > {1}", imageFile, uploadImageFile);
command.setTimeout(TimeSpan.THIRTY_MINUTES);
target.executeCommand(command);
}
} else {
uploadImageFile = imageFile;
}
String imageId;
// Upload & tag the image with the recipe ID
{
Tags tags = new Tags();
tags.add(Tag.buildParentTag(recipe.getKey()));
tags.add(imageFormat.toTag());
imageId = cloud.getImageStore(targetCloud).uploadImage(target, tags, uploadImageFile, imageInfo.size);
}
// Tag the recipe with the image ID
{
TagChanges tagChanges = new TagChanges();
tagChanges.addTags.add(Tag.IMAGE_ID.build(imageId));
platformLayer.changeTags(image.getKey(), tagChanges);
}
// Our pessimism proved unfounded...
opsContext.setFailure(false);
}
use of org.platformlayer.ops.MachineCreationRequest in project platformlayer by platformlayer.
the class PersistentInstanceMapper method buildMachineCreationRequest.
private MachineCreationRequest buildMachineCreationRequest(PersistentInstance model) throws OpsException {
MachineCreationRequest request = new MachineCreationRequest();
try {
request.sshPublicKey = OpenSshUtils.readSshPublicKey(model.sshPublicKey);
} catch (IOException e) {
throw new OpsException("Error reading sshPublicKey", e);
}
request.cloud = model.cloud;
request.hostname = model.dnsName;
request.hostPolicy = model.hostPolicy;
Tags tags = new Tags();
tags.addAll(Tag.HOST_POLICY.filter(tags));
request.tags = tags;
if (model.securityGroup != null) {
request.securityGroups = Lists.newArrayList();
request.securityGroups.add(model.securityGroup);
}
request.minimumMemoryMB = model.minimumRam;
request.recipeId = model.recipe;
request.publicPorts = model.publicPorts;
return request;
}
Aggregations