tracks.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. package analytics
  2. import (
  3. "github.com/porter-dev/porter/api/types"
  4. segment "gopkg.in/segmentio/analytics-go.v3"
  5. )
  6. type segmentTrack interface {
  7. getUserId() string
  8. getEvent() SegmentEvent
  9. getProperties() segment.Properties
  10. }
  11. type defaultTrackOpts struct {
  12. AdditionalProps map[string]interface{}
  13. }
  14. type defaultSegmentTrack struct {
  15. event SegmentEvent
  16. properties segmentProperties
  17. }
  18. func getDefaultSegmentTrack(additionalProps map[string]interface{}, event SegmentEvent) *defaultSegmentTrack {
  19. props := newSegmentProperties()
  20. props.addAdditionalProperties(additionalProps)
  21. return &defaultSegmentTrack{
  22. event: event,
  23. properties: props,
  24. }
  25. }
  26. func (t *defaultSegmentTrack) getEvent() SegmentEvent {
  27. return t.event
  28. }
  29. func (t *defaultSegmentTrack) getProperties() segment.Properties {
  30. props := segment.NewProperties()
  31. for key, val := range t.properties {
  32. props = props.Set(key, val)
  33. }
  34. return props
  35. }
  36. type segmentProperties map[string]interface{}
  37. func newSegmentProperties() segmentProperties {
  38. props := make(map[string]interface{})
  39. return props
  40. }
  41. func (p segmentProperties) addProjectProperties(opts *ProjectScopedTrackOpts) {
  42. p["proj_id"] = opts.ProjectID
  43. }
  44. func (p segmentProperties) addClusterProperties(opts *ClusterScopedTrackOpts) {
  45. p["cluster_id"] = opts.ClusterID
  46. }
  47. func (p segmentProperties) addRegistryProperties(opts *RegistryScopedTrackOpts) {
  48. p["registry_id"] = opts.RegistryID
  49. }
  50. func (p segmentProperties) addApplicationProperties(opts *ApplicationScopedTrackOpts) {
  51. p["app_name"] = opts.Name
  52. p["app_namespace"] = opts.Namespace
  53. p["chart_name"] = opts.ChartName
  54. }
  55. func (p segmentProperties) addAdditionalProperties(props map[string]interface{}) {
  56. for key, val := range props {
  57. p[key] = val
  58. }
  59. }
  60. // UserCreateTrackOpts are the options for creating a track when a user is created
  61. type UserCreateTrackOpts struct {
  62. *UserScopedTrackOpts
  63. Email string
  64. FirstName string
  65. LastName string
  66. CompanyName string
  67. }
  68. // UserCreateTrack returns a track for when a user is created
  69. func UserCreateTrack(opts *UserCreateTrackOpts) segmentTrack {
  70. additionalProps := make(map[string]interface{})
  71. additionalProps["email"] = opts.Email
  72. additionalProps["name"] = opts.FirstName + " " + opts.LastName
  73. additionalProps["company"] = opts.CompanyName
  74. return getSegmentUserTrack(
  75. opts.UserScopedTrackOpts,
  76. getDefaultSegmentTrack(additionalProps, UserCreate),
  77. )
  78. }
  79. // UserCreateTrackOpts are the options for creating a track when a user's email is verified
  80. type UserVerifyEmailTrackOpts struct {
  81. *UserScopedTrackOpts
  82. Email string
  83. }
  84. // UserVerifyEmailTrack returns a track for when a user's email is verified
  85. func UserVerifyEmailTrack(opts *UserVerifyEmailTrackOpts) segmentTrack {
  86. additionalProps := make(map[string]interface{})
  87. additionalProps["email"] = opts.Email
  88. return getSegmentUserTrack(
  89. opts.UserScopedTrackOpts,
  90. getDefaultSegmentTrack(additionalProps, UserVerifyEmail),
  91. )
  92. }
  93. // ProjectCreateTrackOpts are the options for creating a track when a project is created
  94. type ProjectCreateTrackOpts struct {
  95. *ProjectScopedTrackOpts
  96. }
  97. // ProjectCreateTrack returns a track for when a project is created
  98. func ProjectCreateTrack(opts *ProjectCreateTrackOpts) segmentTrack {
  99. additionalProps := make(map[string]interface{})
  100. return getSegmentProjectTrack(
  101. opts.ProjectScopedTrackOpts,
  102. getDefaultSegmentTrack(additionalProps, ProjectCreate),
  103. )
  104. }
  105. // CostConsentTrackOpts are the options for creating a track when a user completes the cost consent
  106. type CostConsentTrackOpts struct {
  107. *UserScopedTrackOpts
  108. }
  109. // CostConsentTrack returns a track for when a user completes the cost consent
  110. func CostConsentTrack(opts *CostConsentTrackOpts) segmentTrack {
  111. additionalProps := make(map[string]interface{})
  112. return getSegmentUserTrack(
  113. opts.UserScopedTrackOpts,
  114. getDefaultSegmentTrack(additionalProps, CostConsentComplete),
  115. )
  116. }
  117. // CredentialStepTrackOpts are the options for creating a track when a user completes the credential step
  118. type CredentialStepTrackOpts struct {
  119. *UserScopedTrackOpts
  120. }
  121. // CredentialStepTrack returns a track for when a user completes the credential step
  122. func CredentialStepTrack(opts *CredentialStepTrackOpts) segmentTrack {
  123. additionalProps := make(map[string]interface{})
  124. return getSegmentUserTrack(
  125. opts.UserScopedTrackOpts,
  126. getDefaultSegmentTrack(additionalProps, CredentialStepComplete),
  127. )
  128. }
  129. // ProvisioningAttemptedTrackOpts are the options for creating a track when a user attempts provisioning
  130. type ProvisioningAttemptTrackOpts struct {
  131. *UserScopedTrackOpts
  132. }
  133. // ProvisioningAttemptTrack returns a track for when a user attempts provisioning
  134. func ProvisioningAttemptTrack(opts *ProvisioningAttemptTrackOpts) segmentTrack {
  135. additionalProps := make(map[string]interface{})
  136. return getSegmentUserTrack(
  137. opts.UserScopedTrackOpts,
  138. getDefaultSegmentTrack(additionalProps, ProvisioningAttempted),
  139. )
  140. }
  141. // ClusterProvisioningStartTrackOpts are the options for creating a track when a cluster
  142. // has started provisioning
  143. type ClusterProvisioningStartTrackOpts struct {
  144. // note that this is a project-scoped track, since the cluster has not been created yet
  145. *ProjectScopedTrackOpts
  146. ClusterType types.InfraKind
  147. InfraID uint
  148. }
  149. // ClusterProvisioningStartTrack returns a track for when a cluster
  150. // has started provisioning
  151. func ClusterProvisioningStartTrack(opts *ClusterProvisioningStartTrackOpts) segmentTrack {
  152. additionalProps := make(map[string]interface{})
  153. additionalProps["cluster_type"] = opts.ClusterType
  154. additionalProps["infra_id"] = opts.InfraID
  155. return getSegmentProjectTrack(
  156. opts.ProjectScopedTrackOpts,
  157. getDefaultSegmentTrack(additionalProps, ClusterProvisioningStart),
  158. )
  159. }
  160. // ClusterProvisioningErrorTrackOpts are the options for creating a track when a cluster
  161. // has experienced a provisioning error
  162. type ClusterProvisioningErrorTrackOpts struct {
  163. // note that this is a project-scoped track, since the cluster has not been created yet
  164. *ProjectScopedTrackOpts
  165. ClusterType types.InfraKind
  166. InfraID uint
  167. }
  168. // ClusterProvisioningErrorTrack returns a track for when a cluster
  169. // has experienced a provisioning error
  170. func ClusterProvisioningErrorTrack(opts *ClusterProvisioningErrorTrackOpts) segmentTrack {
  171. additionalProps := make(map[string]interface{})
  172. additionalProps["cluster_type"] = opts.ClusterType
  173. additionalProps["infra_id"] = opts.InfraID
  174. return getSegmentProjectTrack(
  175. opts.ProjectScopedTrackOpts,
  176. getDefaultSegmentTrack(additionalProps, ClusterProvisioningError),
  177. )
  178. }
  179. // ClusterProvisioningSuccessTrackOpts are the options for creating a track when a cluster
  180. // has successfully provisioned
  181. type ClusterProvisioningSuccessTrackOpts struct {
  182. *ClusterScopedTrackOpts
  183. ClusterType types.InfraKind
  184. InfraID uint
  185. }
  186. // ClusterProvisioningSuccessTrack returns a new track for when a cluster
  187. // has successfully provisioned
  188. func ClusterProvisioningSuccessTrack(opts *ClusterProvisioningSuccessTrackOpts) segmentTrack {
  189. additionalProps := make(map[string]interface{})
  190. additionalProps["cluster_type"] = opts.ClusterType
  191. additionalProps["infra_id"] = opts.InfraID
  192. return getSegmentClusterTrack(
  193. opts.ClusterScopedTrackOpts,
  194. getDefaultSegmentTrack(additionalProps, ClusterProvisioningSuccess),
  195. )
  196. }
  197. // ClusterConnectionStartTrackOpts are the options for creating a track when a cluster
  198. // connection has started
  199. type ClusterConnectionStartTrackOpts struct {
  200. // note that this is a project-scoped track, since the cluster has not been created yet
  201. *ProjectScopedTrackOpts
  202. ClusterCandidateID uint
  203. }
  204. // ClusterConnectionStartTrack returns a new track for when a cluster
  205. // connection has started
  206. func ClusterConnectionStartTrack(opts *ClusterConnectionStartTrackOpts) segmentTrack {
  207. additionalProps := make(map[string]interface{})
  208. additionalProps["cc_id"] = opts.ClusterCandidateID
  209. return getSegmentProjectTrack(
  210. opts.ProjectScopedTrackOpts,
  211. getDefaultSegmentTrack(additionalProps, ClusterConnectionStart),
  212. )
  213. }
  214. // ClusterConnectionSuccessTrackOpts are the options for creating a track when a cluster
  215. // connection has finished
  216. type ClusterConnectionSuccessTrackOpts struct {
  217. *ClusterScopedTrackOpts
  218. ClusterCandidateID uint
  219. }
  220. // ClusterConnectionSuccessTrack returns a new track for when a cluster
  221. // connection has finished
  222. func ClusterConnectionSuccessTrack(opts *ClusterConnectionSuccessTrackOpts) segmentTrack {
  223. additionalProps := make(map[string]interface{})
  224. additionalProps["cc_id"] = opts.ClusterCandidateID
  225. return getSegmentClusterTrack(
  226. opts.ClusterScopedTrackOpts,
  227. getDefaultSegmentTrack(additionalProps, ClusterConnectionSuccess),
  228. )
  229. }
  230. // RegistryConnectionStartTrackOpts are the options for creating a track when a registry
  231. // connection has started
  232. type RegistryConnectionStartTrackOpts struct {
  233. // note that this is a project-scoped track, since the cluster has not been created yet
  234. *ProjectScopedTrackOpts
  235. // a random id assigned to this connection request
  236. FlowID string
  237. }
  238. // RegistryConnectionStartTrack returns a new track for when a registry
  239. // connection has started
  240. func RegistryConnectionStartTrack(opts *RegistryConnectionStartTrackOpts) segmentTrack {
  241. additionalProps := make(map[string]interface{})
  242. additionalProps["flow_id"] = opts.FlowID
  243. return getSegmentProjectTrack(
  244. opts.ProjectScopedTrackOpts,
  245. getDefaultSegmentTrack(additionalProps, RegistryConnectionStart),
  246. )
  247. }
  248. // RegistryConnectionSuccessTrackOpts are the options for creating a track when a registry
  249. // connection has completed
  250. type RegistryConnectionSuccessTrackOpts struct {
  251. *RegistryScopedTrackOpts
  252. // a random id assigned to this connection request
  253. FlowID string
  254. }
  255. // RegistryConnectionSuccessTrack returns a new track for when a registry
  256. // connection has completed
  257. func RegistryConnectionSuccessTrack(opts *RegistryConnectionSuccessTrackOpts) segmentTrack {
  258. additionalProps := make(map[string]interface{})
  259. additionalProps["flow_id"] = opts.FlowID
  260. return getSegmentRegistryTrack(
  261. opts.RegistryScopedTrackOpts,
  262. getDefaultSegmentTrack(additionalProps, RegistryConnectionSuccess),
  263. )
  264. }
  265. // GithubConnectionStartTrackOpts are the options for creating a track when a github account
  266. // connection has started
  267. type GithubConnectionStartTrackOpts struct {
  268. // note that this is a user-scoped track, since github repos are tied to the user
  269. *UserScopedTrackOpts
  270. }
  271. // GithubConnectionStartTrack returns a new track for when a github account
  272. // connection has started
  273. func GithubConnectionStartTrack(opts *GithubConnectionStartTrackOpts) segmentTrack {
  274. additionalProps := make(map[string]interface{})
  275. return getSegmentUserTrack(
  276. opts.UserScopedTrackOpts,
  277. getDefaultSegmentTrack(additionalProps, GithubConnectionStart),
  278. )
  279. }
  280. // GithubConnectionSuccessTrackOpts are the options for creating a track when a github account
  281. // connection has completed
  282. type GithubConnectionSuccessTrackOpts struct {
  283. // note that this is a user-scoped track, since github repos are tied to the user
  284. *UserScopedTrackOpts
  285. }
  286. // GithubConnectionSuccessTrack returns a new track when a github account
  287. // connection has completed
  288. func GithubConnectionSuccessTrack(opts *GithubConnectionSuccessTrackOpts) segmentTrack {
  289. additionalProps := make(map[string]interface{})
  290. return getSegmentUserTrack(
  291. opts.UserScopedTrackOpts,
  292. getDefaultSegmentTrack(additionalProps, GithubConnectionSuccess),
  293. )
  294. }
  295. // ApplicationLaunchStartTrackOpts are the options for creating a track when an application
  296. // launch has started
  297. type ApplicationLaunchStartTrackOpts struct {
  298. *ClusterScopedTrackOpts
  299. FlowID string
  300. }
  301. // ApplicationLaunchStartTrack returns a new track for when an application
  302. // launch has started
  303. func ApplicationLaunchStartTrack(opts *ApplicationLaunchStartTrackOpts) segmentTrack {
  304. additionalProps := make(map[string]interface{})
  305. additionalProps["flow_id"] = opts.FlowID
  306. return getSegmentClusterTrack(
  307. opts.ClusterScopedTrackOpts,
  308. getDefaultSegmentTrack(additionalProps, ApplicationLaunchStart),
  309. )
  310. }
  311. // ApplicationLaunchSuccessTrackOpts are the options for creating a track when an application
  312. // launch has completed
  313. type ApplicationLaunchSuccessTrackOpts struct {
  314. *ApplicationScopedTrackOpts
  315. FlowID string
  316. }
  317. // ApplicationLaunchSuccessTrack returns a new track for when an application
  318. // launch has completed
  319. func ApplicationLaunchSuccessTrack(opts *ApplicationLaunchSuccessTrackOpts) segmentTrack {
  320. additionalProps := make(map[string]interface{})
  321. additionalProps["flow_id"] = opts.FlowID
  322. return getSegmentApplicationTrack(
  323. opts.ApplicationScopedTrackOpts,
  324. getDefaultSegmentTrack(additionalProps, ApplicationLaunchSuccess),
  325. )
  326. }
  327. // ApplicationDeploymentWebhookTrackOpts are the options for creating a track when an application
  328. // launch has completed from a webhook
  329. type ApplicationDeploymentWebhookTrackOpts struct {
  330. *ApplicationScopedTrackOpts
  331. ImageURI string
  332. }
  333. // ApplicationDeploymentWebhookTrack returns a new track for when an application
  334. // launch has completed from a webhook
  335. func ApplicationDeploymentWebhookTrack(opts *ApplicationDeploymentWebhookTrackOpts) segmentTrack {
  336. additionalProps := make(map[string]interface{})
  337. additionalProps["image_uri"] = opts.ImageURI
  338. return getSegmentApplicationTrack(
  339. opts.ApplicationScopedTrackOpts,
  340. getDefaultSegmentTrack(additionalProps, ApplicationDeploymentWebhook),
  341. )
  342. }
  343. // RegistryProvisioningStartTrackOpts are the options for creating a track when a registry
  344. // provisioning has started
  345. type RegistryProvisioningStartTrackOpts struct {
  346. // note that this is a project-scoped track, since the registry has not been created yet
  347. *ProjectScopedTrackOpts
  348. RegistryType types.InfraKind
  349. InfraID uint
  350. }
  351. // RegistryProvisioningStartTrack returns a new track for when a registry
  352. // provisioning has started
  353. func RegistryProvisioningStartTrack(opts *RegistryProvisioningStartTrackOpts) segmentTrack {
  354. additionalProps := make(map[string]interface{})
  355. additionalProps["registry_type"] = opts.RegistryType
  356. additionalProps["infra_id"] = opts.InfraID
  357. return getSegmentProjectTrack(
  358. opts.ProjectScopedTrackOpts,
  359. getDefaultSegmentTrack(additionalProps, RegistryProvisioningStart),
  360. )
  361. }
  362. // RegistryProvisioningErrorTrackOpts are the options for creating a track when a registry
  363. // provisioning has failed
  364. type RegistryProvisioningErrorTrackOpts struct {
  365. // note that this is a project-scoped track, since the registry has not been created yet
  366. *ProjectScopedTrackOpts
  367. RegistryType types.InfraKind
  368. InfraID uint
  369. }
  370. // RegistryProvisioningErrorTrack returns a new track for when a registry
  371. // provisioning has failed
  372. func RegistryProvisioningErrorTrack(opts *RegistryProvisioningErrorTrackOpts) segmentTrack {
  373. additionalProps := make(map[string]interface{})
  374. additionalProps["registry_type"] = opts.RegistryType
  375. additionalProps["infra_id"] = opts.InfraID
  376. return getSegmentProjectTrack(
  377. opts.ProjectScopedTrackOpts,
  378. getDefaultSegmentTrack(additionalProps, RegistryProvisioningError),
  379. )
  380. }
  381. // RegistryProvisioningSuccessTrackOpts are the options for creating a track when a registry
  382. // provisioning has completed
  383. type RegistryProvisioningSuccessTrackOpts struct {
  384. *RegistryScopedTrackOpts
  385. RegistryType types.InfraKind
  386. InfraID uint
  387. }
  388. // RegistryProvisioningSuccessTrack returns a new track for when a registry
  389. // provisioning has completed
  390. func RegistryProvisioningSuccessTrack(opts *RegistryProvisioningSuccessTrackOpts) segmentTrack {
  391. additionalProps := make(map[string]interface{})
  392. additionalProps["registry_type"] = opts.RegistryType
  393. additionalProps["infra_id"] = opts.InfraID
  394. return getSegmentRegistryTrack(
  395. opts.RegistryScopedTrackOpts,
  396. getDefaultSegmentTrack(additionalProps, RegistryProvisioningSuccess),
  397. )
  398. }
  399. // ClusterDestroyingStartTrackOpts are the options for creating a track when a cluster
  400. // has started destroying
  401. type ClusterDestroyingStartTrackOpts struct {
  402. *ClusterScopedTrackOpts
  403. ClusterType types.InfraKind
  404. InfraID uint
  405. }
  406. // ClusterDestroyingStartTrack returns a track for when a cluster
  407. // has started destroying
  408. func ClusterDestroyingStartTrack(opts *ClusterDestroyingStartTrackOpts) segmentTrack {
  409. additionalProps := make(map[string]interface{})
  410. additionalProps["cluster_type"] = opts.ClusterType
  411. additionalProps["infra_id"] = opts.InfraID
  412. return getSegmentClusterTrack(
  413. opts.ClusterScopedTrackOpts,
  414. getDefaultSegmentTrack(additionalProps, ClusterDestroyingStart),
  415. )
  416. }
  417. // ClusterDestroyingSuccessTrackOpts are the options for creating a track when a cluster
  418. // has successfully provisioned
  419. type ClusterDestroyingSuccessTrackOpts struct {
  420. *ClusterScopedTrackOpts
  421. ClusterType types.InfraKind
  422. InfraID uint
  423. }
  424. // ClusterDestroyingSuccessTrack returns a new track for when a cluster
  425. // has successfully provisioned
  426. func ClusterDestroyingSuccessTrack(opts *ClusterDestroyingSuccessTrackOpts) segmentTrack {
  427. additionalProps := make(map[string]interface{})
  428. additionalProps["cluster_type"] = opts.ClusterType
  429. additionalProps["infra_id"] = opts.InfraID
  430. return getSegmentClusterTrack(
  431. opts.ClusterScopedTrackOpts,
  432. getDefaultSegmentTrack(additionalProps, ClusterDestroyingSuccess),
  433. )
  434. }