github.com/coreos/mantle@v0.13.0/platform/api/esx/lease.go (about)

     1  // Copyright (c) 2016 VMware, Inc. All Rights Reserved.
     2  // Copyright 2017 CoreOS, Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package esx
    17  
    18  import (
    19  	"context"
    20  	"sync"
    21  	"sync/atomic"
    22  	"time"
    23  
    24  	"github.com/vmware/govmomi/object"
    25  	"github.com/vmware/govmomi/vim25"
    26  )
    27  
    28  type leaseUpdater struct {
    29  	lease *object.HttpNfcLease
    30  
    31  	pos   int64 // Number of bytes
    32  	total int64 // Total number of bytes
    33  
    34  	done chan struct{} // When lease updater should stop
    35  
    36  	wg sync.WaitGroup // Track when update loop is done
    37  }
    38  
    39  func newLeaseUpdater(client *vim25.Client, lease *object.HttpNfcLease, items []ovfFileItem) *leaseUpdater {
    40  	l := leaseUpdater{
    41  		lease: lease,
    42  
    43  		done: make(chan struct{}),
    44  	}
    45  
    46  	for _, item := range items {
    47  		l.total += item.item.Size
    48  		go l.waitForProgress(item)
    49  	}
    50  
    51  	// Kickstart update loop
    52  	l.wg.Add(1)
    53  	go l.run()
    54  
    55  	return &l
    56  }
    57  
    58  func (l *leaseUpdater) waitForProgress(item ovfFileItem) {
    59  	var pos, total int64
    60  
    61  	total = item.item.Size
    62  
    63  	for {
    64  		select {
    65  		case <-l.done:
    66  			return
    67  		case p, ok := <-item.ch:
    68  			// Return in case of error
    69  			if ok && p.Error() != nil {
    70  				return
    71  			}
    72  
    73  			if !ok {
    74  				// Last element on the channel, add to total
    75  				atomic.AddInt64(&l.pos, total-pos)
    76  				return
    77  			}
    78  
    79  			// Approximate progress in number of bytes
    80  			x := int64(float32(total) * (p.Percentage() / 100.0))
    81  			atomic.AddInt64(&l.pos, x-pos)
    82  			pos = x
    83  		}
    84  	}
    85  }
    86  
    87  func (l *leaseUpdater) run() {
    88  	defer l.wg.Done()
    89  
    90  	tick := time.NewTicker(2 * time.Second)
    91  	defer tick.Stop()
    92  
    93  	for {
    94  		select {
    95  		case <-l.done:
    96  			return
    97  		case <-tick.C:
    98  			// From the vim api HttpNfcLeaseProgress(percent) doc, percent ==
    99  			// "Completion status represented as an integer in the 0-100 range."
   100  			// Always report the current value of percent, as it will renew the
   101  			// lease even if the value hasn't changed or is 0.
   102  			percent := int32(float32(100*atomic.LoadInt64(&l.pos)) / float32(l.total))
   103  			err := l.lease.HttpNfcLeaseProgress(context.TODO(), percent)
   104  			if err != nil {
   105  				plog.Debugf("from lease updater: %s\n", err)
   106  			}
   107  		}
   108  	}
   109  }
   110  
   111  func (l *leaseUpdater) Done() {
   112  	close(l.done)
   113  	l.wg.Wait()
   114  }