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 }