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 }
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 }