configurations.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. package config
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/opencost/opencost/core/pkg/log"
  6. "github.com/opencost/opencost/pkg/cloud"
  7. "github.com/opencost/opencost/pkg/cloud/alibaba"
  8. "github.com/opencost/opencost/pkg/cloud/aws"
  9. "github.com/opencost/opencost/pkg/cloud/azure"
  10. "github.com/opencost/opencost/pkg/cloud/gcp"
  11. "github.com/opencost/opencost/pkg/cloud/oracle"
  12. "github.com/opencost/opencost/pkg/cloud/stackit"
  13. )
  14. // MultiCloudConfig struct is used to unmarshal cloud configs for each provider out of cloud-integration file
  15. // Deprecated: v1.104 use Configurations
  16. type MultiCloudConfig struct {
  17. AzureConfigs []azure.AzureStorageConfig `json:"azure"`
  18. GCPConfigs []gcp.BigQueryConfig `json:"gcp"`
  19. AWSConfigs []aws.AwsAthenaInfo `json:"aws"`
  20. AlibabaConfigs []alibaba.AlibabaInfo `json:"alibaba"`
  21. }
  22. func (mcc MultiCloudConfig) loadConfigurations(configs *Configurations) {
  23. // Load AWS configs
  24. for _, awsConfig := range mcc.AWSConfigs {
  25. kc := aws.ConvertAwsAthenaInfoToConfig(awsConfig)
  26. err := configs.Insert(kc)
  27. if err != nil {
  28. log.Errorf("MultiCloudConfig: error converting AWS config %s", err.Error())
  29. }
  30. }
  31. // Load GCP configs
  32. for _, gcpConfig := range mcc.GCPConfigs {
  33. kc := gcp.ConvertBigQueryConfigToConfig(gcpConfig)
  34. err := configs.Insert(kc)
  35. if err != nil {
  36. log.Errorf("MultiCloudConfig: error converting GCP config %s", err.Error())
  37. }
  38. }
  39. // Load Azure configs
  40. for _, azureConfig := range mcc.AzureConfigs {
  41. kc := azure.ConvertAzureStorageConfigToConfig(azureConfig)
  42. err := configs.Insert(kc)
  43. if err != nil {
  44. log.Errorf("MultiCloudConfig: error converting Azure config %s", err.Error())
  45. }
  46. }
  47. // Load Alibaba Cloud Configs
  48. for _, aliCloudConfig := range mcc.AlibabaConfigs {
  49. kc := alibaba.ConvertAlibabaInfoToConfig(aliCloudConfig)
  50. err := configs.Insert(kc)
  51. if err != nil {
  52. log.Errorf("MultiCloudConfig: error converting Alibaba config %s", err.Error())
  53. }
  54. }
  55. }
  56. // Configurations is a general use container for all configuration types
  57. type Configurations struct {
  58. AWS *AWSConfigs `json:"aws,omitempty"`
  59. GCP *GCPConfigs `json:"gcp,omitempty"`
  60. Azure *AzureConfigs `json:"azure,omitempty"`
  61. Alibaba *AlibabaConfigs `json:"alibaba,omitempty"`
  62. OCI *OCIConfigs `json:"oci,omitempty"`
  63. STACKIT *STACKITConfigs `json:"stackit,omitempty"`
  64. }
  65. // UnmarshalJSON custom json unmarshalling to maintain support for MultiCloudConfig format
  66. func (c *Configurations) UnmarshalJSON(bytes []byte) error {
  67. // This has been tested for backwards compatability, and it works in both config formats.
  68. // It also coincidentally works if you mix-and-match both the old format and the new
  69. // format.
  70. // Create inline type to gain access to default Unmarshalling
  71. type ConfUnmarshaller *Configurations
  72. var conf ConfUnmarshaller = c
  73. err := json.Unmarshal(bytes, conf)
  74. // If unmarshal is successful, return
  75. if err == nil {
  76. return nil
  77. }
  78. // Attempt to unmarshal into old config object
  79. multiConfig := &MultiCloudConfig{}
  80. err = json.Unmarshal(bytes, multiConfig)
  81. if err != nil {
  82. return err
  83. }
  84. multiConfig.loadConfigurations(c)
  85. return nil
  86. }
  87. func (c *Configurations) Equals(that *Configurations) bool {
  88. if c == nil && that == nil {
  89. return true
  90. }
  91. if c == nil || that == nil {
  92. return false
  93. }
  94. if !c.AWS.Equals(that.AWS) {
  95. return false
  96. }
  97. if !c.GCP.Equals(that.GCP) {
  98. return false
  99. }
  100. if !c.Azure.Equals(that.Azure) {
  101. return false
  102. }
  103. if !c.Alibaba.Equals(that.Alibaba) {
  104. return false
  105. }
  106. if !c.OCI.Equals(that.OCI) {
  107. return false
  108. }
  109. if !c.STACKIT.Equals(that.STACKIT) {
  110. return false
  111. }
  112. return true
  113. }
  114. func (c *Configurations) Insert(keyedConfig cloud.Config) error {
  115. switch keyedConfig.(type) {
  116. case *aws.AthenaConfiguration:
  117. if c.AWS == nil {
  118. c.AWS = &AWSConfigs{}
  119. }
  120. c.AWS.Athena = append(c.AWS.Athena, keyedConfig.(*aws.AthenaConfiguration))
  121. case *aws.S3Configuration:
  122. if c.AWS == nil {
  123. c.AWS = &AWSConfigs{}
  124. }
  125. c.AWS.S3 = append(c.AWS.S3, keyedConfig.(*aws.S3Configuration))
  126. case *gcp.BigQueryConfiguration:
  127. if c.GCP == nil {
  128. c.GCP = &GCPConfigs{}
  129. }
  130. c.GCP.BigQuery = append(c.GCP.BigQuery, keyedConfig.(*gcp.BigQueryConfiguration))
  131. case *azure.StorageConfiguration:
  132. if c.Azure == nil {
  133. c.Azure = &AzureConfigs{}
  134. }
  135. c.Azure.Storage = append(c.Azure.Storage, keyedConfig.(*azure.StorageConfiguration))
  136. case *alibaba.BOAConfiguration:
  137. if c.Alibaba == nil {
  138. c.Alibaba = &AlibabaConfigs{}
  139. }
  140. c.Alibaba.BOA = append(c.Alibaba.BOA, keyedConfig.(*alibaba.BOAConfiguration))
  141. case *oracle.UsageApiConfiguration:
  142. if c.OCI == nil {
  143. c.OCI = &OCIConfigs{}
  144. }
  145. c.OCI.UsageAPI = append(c.OCI.UsageAPI, keyedConfig.(*oracle.UsageApiConfiguration))
  146. case *stackit.CostConfiguration:
  147. if c.STACKIT == nil {
  148. c.STACKIT = &STACKITConfigs{}
  149. }
  150. c.STACKIT.CostAPI = append(c.STACKIT.CostAPI, keyedConfig.(*stackit.CostConfiguration))
  151. default:
  152. return fmt.Errorf("Configurations: Insert: failed to insert config of type: %T", keyedConfig)
  153. }
  154. return nil
  155. }
  156. func (c *Configurations) ToSlice() []cloud.KeyedConfig {
  157. var keyedConfigs []cloud.KeyedConfig
  158. if c.AWS != nil {
  159. for _, athenaConfig := range c.AWS.Athena {
  160. keyedConfigs = append(keyedConfigs, athenaConfig)
  161. }
  162. for _, s3Config := range c.AWS.S3 {
  163. keyedConfigs = append(keyedConfigs, s3Config)
  164. }
  165. }
  166. if c.GCP != nil {
  167. for _, bigQueryConfig := range c.GCP.BigQuery {
  168. keyedConfigs = append(keyedConfigs, bigQueryConfig)
  169. }
  170. }
  171. if c.Azure != nil {
  172. for _, azureStorageConfig := range c.Azure.Storage {
  173. keyedConfigs = append(keyedConfigs, azureStorageConfig)
  174. }
  175. }
  176. if c.Alibaba != nil {
  177. for _, boaConfig := range c.Alibaba.BOA {
  178. keyedConfigs = append(keyedConfigs, boaConfig)
  179. }
  180. }
  181. if c.OCI != nil {
  182. for _, usageConfig := range c.OCI.UsageAPI {
  183. keyedConfigs = append(keyedConfigs, usageConfig)
  184. }
  185. }
  186. if c.STACKIT != nil {
  187. for _, costConfig := range c.STACKIT.CostAPI {
  188. keyedConfigs = append(keyedConfigs, costConfig)
  189. }
  190. }
  191. return keyedConfigs
  192. }
  193. type AWSConfigs struct {
  194. Athena []*aws.AthenaConfiguration `json:"athena,omitempty"`
  195. S3 []*aws.S3Configuration `json:"s3,omitempty"`
  196. }
  197. func (ac *AWSConfigs) Equals(that *AWSConfigs) bool {
  198. if ac == nil && that == nil {
  199. return true
  200. }
  201. if ac == nil || that == nil {
  202. return false
  203. }
  204. // Check Athena
  205. if len(ac.Athena) != len(that.Athena) {
  206. return false
  207. }
  208. for i, thisAthena := range ac.Athena {
  209. thatAthena := that.Athena[i]
  210. if !thisAthena.Equals(thatAthena) {
  211. return false
  212. }
  213. }
  214. // Check S3
  215. if len(ac.S3) != len(that.S3) {
  216. return false
  217. }
  218. for i, thisS3 := range ac.S3 {
  219. thatS3 := that.S3[i]
  220. if !thisS3.Equals(thatS3) {
  221. return false
  222. }
  223. }
  224. return true
  225. }
  226. type GCPConfigs struct {
  227. BigQuery []*gcp.BigQueryConfiguration `json:"bigQuery,omitempty"`
  228. }
  229. func (gc *GCPConfigs) Equals(that *GCPConfigs) bool {
  230. if gc == nil && that == nil {
  231. return true
  232. }
  233. if gc == nil || that == nil {
  234. return false
  235. }
  236. // Check BigQuery
  237. if len(gc.BigQuery) != len(that.BigQuery) {
  238. return false
  239. }
  240. for i, thisBigQuery := range gc.BigQuery {
  241. thatBigQuery := that.BigQuery[i]
  242. if !thisBigQuery.Equals(thatBigQuery) {
  243. return false
  244. }
  245. }
  246. return true
  247. }
  248. type AzureConfigs struct {
  249. Storage []*azure.StorageConfiguration `json:"storage,omitempty"`
  250. }
  251. func (ac *AzureConfigs) Equals(that *AzureConfigs) bool {
  252. if ac == nil && that == nil {
  253. return true
  254. }
  255. if ac == nil || that == nil {
  256. return false
  257. }
  258. // Check Storage
  259. if len(ac.Storage) != len(that.Storage) {
  260. return false
  261. }
  262. for i, thisStorage := range ac.Storage {
  263. thatStorage := that.Storage[i]
  264. if !thisStorage.Equals(thatStorage) {
  265. return false
  266. }
  267. }
  268. return true
  269. }
  270. type AlibabaConfigs struct {
  271. BOA []*alibaba.BOAConfiguration `json:"boa,omitempty"`
  272. }
  273. func (ac *AlibabaConfigs) Equals(that *AlibabaConfigs) bool {
  274. if ac == nil && that == nil {
  275. return true
  276. }
  277. if ac == nil || that == nil {
  278. return false
  279. }
  280. // Check BOA
  281. if len(ac.BOA) != len(that.BOA) {
  282. return false
  283. }
  284. for i, thisBOA := range ac.BOA {
  285. thatBOA := that.BOA[i]
  286. if !thisBOA.Equals(thatBOA) {
  287. return false
  288. }
  289. }
  290. return true
  291. }
  292. type OCIConfigs struct {
  293. UsageAPI []*oracle.UsageApiConfiguration `json:"usageApi,omitempty"`
  294. }
  295. func (oc *OCIConfigs) Equals(that *OCIConfigs) bool {
  296. if oc == nil && that == nil {
  297. return true
  298. }
  299. if oc == nil || that == nil {
  300. return false
  301. }
  302. // Check Usage API
  303. if len(oc.UsageAPI) != len(that.UsageAPI) {
  304. return false
  305. }
  306. for i, thisUsageAPI := range oc.UsageAPI {
  307. thatUsageAPI := that.UsageAPI[i]
  308. if !thisUsageAPI.Equals(thatUsageAPI) {
  309. return false
  310. }
  311. }
  312. return true
  313. }
  314. type STACKITConfigs struct {
  315. CostAPI []*stackit.CostConfiguration `json:"costApi,omitempty"`
  316. }
  317. func (sc *STACKITConfigs) Equals(that *STACKITConfigs) bool {
  318. if sc == nil && that == nil {
  319. return true
  320. }
  321. if sc == nil || that == nil {
  322. return false
  323. }
  324. if len(sc.CostAPI) != len(that.CostAPI) {
  325. return false
  326. }
  327. for i, thisCost := range sc.CostAPI {
  328. thatCost := that.CostAPI[i]
  329. if !thisCost.Equals(thatCost) {
  330. return false
  331. }
  332. }
  333. return true
  334. }