github.com/Axway/agent-sdk@v1.1.101/pkg/config/usagereportingconfig.go (about) 1 package config 2 3 import ( 4 "os" 5 "strconv" 6 "strings" 7 "time" 8 9 "github.com/Axway/agent-sdk/pkg/cmd/properties" 10 "github.com/Axway/agent-sdk/pkg/util/exception" 11 "github.com/Axway/agent-sdk/pkg/util/log" 12 "github.com/gorhill/cronexpr" 13 ) 14 15 const ( 16 // DEPRECATE remove old and new env vars as well as checks below 17 oldUsageReportingPublishEnvVar = "CENTRAL_PUBLISHUSAGE" 18 newUsageReportingPublishEnvVar = "CENTRAL_USAGEREPORTING_PUBLISH" 19 oldUsageReportingScheduleEnvVar = "CENTRAL_USAGEREPORTING_USAGESCHEDULE" 20 newUsageReportingScheduleEnvVar = "CENTRAL_USAGEREPORTING_SCHEDULE" 21 22 // QA EnvVars 23 qaUsageReportingScheduleEnvVar = "QA_CENTRAL_USAGEREPORTING_OFFLINESCHEDULE" 24 qaUsageReportingOfflineScheduleEnvVar = "QA_CENTRAL_USAGEREPORTING_OFFLINEREPORTSCHEDULE" 25 qaUsageReportingUsageScheduleEnvVar = "QA_CENTRAL_USAGEREPORTING_SCHEDULE" 26 27 // Config paths 28 pathUsageReportingPublish = "central.usagereporting.publish" 29 pathUsageReportingSchedule = "central.usagereporting.schedule" 30 pathUsageReportingOffline = "central.usagereporting.offline" 31 pathUsageReportingOfflineSchedule = "central.usagereporting.offlineSchedule" 32 ) 33 34 // UsageReportingConfig - Interface to get usage reporting config 35 type UsageReportingConfig interface { 36 GetURL() string 37 CanPublish() bool 38 GetReportInterval() time.Duration 39 GetSchedule() string 40 IsOfflineMode() bool 41 GetOfflineSchedule() string 42 GetReportSchedule() string 43 GetReportGranularity() int 44 UsingQAVars() bool 45 Validate() 46 } 47 48 // UsageReportingConfiguration - structure to hold all usage reporting settings 49 type UsageReportingConfiguration struct { 50 UsageReportingConfig 51 Publish bool `config:"publish"` 52 Schedule string `config:"schedule"` 53 Offline bool `config:"offline"` 54 OfflineSchedule string `config:"offlineSchedule"` 55 URL string 56 reportSchedule string 57 reportGranularity int 58 qaVars bool 59 } 60 61 // NewUsageReporting - Creates the default usage reporting config 62 func NewUsageReporting(platformURL string) UsageReportingConfig { 63 return &UsageReportingConfiguration{ 64 URL: platformURL, 65 Publish: true, 66 Schedule: "@daily", 67 Offline: false, 68 OfflineSchedule: "@hourly", 69 reportSchedule: "@monthly", 70 qaVars: false, 71 } 72 } 73 74 func (u *UsageReportingConfiguration) validatePublish() { 75 if val := os.Getenv(newUsageReportingPublishEnvVar); val != "" { 76 return // this env var is set use what has been parsed 77 } 78 79 // check if the old env var had a value 80 val := os.Getenv(oldUsageReportingPublishEnvVar) 81 if val != "" { 82 if value, err := strconv.ParseBool(val); err == nil { 83 log.DeprecationWarningReplace(oldUsageReportingPublishEnvVar, newUsageReportingPublishEnvVar) 84 u.Publish = value 85 } 86 } 87 } 88 89 // Validate - 90 func (u *UsageReportingConfiguration) Validate() { 91 u.validatePublish() 92 93 if !u.Offline { 94 u.validateUsageSchedule() 95 } else { 96 u.validateOffline() 97 } 98 } 99 100 func (u *UsageReportingConfiguration) validateUsageSchedule() { 101 // check if the qa env var is set 102 if val := os.Getenv(qaUsageReportingUsageScheduleEnvVar); val != "" { 103 if _, err := cronexpr.Parse(val); err != nil { 104 log.Tracef("Could not use %s (%s) it is not a proper cron schedule", qaUsageReportingUsageScheduleEnvVar, val) 105 } else { 106 log.Tracef("Using %s (%s) rather than the default (%s) for non-QA", qaUsageReportingUsageScheduleEnvVar, val, u.Schedule) 107 u.Schedule = val 108 u.qaVars = true 109 } 110 return 111 } 112 113 if val := os.Getenv(newUsageReportingScheduleEnvVar); val == "" { 114 if val = os.Getenv(oldUsageReportingScheduleEnvVar); val != "" { 115 log.DeprecationWarningReplace(oldUsageReportingScheduleEnvVar, newUsageReportingScheduleEnvVar) 116 u.Schedule = val 117 } 118 } 119 120 // Check the cron expressions 121 cron, err := cronexpr.Parse(u.Schedule) 122 if err != nil { 123 exception.Throw(ErrBadConfig.FormatError(pathUsageReportingSchedule)) 124 } 125 checks := 5 126 nextRuns := cron.NextN(time.Now(), uint(checks)) 127 if len(nextRuns) != checks { 128 exception.Throw(ErrBadConfig.FormatError(pathUsageReportingSchedule)) 129 } 130 for i := 1; i < checks-1; i++ { 131 delta := nextRuns[i].Sub(nextRuns[i-1]) 132 if delta < time.Hour { 133 log.Tracef("%s must be at 1 hour apart", pathUsageReportingSchedule) 134 exception.Throw(ErrBadConfig.FormatError(pathUsageReportingSchedule)) 135 } 136 } 137 } 138 139 func (u *UsageReportingConfiguration) validateOffline() { 140 if _, err := cronexpr.Parse(u.OfflineSchedule); err != nil { 141 exception.Throw(ErrBadConfig.FormatError(pathUsageReportingOfflineSchedule)) 142 } 143 144 // reporting is offline, lets read the QA env vars 145 if val := os.Getenv(qaUsageReportingScheduleEnvVar); val != "" { 146 if _, err := cronexpr.Parse(val); err != nil { 147 log.Tracef("Could not use %s (%s) it is not a proper cron schedule", qaUsageReportingScheduleEnvVar, val) 148 } else { 149 log.Tracef("Using %s (%s) rather than the default (%s) for non-QA", qaUsageReportingScheduleEnvVar, val, u.OfflineSchedule) 150 u.OfflineSchedule = val 151 u.qaVars = true 152 } 153 } 154 155 if val := os.Getenv(qaUsageReportingOfflineScheduleEnvVar); val != "" { 156 if _, err := cronexpr.Parse(val); err != nil { 157 log.Tracef("Could not use %s (%s) it is not a proper cron schedule", qaUsageReportingOfflineScheduleEnvVar, val) 158 } else { 159 log.Tracef("Using %s (%s) rather than the default (%s) for non-QA", qaUsageReportingOfflineScheduleEnvVar, val, u.reportSchedule) 160 u.reportSchedule = val 161 u.qaVars = true 162 } 163 } 164 165 // Check the cron expressions 166 cron, err := cronexpr.Parse(u.OfflineSchedule) 167 if err != nil { 168 exception.Throw(ErrBadConfig.FormatError(pathUsageReportingOfflineSchedule)) 169 } 170 nextTwoRuns := cron.NextN(time.Now(), 2) 171 if len(nextTwoRuns) != 2 { 172 exception.Throw(ErrBadConfig.FormatError(pathUsageReportingOfflineSchedule)) 173 } 174 u.reportGranularity = int(nextTwoRuns[1].Sub(nextTwoRuns[0]).Milliseconds()) 175 176 // if no QA env vars are set then validate the schedule is at least hourly 177 if nextTwoRuns[1].Sub(nextTwoRuns[0]) < time.Hour && !u.qaVars { 178 exception.Throw(ErrBadConfig.FormatError(pathUsageReportingOfflineSchedule)) 179 } 180 } 181 182 // GetURL - Returns the usage reporting URL 183 func (u *UsageReportingConfiguration) GetURL() string { 184 return u.URL 185 } 186 187 // CanPublish - Returns the publish boolean 188 func (u *UsageReportingConfiguration) CanPublish() bool { 189 return u.Publish 190 } 191 192 // IsOfflineMode - Returns the offline boolean 193 func (u *UsageReportingConfiguration) IsOfflineMode() bool { 194 return u.Offline 195 } 196 197 // GetSchedule - Returns the schedule string 198 func (u *UsageReportingConfiguration) GetOfflineSchedule() string { 199 return u.OfflineSchedule 200 } 201 202 // GetSchedule - Returns the schedule string for publishing reports 203 func (u *UsageReportingConfiguration) GetSchedule() string { 204 return u.Schedule 205 } 206 207 // GetReportSchedule - Returns the offline schedule string for creating reports 208 func (u *UsageReportingConfiguration) GetReportSchedule() string { 209 return u.reportSchedule 210 } 211 212 // GetReportGranularity - Returns the granularity used in the offline reports 213 func (u *UsageReportingConfiguration) GetReportGranularity() int { 214 return u.reportGranularity 215 } 216 217 // UsingQAVars - Returns the offline boolean 218 func (u *UsageReportingConfiguration) UsingQAVars() bool { 219 return u.qaVars 220 } 221 222 // AddUsageReportingProperties - Adds the command properties needed for Usage Reporting Settings 223 func AddUsageReportingProperties(props properties.Properties) { 224 props.AddBoolProperty(pathUsageReportingPublish, true, "Indicates if the agent can publish usage events to Amplify platform. Default to true") 225 props.AddStringProperty(pathUsageReportingSchedule, "@daily", "The schedule at usage events are sent to the platform") 226 props.AddBoolProperty(pathUsageReportingOffline, false, "Turn this on to save the usage events to disk for manual upload") 227 props.AddStringProperty(pathUsageReportingOfflineSchedule, "@hourly", "The schedule at which usage events are generated, for offline mode only") 228 } 229 230 // ParseUsageReportingConfig - Parses the Usage Reporting Config values from the command line 231 func ParseUsageReportingConfig(props properties.Properties) UsageReportingConfig { 232 // Start with the default config 233 platformURL := strings.TrimRight(props.StringPropertyValue(pathPlatformURL), urlCutSet) 234 cfg := NewUsageReporting(platformURL).(*UsageReportingConfiguration) 235 236 // update the config 237 cfg.Publish = props.BoolPropertyValue(pathUsageReportingPublish) 238 cfg.Schedule = props.StringPropertyValue(pathUsageReportingSchedule) 239 cfg.Offline = props.BoolPropertyValue(pathUsageReportingOffline) 240 cfg.OfflineSchedule = props.StringPropertyValue(pathUsageReportingOfflineSchedule) 241 242 return cfg 243 }