github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/uniter/hook/hook.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package hook 5 6 import ( 7 "github.com/juju/charm/v12/hooks" 8 "github.com/juju/errors" 9 "github.com/juju/names/v5" 10 11 "github.com/juju/juju/core/secrets" 12 ) 13 14 // Info holds details required to execute a hook. Not all fields are 15 // relevant to all Kind values. 16 type Info struct { 17 Kind hooks.Kind `yaml:"kind"` 18 19 // RelationId identifies the relation associated with the hook. 20 // It is only set when Kind indicates a relation hook. 21 RelationId int `yaml:"relation-id,omitempty"` 22 23 // RemoteUnit is the name of the unit that triggered the hook. 24 // It is only set when Kind indicates a relation hook other than 25 // relation-created or relation-broken. 26 RemoteUnit string `yaml:"remote-unit,omitempty"` 27 28 // RemoteApplication is always set if either an app or a unit triggers 29 // the hook. If the app triggers the hook, then RemoteUnit will be empty. 30 RemoteApplication string `yaml:"remote-application,omitempty"` 31 32 // ChangeVersion identifies the most recent unit settings change 33 // associated with RemoteUnit. It is only set when RemoteUnit is set. 34 ChangeVersion int64 `yaml:"change-version,omitempty"` 35 36 // StorageId is the ID of the storage instance relevant to the hook. 37 StorageId string `yaml:"storage-id,omitempty"` 38 39 // DepartingUnit is the name of the unit that goes away. It is only set 40 // when Kind indicates a relation-departed hook. 41 DepartingUnit string `yaml:"departee,omitempty"` 42 43 // WorkloadName is the name of the sidecar container or workload relevant to the hook. 44 WorkloadName string `yaml:"workload-name,omitempty"` 45 46 // NoticeID is the Pebble notice ID associated with the hook. 47 NoticeID string `yaml:"notice-id,omitempty"` 48 49 // NoticeType is the Pebble notice type associated with the hook. 50 NoticeType string `yaml:"notice-type,omitempty"` 51 52 // NoticeKey is the Pebble notice key associated with the hook. 53 NoticeKey string `yaml:"notice-key,omitempty"` 54 55 // MachineUpgradeTarget is the base that the unit's machine is to be 56 // updated to when Juju is issued the `upgrade-machine` command. 57 // It is only set for the pre-series-upgrade hook. 58 MachineUpgradeTarget string `yaml:"series-upgrade-target,omitempty"` 59 60 // SecretURI is the secret URI relevant to the hook. 61 SecretURI string `yaml:"secret-uri,omitempty"` 62 63 // SecretRevision is the secret revision relevant to the hook. 64 SecretRevision int `yaml:"secret-revision,omitempty"` 65 66 // SecretLabel is the secret label to expose to the hook. 67 SecretLabel string `yaml:"secret-label,omitempty"` 68 } 69 70 // SecretHookRequiresRevision returns true if the hook context needs a secret revision. 71 func SecretHookRequiresRevision(kind hooks.Kind) bool { 72 return kind == hooks.SecretRemove || kind == hooks.SecretExpired 73 } 74 75 // Validate returns an error if the info is not valid. 76 func (hi Info) Validate() error { 77 switch hi.Kind { 78 case hooks.RelationChanged: 79 if hi.RemoteUnit == "" { 80 if hi.RemoteApplication == "" { 81 return errors.Errorf("%q hook requires a remote unit or application", hi.Kind) 82 } 83 } else if hi.RemoteApplication == "" { 84 return errors.Errorf("%q hook has a remote unit but no application", hi.Kind) 85 } 86 return nil 87 case hooks.RelationJoined, hooks.RelationDeparted: 88 if hi.RemoteUnit == "" { 89 return errors.Errorf("%q hook requires a remote unit", hi.Kind) 90 } 91 if hi.RemoteApplication == "" { 92 return errors.Errorf("%q hook has a remote unit but no application", hi.Kind) 93 } 94 return nil 95 case hooks.PebbleCustomNotice: 96 if hi.WorkloadName == "" { 97 return errors.Errorf("%q hook requires a workload name", hi.Kind) 98 } 99 if hi.NoticeID == "" || hi.NoticeType == "" || hi.NoticeKey == "" { 100 return errors.Errorf("%q hook requires a notice ID, type, and key", hi.Kind) 101 } 102 return nil 103 case hooks.PebbleReady: 104 if hi.WorkloadName == "" { 105 return errors.Errorf("%q hook requires a workload name", hi.Kind) 106 } 107 return nil 108 case hooks.PreSeriesUpgrade: 109 if hi.MachineUpgradeTarget == "" { 110 return errors.Errorf("%q hook requires a target base", hi.Kind) 111 } 112 return nil 113 case hooks.Install, hooks.Remove, hooks.Start, hooks.ConfigChanged, hooks.UpgradeCharm, hooks.Stop, 114 hooks.RelationCreated, hooks.RelationBroken, hooks.CollectMetrics, hooks.MeterStatusChanged, hooks.UpdateStatus, 115 hooks.PostSeriesUpgrade: 116 return nil 117 case hooks.Action: 118 return errors.Errorf("hooks.Kind Action is deprecated") 119 case hooks.StorageAttached, hooks.StorageDetaching: 120 if !names.IsValidStorage(hi.StorageId) { 121 return errors.Errorf("invalid storage ID %q", hi.StorageId) 122 } 123 return nil 124 case hooks.LeaderElected, hooks.LeaderDeposed, hooks.LeaderSettingsChanged: 125 return nil 126 case hooks.SecretRotate, hooks.SecretChanged, hooks.SecretExpired, hooks.SecretRemove: 127 if hi.SecretURI == "" { 128 return errors.Errorf("%q hook requires a secret URI", hi.Kind) 129 } 130 if _, err := secrets.ParseURI(hi.SecretURI); err != nil { 131 return errors.Errorf("invalid secret URI %q", hi.SecretURI) 132 } 133 if SecretHookRequiresRevision(hi.Kind) && hi.SecretRevision <= 0 { 134 return errors.Errorf("%q hook requires a secret revision", hi.Kind) 135 } 136 return nil 137 } 138 return errors.Errorf("unknown hook kind %q", hi.Kind) 139 } 140 141 // Committer is an interface that may be used to convey the fact that the 142 // specified hook has been successfully executed, and committed. 143 type Committer interface { 144 CommitHook(Info) error 145 } 146 147 // Validator is an interface that may be used to validate a hook execution 148 // request prior to executing it. 149 type Validator interface { 150 ValidateHook(Info) error 151 }