func dispatch(context *cpi.Context, actions map[string]cpi.ActionFn, method string, args []interface{}) (result []byte) {
	// Attempt to recover from any panic that may occur during API calls
	defer func() {
		if r := recover(); r != nil {
			if _, ok := r.(runtime.Error); ok {
				// Don't even try to recover severe runtime errors
				panic(r)
			}
			e := fmt.Errorf("%v", r)
			context.Logger.Error(e)
			result = createErrorResponse(e, context.Logger.LogData())
		}
	}()
	if fn, ok := actions[method]; ok {
		context.Logger.Infof("Begin action %s", method)
		context.Logger.Infof("Raw action arguments: %#v", args)

		res, err := fn(context, args)
		if err != nil {
			context.Logger.Errorf("Error encountered during action %s: %v", method, err)
			return createErrorResponse(err, context.Logger.LogData())
		}

		context.Logger.Infof("Action response: %#v", res)
		context.Logger.Infof("End action %s", method)
		return createResponse(res, context.Logger.LogData())
	} else {
		e := cpi.NewBoshError(cpi.NotSupportedError, false, "Method %s not supported in photon CPI.", method)
		context.Logger.Error(e)
		return createErrorResponse(e, context.Logger.LogData())
	}
	return
}
Example #2
0
func CreateVM(ctx *cpi.Context, args []interface{}) (result interface{}, err error) {
	if len(args) < 6 {
		return nil, errors.New("Expected at least 6 arguments")
	}
	agentID, ok := args[0].(string)
	if !ok {
		return nil, errors.New("Unexpected argument where agent_id should be")
	}
	stemcellCID, ok := args[1].(string)
	if !ok {
		return nil, errors.New("Unexpected argument where stemcell_cid should be")
	}
	cloudPropsMap, ok := args[2].(map[string]interface{})
	if !ok {
		return nil, errors.New("Unexpected argument where cloud_properties should be")
	}

	cloudProps, err := ParseCloudProps(cloudPropsMap)
	if err != nil {
		return nil, err
	}

	networks, ok := args[3].(map[string]interface{})
	if !ok {
		return nil, errors.New("Unexpected argument where networks should be")
	}
	// Ignore args[4] for now, which is disk_cids
	env, ok := args[5].(map[string]interface{})
	if !ok {
		return nil, errors.New("Unexpected argument where env should be")
	}

	ctx.Logger.Infof(
		"CreateVM with agent_id: '%v', stemcell_cid: '%v', cloud_properties: '%v', networks: '%v', env: '%v'",
		agentID, stemcellCID, cloudProps, networks, env)

	ephDiskName := "bosh-ephemeral-disk"
	spec := &ec.VmCreateSpec{
		Name:          "bosh-vm",
		Flavor:        cloudProps.VMFlavor,
		SourceImageID: stemcellCID,
		AttachedDisks: []ec.AttachedDisk{
			ec.AttachedDisk{
				CapacityGB: 50, // Ignored
				Flavor:     cloudProps.DiskFlavor,
				Kind:       "ephemeral-disk",
				Name:       "boot-disk",
				State:      "STARTED",
				BootDisk:   true,
			},
			ec.AttachedDisk{
				CapacityGB: cloudProps.VMAttachedDiskSizeGB,
				Flavor:     cloudProps.DiskFlavor,
				Kind:       "ephemeral-disk",
				Name:       ephDiskName,
				State:      "STARTED",
				BootDisk:   false,
			},
		},
	}
	ctx.Logger.Infof("Creating VM with spec: %#v", spec)
	vmTask, err := ctx.Client.Projects.CreateVM(ctx.Config.Photon.ProjectID, spec)
	if err != nil {
		return
	}
	ctx.Logger.Infof("Waiting on task: %#v", vmTask)
	vmTask, err = ctx.Client.Tasks.Wait(vmTask.ID)
	if err != nil {
		return
	}

	// Get disk details of VM
	ctx.Logger.Infof("Getting details of VM: %s", vmTask.Entity.ID)
	vm, err := ctx.Client.VMs.Get(vmTask.Entity.ID)
	if err != nil {
		return
	}
	diskID := ""
	for _, disk := range vm.AttachedDisks {
		if disk.Name == ephDiskName {
			diskID = disk.ID
			break
		}
	}
	if diskID == "" {
		err = cpi.NewBoshError(
			cpi.CloudError, false, "Could not find ID for ephemeral disk of new VM %s", vm.ID)
		return
	}

	// Create agent config
	agentEnv := &cpi.AgentEnv{
		AgentID:  agentID,
		VM:       cpi.VMSpec{Name: vm.Name, ID: vm.ID},
		Networks: networks,
		Env:      env,
		Mbus:     ctx.Config.Agent.Mbus,
		NTP:      ctx.Config.Agent.NTP,
		Disks: map[string]interface{}{
			"ephemeral": map[string]interface{}{
				"id":   diskID,
				"path": "/dev/sdb"},
		},
		Blobstore: cpi.BlobstoreSpec{
			Provider: ctx.Config.Agent.Blobstore.Provider,
			Options:  ctx.Config.Agent.Blobstore.Options,
		},
	}

	// Create and attach agent env ISO file
	err = updateAgentEnv(ctx, vmTask.Entity.ID, agentEnv)
	if err != nil {
		return
	}

	ctx.Logger.Info("Starting VM")
	onTask, err := ctx.Client.VMs.Start(vmTask.Entity.ID)
	if err != nil {
		return
	}
	ctx.Logger.Infof("Waiting on task: %#v", onTask)
	onTask, err = ctx.Client.Tasks.Wait(onTask.ID)
	if err != nil {
		return
	}

	return vmTask.Entity.ID, nil
}