assetprops.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. package kubecost
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. // AssetProperty is a kind of property belonging to an Asset
  7. type AssetProperty string
  8. const (
  9. // AssetNilProp is the zero-value of AssetProperty
  10. AssetNilProp AssetProperty = ""
  11. // AssetAccountProp describes the account of the Asset
  12. AssetAccountProp AssetProperty = "account"
  13. // AssetCategoryProp describes the category of the Asset
  14. AssetCategoryProp AssetProperty = "category"
  15. // AssetClusterProp describes the cluster of the Asset
  16. AssetClusterProp AssetProperty = "cluster"
  17. // AssetNameProp describes the name of the Asset
  18. AssetNameProp AssetProperty = "name"
  19. // AssetNodeProp describes the node of the Asset
  20. AssetNodeProp AssetProperty = "node"
  21. // AssetProjectProp describes the project of the Asset
  22. AssetProjectProp AssetProperty = "project"
  23. // AssetProviderProp describes the provider of the Asset
  24. AssetProviderProp AssetProperty = "provider"
  25. // AssetProviderIDProp describes the providerID of the Asset
  26. AssetProviderIDProp AssetProperty = "providerID"
  27. // AssetServiceProp describes the service of the Asset
  28. AssetServiceProp AssetProperty = "service"
  29. // AssetTypeProp describes the type of the Asset
  30. AssetTypeProp AssetProperty = "type"
  31. // AssetDepartmentProp describes the department of the Asset
  32. AssetDepartmentProp AssetProperty = "department"
  33. // AssetEnvironmentProp describes the environment of the Asset
  34. AssetEnvironmentProp AssetProperty = "environment"
  35. // AssetOwnerProp describes the owner of the Asset
  36. AssetOwnerProp AssetProperty = "owner"
  37. // AssetProductProp describes the product of the Asset
  38. AssetProductProp AssetProperty = "product"
  39. // AssetTeamProp describes the team of the Asset
  40. AssetTeamProp AssetProperty = "team"
  41. )
  42. // ParseAssetProperty attempts to parse a string into an AssetProperty
  43. func ParseAssetProperty(text string) (AssetProperty, error) {
  44. switch strings.TrimSpace(strings.ToLower(text)) {
  45. case "account":
  46. return AssetAccountProp, nil
  47. case "category":
  48. return AssetCategoryProp, nil
  49. case "cluster":
  50. return AssetClusterProp, nil
  51. case "name":
  52. return AssetNameProp, nil
  53. case "project":
  54. return AssetProjectProp, nil
  55. case "provider":
  56. return AssetProviderProp, nil
  57. case "providerid":
  58. return AssetProviderIDProp, nil
  59. case "service":
  60. return AssetServiceProp, nil
  61. case "type":
  62. return AssetTypeProp, nil
  63. case "department":
  64. return AssetDepartmentProp, nil
  65. case "environment":
  66. return AssetEnvironmentProp, nil
  67. case "owner":
  68. return AssetOwnerProp, nil
  69. case "product":
  70. return AssetProductProp, nil
  71. case "team":
  72. return AssetTeamProp, nil
  73. }
  74. return AssetNilProp, fmt.Errorf("invalid asset property: %s", text)
  75. }
  76. // Category options
  77. // ComputeCategory signifies the Compute Category
  78. const ComputeCategory = "Compute"
  79. // StorageCategory signifies the Storage Category
  80. const StorageCategory = "Storage"
  81. // NetworkCategory signifies the Network Category
  82. const NetworkCategory = "Network"
  83. // ManagementCategory signifies the Management Category
  84. const ManagementCategory = "Management"
  85. // SharedCategory signifies an unassigned Category
  86. const SharedCategory = "Shared"
  87. // OtherCategory signifies an unassigned Category
  88. const OtherCategory = "Other"
  89. // Provider options
  90. // AWSProvider describes the provider AWS
  91. const AWSProvider = "AWS"
  92. // describes how AWS labels nodepool nodes
  93. const EKSNodepoolLabel = "eks.amazonaws.com/nodegroup"
  94. // GCPProvider describes the provider GCP
  95. const GCPProvider = "GCP"
  96. // describes how nodepool nodes are labeled in GKE
  97. const GKENodePoolLabel = "cloud.google.com/gke-nodepool"
  98. // AzureProvider describes the provider Azure
  99. const AzureProvider = "Azure"
  100. // describes how Azure labels nodepool nodes
  101. const AKSNodepoolLabel = "kubernetes.azure.com/agentpool"
  102. // AlibabaProvider describes the provider for Alibaba Cloud
  103. const AlibabaProvider = "Alibaba"
  104. // CSVProvider describes the provider a CSV
  105. const CSVProvider = "CSV"
  106. // CustomProvider describes a custom provider
  107. const CustomProvider = "custom"
  108. // ScalewayProvider describes the provider Scaleway
  109. const ScalewayProvider = "Scaleway"
  110. // NilProvider describes unknown provider
  111. const NilProvider = "-"
  112. // Service options
  113. const KubernetesService = "Kubernetes"
  114. // ParseProvider attempts to parse and return a known provider, given a string
  115. func ParseProvider(str string) string {
  116. switch strings.ToLower(strings.TrimSpace(str)) {
  117. case "aws", "eks", "amazon":
  118. return AWSProvider
  119. case "gcp", "gke", "google":
  120. return GCPProvider
  121. case "azure":
  122. return AzureProvider
  123. case "scaleway", "scw", "kapsule":
  124. return ScalewayProvider
  125. default:
  126. return NilProvider
  127. }
  128. }
  129. // AssetProperties describes all properties assigned to an Asset.
  130. type AssetProperties struct {
  131. Category string `json:"category,omitempty"`
  132. Provider string `json:"provider,omitempty"`
  133. Account string `json:"account,omitempty"`
  134. Project string `json:"project,omitempty"`
  135. Service string `json:"service,omitempty"`
  136. Cluster string `json:"cluster,omitempty"`
  137. Name string `json:"name,omitempty"`
  138. ProviderID string `json:"providerID,omitempty"`
  139. }
  140. // Clone returns a cloned instance of the given AssetProperties
  141. func (ap *AssetProperties) Clone() *AssetProperties {
  142. if ap == nil {
  143. return nil
  144. }
  145. clone := &AssetProperties{}
  146. clone.Category = ap.Category
  147. clone.Provider = ap.Provider
  148. clone.Account = ap.Account
  149. clone.Project = ap.Project
  150. clone.Service = ap.Service
  151. clone.Cluster = ap.Cluster
  152. clone.Name = ap.Name
  153. clone.ProviderID = ap.ProviderID
  154. return clone
  155. }
  156. // Equal returns true only if both AssetProperties are matches
  157. func (ap *AssetProperties) Equal(that *AssetProperties) bool {
  158. if ap == nil && that == nil {
  159. return true
  160. }
  161. if ap == nil || that == nil {
  162. return false
  163. }
  164. if ap.Category != that.Category {
  165. return false
  166. }
  167. if ap.Provider != that.Provider {
  168. return false
  169. }
  170. if ap.Account != that.Account {
  171. return false
  172. }
  173. if ap.Project != that.Project {
  174. return false
  175. }
  176. if ap.Service != that.Service {
  177. return false
  178. }
  179. if ap.Cluster != that.Cluster {
  180. return false
  181. }
  182. if ap.Name != that.Name {
  183. return false
  184. }
  185. if ap.ProviderID != that.ProviderID {
  186. return false
  187. }
  188. return true
  189. }
  190. // Keys returns the list of string values used to key the Asset based on the
  191. // list of properties provided.
  192. func (ap *AssetProperties) Keys(props []AssetProperty) []string {
  193. keys := []string{}
  194. if ap == nil {
  195. return keys
  196. }
  197. if (props == nil || hasProp(props, AssetCategoryProp)) && ap.Category != "" {
  198. keys = append(keys, ap.Category)
  199. }
  200. if (props == nil || hasProp(props, AssetProviderProp)) && ap.Provider != "" {
  201. keys = append(keys, ap.Provider)
  202. }
  203. if (props == nil || hasProp(props, AssetAccountProp)) && ap.Account != "" {
  204. keys = append(keys, ap.Account)
  205. }
  206. if (props == nil || hasProp(props, AssetProjectProp)) && ap.Project != "" {
  207. keys = append(keys, ap.Project)
  208. }
  209. if (props == nil || hasProp(props, AssetServiceProp)) && ap.Service != "" {
  210. keys = append(keys, ap.Service)
  211. }
  212. if (props == nil || hasProp(props, AssetClusterProp)) && ap.Cluster != "" {
  213. keys = append(keys, ap.Cluster)
  214. }
  215. if (props == nil || hasProp(props, AssetNameProp)) && ap.Name != "" {
  216. keys = append(keys, ap.Name)
  217. }
  218. if (props == nil || hasProp(props, AssetProviderIDProp)) && ap.ProviderID != "" {
  219. keys = append(keys, ap.ProviderID)
  220. }
  221. return keys
  222. }
  223. // Merge retains only the properties shared with the given AssetProperties
  224. func (ap *AssetProperties) Merge(that *AssetProperties) *AssetProperties {
  225. if ap == nil || that == nil {
  226. return nil
  227. }
  228. result := &AssetProperties{}
  229. if ap.Category == that.Category {
  230. result.Category = ap.Category
  231. }
  232. if ap.Provider == that.Provider {
  233. result.Provider = ap.Provider
  234. }
  235. if ap.Account == that.Account {
  236. result.Account = ap.Account
  237. }
  238. if ap.Project == that.Project {
  239. result.Project = ap.Project
  240. }
  241. if ap.Service == that.Service {
  242. result.Service = ap.Service
  243. }
  244. if ap.Cluster == that.Cluster {
  245. result.Cluster = ap.Cluster
  246. }
  247. if ap.Name == that.Name {
  248. result.Name = ap.Name
  249. }
  250. if ap.ProviderID == that.ProviderID {
  251. result.ProviderID = ap.ProviderID
  252. }
  253. return result
  254. }
  255. // String represents the properties as a string
  256. func (ap *AssetProperties) String() string {
  257. if ap == nil {
  258. return "<nil>"
  259. }
  260. strs := []string{}
  261. if ap.Category != "" {
  262. strs = append(strs, "Category:"+ap.Category)
  263. }
  264. if ap.Provider != "" {
  265. strs = append(strs, "Provider:"+ap.Provider)
  266. }
  267. if ap.Account != "" {
  268. strs = append(strs, "Account:"+ap.Account)
  269. }
  270. if ap.Project != "" {
  271. strs = append(strs, "Project:"+ap.Project)
  272. }
  273. if ap.Service != "" {
  274. strs = append(strs, "Service:"+ap.Service)
  275. }
  276. if ap.Cluster != "" {
  277. strs = append(strs, "Cluster:"+ap.Cluster)
  278. }
  279. if ap.Name != "" {
  280. strs = append(strs, "Name:"+ap.Name)
  281. }
  282. if ap.ProviderID != "" {
  283. strs = append(strs, "ProviderID:"+ap.ProviderID)
  284. }
  285. return strings.Join(strs, ",")
  286. }
  287. func hasProp(props []AssetProperty, prop AssetProperty) bool {
  288. for _, p := range props {
  289. if p == prop {
  290. return true
  291. }
  292. }
  293. return false
  294. }