github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/aagent/machine/info.go (about)

     1  // Copyright (c) 2019-2022, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package machine
     6  
     7  import (
     8  	"crypto/md5"
     9  	"fmt"
    10  	"io"
    11  	"math/rand"
    12  	"os"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/gofrs/uuid"
    17  )
    18  
    19  // WatcherState is the status of a given watcher, boolean result is false for unknown watchers
    20  func (m *Machine) WatcherState(watcher string) (any, bool) {
    21  	return m.manager.WatcherState(watcher)
    22  }
    23  
    24  // InstanceID is a unique id for the instance of a machine
    25  func (m *Machine) InstanceID() string {
    26  	return m.instanceID
    27  }
    28  
    29  // Directory returns the directory where the machine definition is, "" when unknown
    30  func (m *Machine) Directory() string {
    31  	return m.directory
    32  }
    33  
    34  // StartTime is the time the machine started in UTC
    35  func (m *Machine) StartTime() time.Time {
    36  	return m.startTime
    37  }
    38  
    39  // Identity implements InfoSource
    40  func (m *Machine) Identity() string {
    41  	if m.identity == "" {
    42  		return "unknown"
    43  	}
    44  
    45  	return m.identity
    46  }
    47  
    48  // Version implements InfoSource
    49  func (m *Machine) Version() string {
    50  	return m.MachineVersion
    51  }
    52  
    53  // Name implements InfoSource
    54  func (m *Machine) Name() string {
    55  	return m.MachineName
    56  }
    57  
    58  // State implements InfoSource
    59  func (m *Machine) State() string {
    60  	return m.fsm.Current()
    61  }
    62  
    63  // AvailableTransitions reports the transitions thats possible in the current state
    64  func (m *Machine) AvailableTransitions() []string {
    65  	return m.fsm.AvailableTransitions()
    66  }
    67  
    68  // TimeStamp returns a UTC time
    69  func (m *Machine) TimeStamp() time.Time {
    70  	return time.Now().UTC()
    71  }
    72  
    73  // TimeStampSeconds returns the current time in unix seconds
    74  func (m *Machine) TimeStampSeconds() int64 {
    75  	return m.TimeStamp().Unix()
    76  }
    77  
    78  // UniqueID creates a new unique ID, usually a v4 uuid, if that fails a random string based ID is made
    79  func (m *Machine) UniqueID() (id string) {
    80  	uuid, err := uuid.NewV4()
    81  	if err == nil {
    82  		return uuid.String()
    83  	}
    84  
    85  	parts := []string{}
    86  	parts = append(parts, randStringRunes(8))
    87  	parts = append(parts, randStringRunes(4))
    88  	parts = append(parts, randStringRunes(4))
    89  	parts = append(parts, randStringRunes(12))
    90  
    91  	return strings.Join(parts, "-")
    92  }
    93  
    94  // Hash computes a md5 hash of the manifest
    95  func (m *Machine) Hash() (string, error) {
    96  	return filemd5(m.manifest)
    97  }
    98  
    99  func randStringRunes(n int) string {
   100  	letterRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
   101  
   102  	b := make([]rune, n)
   103  	for i := range b {
   104  		b[i] = letterRunes[rand.Intn(len(letterRunes))]
   105  	}
   106  	return string(b)
   107  }
   108  
   109  func filemd5(path string) (string, error) {
   110  	f, err := os.Open(path)
   111  	if err != nil {
   112  		return "", fmt.Errorf("could not open data for md5 hash: %s", err)
   113  	}
   114  	defer f.Close()
   115  
   116  	h := md5.New()
   117  	if _, err := io.Copy(h, f); err != nil {
   118  		return "", fmt.Errorf("could not copy data to md5: %s", err)
   119  	}
   120  
   121  	return fmt.Sprintf("%x", h.Sum(nil)), nil
   122  }