github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/providers/openstack/list_instances.go (about)

     1  package openstack
     2  
     3  import (
     4  	"github.com/sirupsen/logrus"
     5  	"github.com/emc-advanced-dev/pkg/errors"
     6  	"github.com/solo-io/unik/pkg/types"
     7  	"github.com/rackspace/gophercloud"
     8  	"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
     9  	"github.com/rackspace/gophercloud/pagination"
    10  	"strings"
    11  )
    12  
    13  func (p *OpenstackProvider) ListInstances() ([]*types.Instance, error) {
    14  	// Return immediately if no instance is managed by unik.
    15  	managedInstances := p.state.GetInstances()
    16  	if len(managedInstances) < 1 {
    17  		return []*types.Instance{}, nil
    18  	}
    19  
    20  	clientNova, err := p.newClientNova()
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  
    25  	instList, err := fetchInstances(clientNova, managedInstances)
    26  
    27  	// Update state.
    28  	if err := p.state.ModifyInstances(func(instances map[string]*types.Instance) error {
    29  		// Clear everything.
    30  		for k := range instances {
    31  			delete(instances, k)
    32  		}
    33  
    34  		// Add fetched instances.
    35  		for _, inst := range instList {
    36  			instances[inst.Id] = inst
    37  		}
    38  		return nil
    39  	}); err != nil {
    40  		return nil, errors.New("failed to modify instance map in state", err)
    41  	}
    42  
    43  	return instList, nil
    44  }
    45  
    46  // fetchInstances fetches a list of instances runnign on OpenStack and returns a list of
    47  // those that are managed by unik.
    48  func fetchInstances(clientNova *gophercloud.ServiceClient, managedInstances map[string]*types.Instance) ([]*types.Instance, error) {
    49  	var result []*types.Instance = make([]*types.Instance, 0)
    50  
    51  	pagerServers := servers.List(clientNova, servers.ListOpts{})
    52  	pagerServers.EachPage(func(page pagination.Page) (bool, error) {
    53  		serverList, err := servers.ExtractServers(page)
    54  		if err != nil {
    55  			return false, err
    56  		}
    57  
    58  		for _, s := range serverList {
    59  			// Filter out instances that unik is not aware of.
    60  			instance, ok := managedInstances[s.ID]
    61  			if !ok {
    62  				continue
    63  			}
    64  
    65  			// Interpret instance state and filter out instance with bad state.
    66  			if state := parseInstanceState(s.Status); state == types.InstanceState_Terminated {
    67  				continue
    68  			} else {
    69  				instance.State = state
    70  			}
    71  
    72  			// Update fields.
    73  			instance.Name = s.Name
    74  			instance.IpAddress = s.AccessIPv4
    75  
    76  			result = append(result, instance)
    77  		}
    78  
    79  		return true, nil
    80  	})
    81  	return result, nil
    82  }
    83  
    84  func parseInstanceState(serverState string) types.InstanceState {
    85  	// http://docs.openstack.org/developer/nova/vmstates.html#vm-states-and-possible-commands
    86  	switch strings.ToLower(serverState) {
    87  	case "active", "rescued":
    88  		return types.InstanceState_Running
    89  	case "building":
    90  		return types.InstanceState_Pending
    91  	case "paused":
    92  		return types.InstanceState_Paused
    93  	case "suspended":
    94  		return types.InstanceState_Suspended
    95  	case "shutoff", "stopped", "soft_deleted":
    96  		return types.InstanceState_Stopped
    97  	case "hard_deleted":
    98  		return types.InstanceState_Terminated
    99  	case "error":
   100  		return types.InstanceState_Error
   101  	}
   102  
   103  	logrus.WithFields(logrus.Fields{
   104  		"serverState": serverState,
   105  	}).Infof("Received unknown instance state")
   106  
   107  	return types.InstanceState_Unknown
   108  }