| /* |
| Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package nfc |
| |
| import ( |
| "context" |
| "errors" |
| "fmt" |
| "io" |
| "path" |
| |
| "github.com/vmware/govmomi/property" |
| "github.com/vmware/govmomi/vim25" |
| "github.com/vmware/govmomi/vim25/methods" |
| "github.com/vmware/govmomi/vim25/mo" |
| "github.com/vmware/govmomi/vim25/progress" |
| "github.com/vmware/govmomi/vim25/soap" |
| "github.com/vmware/govmomi/vim25/types" |
| ) |
| |
| type Lease struct { |
| types.ManagedObjectReference |
| |
| c *vim25.Client |
| } |
| |
| func NewLease(c *vim25.Client, ref types.ManagedObjectReference) *Lease { |
| return &Lease{ref, c} |
| } |
| |
| // Abort wraps methods.Abort |
| func (l *Lease) Abort(ctx context.Context, fault *types.LocalizedMethodFault) error { |
| req := types.HttpNfcLeaseAbort{ |
| This: l.Reference(), |
| Fault: fault, |
| } |
| |
| _, err := methods.HttpNfcLeaseAbort(ctx, l.c, &req) |
| if err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| // Complete wraps methods.Complete |
| func (l *Lease) Complete(ctx context.Context) error { |
| req := types.HttpNfcLeaseComplete{ |
| This: l.Reference(), |
| } |
| |
| _, err := methods.HttpNfcLeaseComplete(ctx, l.c, &req) |
| if err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| // GetManifest wraps methods.GetManifest |
| func (l *Lease) GetManifest(ctx context.Context) error { |
| req := types.HttpNfcLeaseGetManifest{ |
| This: l.Reference(), |
| } |
| |
| _, err := methods.HttpNfcLeaseGetManifest(ctx, l.c, &req) |
| if err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| // Progress wraps methods.Progress |
| func (l *Lease) Progress(ctx context.Context, percent int32) error { |
| req := types.HttpNfcLeaseProgress{ |
| This: l.Reference(), |
| Percent: percent, |
| } |
| |
| _, err := methods.HttpNfcLeaseProgress(ctx, l.c, &req) |
| if err != nil { |
| return err |
| } |
| |
| return nil |
| } |
| |
| type LeaseInfo struct { |
| types.HttpNfcLeaseInfo |
| |
| Items []FileItem |
| } |
| |
| func (l *Lease) newLeaseInfo(li *types.HttpNfcLeaseInfo, items []types.OvfFileItem) (*LeaseInfo, error) { |
| info := &LeaseInfo{ |
| HttpNfcLeaseInfo: *li, |
| } |
| |
| for _, device := range li.DeviceUrl { |
| u, err := l.c.ParseURL(device.Url) |
| if err != nil { |
| return nil, err |
| } |
| |
| if device.SslThumbprint != "" { |
| // TODO: prefer host management IP |
| l.c.SetThumbprint(u.Host, device.SslThumbprint) |
| } |
| |
| if len(items) == 0 { |
| // this is an export |
| item := types.OvfFileItem{ |
| DeviceId: device.Key, |
| Path: device.TargetId, |
| Size: device.FileSize, |
| } |
| |
| if item.Size == 0 { |
| item.Size = li.TotalDiskCapacityInKB * 1024 |
| } |
| |
| if item.Path == "" { |
| item.Path = path.Base(device.Url) |
| } |
| |
| info.Items = append(info.Items, NewFileItem(u, item)) |
| |
| continue |
| } |
| |
| // this is an import |
| for _, item := range items { |
| if device.ImportKey == item.DeviceId { |
| info.Items = append(info.Items, NewFileItem(u, item)) |
| break |
| } |
| } |
| } |
| |
| return info, nil |
| } |
| |
| func (l *Lease) Wait(ctx context.Context, items []types.OvfFileItem) (*LeaseInfo, error) { |
| var lease mo.HttpNfcLease |
| |
| pc := property.DefaultCollector(l.c) |
| err := property.Wait(ctx, pc, l.Reference(), []string{"state", "info", "error"}, func(pc []types.PropertyChange) bool { |
| done := false |
| |
| for _, c := range pc { |
| if c.Val == nil { |
| continue |
| } |
| |
| switch c.Name { |
| case "error": |
| val := c.Val.(types.LocalizedMethodFault) |
| lease.Error = &val |
| done = true |
| case "info": |
| val := c.Val.(types.HttpNfcLeaseInfo) |
| lease.Info = &val |
| case "state": |
| lease.State = c.Val.(types.HttpNfcLeaseState) |
| if lease.State != types.HttpNfcLeaseStateInitializing { |
| done = true |
| } |
| } |
| } |
| |
| return done |
| }) |
| |
| if err != nil { |
| return nil, err |
| } |
| |
| if lease.State == types.HttpNfcLeaseStateReady { |
| return l.newLeaseInfo(lease.Info, items) |
| } |
| |
| if lease.Error != nil { |
| return nil, errors.New(lease.Error.LocalizedMessage) |
| } |
| |
| return nil, fmt.Errorf("unexpected nfc lease state: %s", lease.State) |
| } |
| |
| func (l *Lease) StartUpdater(ctx context.Context, info *LeaseInfo) *LeaseUpdater { |
| return newLeaseUpdater(ctx, l, info) |
| } |
| |
| func (l *Lease) Upload(ctx context.Context, item FileItem, f io.Reader, opts soap.Upload) error { |
| if opts.Progress == nil { |
| opts.Progress = item |
| } else { |
| opts.Progress = progress.Tee(item, opts.Progress) |
| } |
| |
| // Non-disk files (such as .iso) use the PUT method. |
| // Overwrite: t header is also required in this case (ovftool does the same) |
| if item.Create { |
| opts.Method = "PUT" |
| opts.Headers = map[string]string{ |
| "Overwrite": "t", |
| } |
| } else { |
| opts.Method = "POST" |
| opts.Type = "application/x-vnd.vmware-streamVmdk" |
| } |
| |
| return l.c.Upload(ctx, f, item.URL, &opts) |
| } |
| |
| func (l *Lease) DownloadFile(ctx context.Context, file string, item FileItem, opts soap.Download) error { |
| if opts.Progress == nil { |
| opts.Progress = item |
| } else { |
| opts.Progress = progress.Tee(item, opts.Progress) |
| } |
| |
| return l.c.DownloadFile(ctx, file, item.URL, &opts) |
| } |