Ejemplo n.º 1
0
// Calling in parallel is ok
func (gc *gceCluster) NewMachine(cloudConfig string) (Machine, error) {
	cconfig, err := config.NewCloudConfig(cloudConfig)
	if err != nil {
		return nil, err
	}
	if err = gc.sshAgent.UpdateConfig(cconfig); err != nil {
		return nil, err
	}
	cloudConfig = cconfig.String()

	// Create gce VM and wait for creation to succeed.
	gm, err := GCECreateVM(gc.api, gc.conf, cloudConfig)
	if err != nil {
		return nil, err
	}
	gm.gc = gc

	err = sshCheck(gm)
	if err != nil {
		gm.Destroy()
		return nil, err
	}

	gc.mu.Lock()
	gc.machines[gm.ID()] = gm
	gc.mu.Unlock()

	return Machine(gm), nil
}
Ejemplo n.º 2
0
// NewConf parses userdata and returns a new Conf. It returns an error if the
// userdata can't be parsed as a coreos-cloudinit or ignition configuration.
func NewConf(userdata string) (*Conf, error) {
	c := &Conf{}

	ignc, err := ign.Parse([]byte(userdata))
	switch err {
	case ign.ErrEmpty:
		// empty, noop
		// XXX(mischief): i would use ignition as the default config,
		// but there's no way to load it in qemu yet.
		c.cloudconfig = &defConfig
	case ign.ErrCloudConfig:
		// fall back to cloud-config
		c.cloudconfig, err = cci.NewCloudConfig(userdata)
		if err != nil {
			return nil, err
		}
	default:
		// some other error (invalid json, script)
		return nil, err
	case nil:
		c.ignition = &ignc
	}

	return c, nil
}
Ejemplo n.º 3
0
func GCECreateVM(api *compute.Service, opts *GCEOptions, userdata string) (*gceMachine, error) {
	if userdata != "" {
		_, err := config.NewCloudConfig(userdata)
		if err != nil {
			return nil, err
		}
	}

	// generate name
	name, err := newName(opts)
	if err != nil {
		return nil, fmt.Errorf("Failed allocating unique name for vm: %v\n", err)
	}

	instance, err := gceMakeInstance(opts, userdata, name)
	if err != nil {
		return nil, err
	}

	// request instance
	op, err := api.Instances.Insert(opts.Project, opts.Zone, instance).Do()
	if err != nil {
		return nil, fmt.Errorf("Failed to create new VM: %v\n", err)
	}

	fmt.Fprintf(os.Stderr, "Instance %v requested\n", name)
	fmt.Fprintf(os.Stderr, "Waiting for creation to finish...\n")

	// wait for creation to finish
	err = gceWaitVM(api, opts.Project, opts.Zone, op.Name)
	if err != nil {
		return nil, err
	}

	inst, err := api.Instances.Get(opts.Project, opts.Zone, name).Do()
	if err != nil {
		return nil, fmt.Errorf("Error getting instance %s details after creation: %v", name, err)
	}
	intIP, extIP := instanceIPs(inst)

	gm := &gceMachine{
		name:  name,
		extIP: extIP,
		intIP: intIP,
	}

	return gm, nil
}
Ejemplo n.º 4
0
func (ac *awsCluster) NewMachine(userdata string) (Machine, error) {
	cloudConfig, err := config.NewCloudConfig(userdata)
	if err != nil {
		return nil, err
	}

	if err = ac.agent.UpdateConfig(cloudConfig); err != nil {
		return nil, err
	}

	if cloudConfig.Hostname == "" {
		id := make([]byte, 4)
		_, _ = rand.Read(id)
		cloudConfig.Hostname = fmt.Sprintf("%x", id)
	}

	ud := base64.StdEncoding.EncodeToString([]byte(cloudConfig.String()))
	cnt := int64(1)

	inst := ec2.RunInstancesInput{
		ImageId:        &ac.conf.AMI,
		MinCount:       &cnt,
		MaxCount:       &cnt,
		KeyName:        &ac.conf.KeyName, // this is only useful if you wish to ssh in for debugging
		InstanceType:   &ac.conf.InstanceType,
		SecurityGroups: []*string{&ac.conf.SecurityGroup},
		UserData:       &ud,
	}

	resp, err := ac.api.RunInstances(&inst)
	if err != nil {
		return nil, err
	}

	ids := []*string{resp.Instances[0].InstanceId}

	if err := waitForAWSInstances(ac.api, ids, 5*time.Minute); err != nil {
		return nil, err
	}

	getinst := &ec2.DescribeInstancesInput{
		InstanceIds: ids,
	}

	insts, err := ac.api.DescribeInstances(getinst)
	if err != nil {
		return nil, err
	}

	mach := &awsMachine{
		cluster: ac,
		mach:    insts.Reservations[0].Instances[0],
	}

	// Allow a few authentication failures in case setup is slow.
	sshchecker := func() error {
		mach.sshClient, err = mach.cluster.agent.NewClient(mach.IP())
		if err != nil {
			return err
		}
		return nil
	}

	if err := util.Retry(sshRetries, sshTimeout, sshchecker); err != nil {
		mach.Destroy()
		return nil, err
	}

	ac.addMach(mach)

	return mach, nil
}
Ejemplo n.º 5
0
func (qc *qemuCluster) NewMachine(cfg string) (Machine, error) {
	id := uuid.NewV4()

	// hacky solution for cloud config ip substitution
	// NOTE: escaping is not supported
	qc.mu.Lock()
	netif := qc.Dnsmasq.GetInterface("br0")
	ip := strings.Split(netif.DHCPv4[0].String(), "/")[0]

	cfg = strings.Replace(cfg, "$public_ipv4", ip, -1)
	cfg = strings.Replace(cfg, "$private_ipv4", ip, -1)

	cloudConfig, err := config.NewCloudConfig(cfg)
	if err != nil {
		qc.mu.Unlock()
		return nil, err
	}

	if err = qc.SSHAgent.UpdateConfig(cloudConfig); err != nil {
		qc.mu.Unlock()
		return nil, err
	}

	if cloudConfig.Hostname == "" {
		cloudConfig.Hostname = id.String()[:8]
	}

	qc.mu.Unlock()

	configDrive, err := local.NewConfigDrive(cloudConfig)
	if err != nil {
		return nil, err
	}

	qm := &qemuMachine{
		qc:          qc,
		id:          id.String(),
		configDrive: configDrive,
		netif:       netif,
	}

	disk, err := setupDisk(qc.conf.DiskImage)
	if err != nil {
		return nil, err
	}
	defer disk.Close()

	qc.mu.Lock()

	tap, err := qc.NewTap("br0")
	if err != nil {
		qc.mu.Unlock()
		return nil, err
	}
	defer tap.Close()

	qmMac := qm.netif.HardwareAddr.String()
	qmCfg := qm.configDrive.Directory
	qm.qemu = qm.qc.NewCommand(
		"qemu-system-x86_64",
		"-machine", "accel=kvm",
		"-cpu", "host",
		"-smp", "2",
		"-m", "1024",
		"-uuid", qm.id,
		"-display", "none",
		"-add-fd", "fd=3,set=1",
		"-drive", "file=/dev/fdset/1,media=disk,if=virtio,format=raw",
		"-netdev", "tap,id=tap,fd=4",
		"-device", "virtio-net,netdev=tap,mac="+qmMac,
		"-fsdev", "local,id=cfg,security_model=none,readonly,path="+qmCfg,
		"-device", "virtio-9p-pci,fsdev=cfg,mount_tag=config-2")

	qc.mu.Unlock()

	cmd := qm.qemu.(*local.NsCmd)
	cmd.Stderr = os.Stderr
	cmd.ExtraFiles = append(cmd.ExtraFiles, disk)     // fd=3
	cmd.ExtraFiles = append(cmd.ExtraFiles, tap.File) // fd=4

	if err = qm.qemu.Start(); err != nil {
		return nil, err
	}

	// Allow a few authentication failures in case setup is slow.
	sshchecker := func() error {
		qm.qc.mu.Lock()
		defer qm.qc.mu.Unlock()
		qm.sshClient, err = qm.qc.SSHAgent.NewClient(qm.IP())
		if err != nil {
			return err
		}
		return nil
	}

	if err := util.Retry(sshRetries, sshTimeout, sshchecker); err != nil {
		return nil, err
	}

	if err != nil {
		qm.Destroy()
		return nil, err
	}

	out, err := qm.SSH("grep ^ID= /etc/os-release")
	if err != nil {
		qm.Destroy()
		return nil, err
	}

	if !bytes.Equal(out, []byte("ID=coreos")) {
		qm.Destroy()
		return nil, fmt.Errorf("Unexpected SSH output: %s", out)
	}

	qc.mu.Lock()
	qc.machines[qm.ID()] = qm
	qc.mu.Unlock()

	return Machine(qm), nil
}