configurations.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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 defined type to gain access to default Unmarshalling, then convert to pointer
  71. type confUnmarshaller Configurations
  72. err := json.Unmarshal(bytes, (*confUnmarshaller)(c))
  73. // If unmarshal is successful, return
  74. if err == nil {
  75. return nil
  76. }
  77. // Attempt to unmarshal into old config object
  78. multiConfig := &MultiCloudConfig{}
  79. err = json.Unmarshal(bytes, multiConfig)
  80. if err != nil {
  81. return err
  82. }
  83. multiConfig.loadConfigurations(c)
  84. return nil
  85. }
  86. func (c *Configurations) Equals(that *Configurations) bool {
  87. if c == nil && that == nil {
  88. return true
  89. }
  90. if c == nil || that == nil {
  91. return false
  92. }
  93. if !c.AWS.Equals(that.AWS) {
  94. return false
  95. }
  96. if !c.GCP.Equals(that.GCP) {
  97. return false
  98. }
  99. if !c.Azure.Equals(that.Azure) {
  100. return false
  101. }
  102. if !c.Alibaba.Equals(that.Alibaba) {
  103. return false
  104. }
  105. if !c.OCI.Equals(that.OCI) {
  106. return false
  107. }
  108. if !c.STACKIT.Equals(that.STACKIT) {
  109. return false
  110. }
  111. return true
  112. }
  113. func (c *Configurations) Insert(keyedConfig cloud.Config) error {
  114. switch keyedConfig.(type) {
  115. case *aws.AthenaConfiguration:
  116. if c.AWS == nil {
  117. c.AWS = &AWSConfigs{}
  118. }
  119. c.AWS.Athena = append(c.AWS.Athena, keyedConfig.(*aws.AthenaConfiguration))
  120. case *aws.S3Configuration:
  121. if c.AWS == nil {
  122. c.AWS = &AWSConfigs{}
  123. }
  124. c.AWS.S3 = append(c.AWS.S3, keyedConfig.(*aws.S3Configuration))
  125. case *gcp.BigQueryConfiguration:
  126. if c.GCP == nil {
  127. c.GCP = &GCPConfigs{}
  128. }
  129. c.GCP.BigQuery = append(c.GCP.BigQuery, keyedConfig.(*gcp.BigQueryConfiguration))
  130. case *azure.StorageConfiguration:
  131. if c.Azure == nil {
  132. c.Azure = &AzureConfigs{}
  133. }
  134. c.Azure.Storage = append(c.Azure.Storage, keyedConfig.(*azure.StorageConfiguration))
  135. case *alibaba.BOAConfiguration:
  136. if c.Alibaba == nil {
  137. c.Alibaba = &AlibabaConfigs{}
  138. }
  139. c.Alibaba.BOA = append(c.Alibaba.BOA, keyedConfig.(*alibaba.BOAConfiguration))
  140. case *oracle.UsageApiConfiguration:
  141. if c.OCI == nil {
  142. c.OCI = &OCIConfigs{}
  143. }
  144. c.OCI.UsageAPI = append(c.OCI.UsageAPI, keyedConfig.(*oracle.UsageApiConfiguration))
  145. case *stackit.CostConfiguration:
  146. if c.STACKIT == nil {
  147. c.STACKIT = &STACKITConfigs{}
  148. }
  149. c.STACKIT.CostAPI = append(c.STACKIT.CostAPI, keyedConfig.(*stackit.CostConfiguration))
  150. default:
  151. return fmt.Errorf("Configurations: Insert: failed to insert config of type: %T", keyedConfig)
  152. }
  153. return nil
  154. }
  155. func (c *Configurations) ToSlice() []cloud.KeyedConfig {
  156. var keyedConfigs []cloud.KeyedConfig
  157. if c.AWS != nil {
  158. for _, athenaConfig := range c.AWS.Athena {
  159. keyedConfigs = append(keyedConfigs, athenaConfig)
  160. }
  161. for _, s3Config := range c.AWS.S3 {
  162. keyedConfigs = append(keyedConfigs, s3Config)
  163. }
  164. }
  165. if c.GCP != nil {
  166. for _, bigQueryConfig := range c.GCP.BigQuery {
  167. keyedConfigs = append(keyedConfigs, bigQueryConfig)
  168. }
  169. }
  170. if c.Azure != nil {
  171. for _, azureStorageConfig := range c.Azure.Storage {
  172. keyedConfigs = append(keyedConfigs, azureStorageConfig)
  173. }
  174. }
  175. if c.Alibaba != nil {
  176. for _, boaConfig := range c.Alibaba.BOA {
  177. keyedConfigs = append(keyedConfigs, boaConfig)
  178. }
  179. }
  180. if c.OCI != nil {
  181. for _, usageConfig := range c.OCI.UsageAPI {
  182. keyedConfigs = append(keyedConfigs, usageConfig)
  183. }
  184. }
  185. if c.STACKIT != nil {
  186. for _, costConfig := range c.STACKIT.CostAPI {
  187. keyedConfigs = append(keyedConfigs, costConfig)
  188. }
  189. }
  190. return keyedConfigs
  191. }
  192. type AWSConfigs struct {
  193. Athena []*aws.AthenaConfiguration `json:"athena,omitempty"`
  194. S3 []*aws.S3Configuration `json:"s3,omitempty"`
  195. }
  196. func (ac *AWSConfigs) Equals(that *AWSConfigs) bool {
  197. if ac == nil && that == nil {
  198. return true
  199. }
  200. if ac == nil || that == nil {
  201. return false
  202. }
  203. // Check Athena
  204. if len(ac.Athena) != len(that.Athena) {
  205. return false
  206. }
  207. for i, thisAthena := range ac.Athena {
  208. thatAthena := that.Athena[i]
  209. if !thisAthena.Equals(thatAthena) {
  210. return false
  211. }
  212. }
  213. // Check S3
  214. if len(ac.S3) != len(that.S3) {
  215. return false
  216. }
  217. for i, thisS3 := range ac.S3 {
  218. thatS3 := that.S3[i]
  219. if !thisS3.Equals(thatS3) {
  220. return false
  221. }
  222. }
  223. return true
  224. }
  225. type GCPConfigs struct {
  226. BigQuery []*gcp.BigQueryConfiguration `json:"bigQuery,omitempty"`
  227. }
  228. func (gc *GCPConfigs) Equals(that *GCPConfigs) bool {
  229. if gc == nil && that == nil {
  230. return true
  231. }
  232. if gc == nil || that == nil {
  233. return false
  234. }
  235. // Check BigQuery
  236. if len(gc.BigQuery) != len(that.BigQuery) {
  237. return false
  238. }
  239. for i, thisBigQuery := range gc.BigQuery {
  240. thatBigQuery := that.BigQuery[i]
  241. if !thisBigQuery.Equals(thatBigQuery) {
  242. return false
  243. }
  244. }
  245. return true
  246. }
  247. type AzureConfigs struct {
  248. Storage []*azure.StorageConfiguration `json:"storage,omitempty"`
  249. }
  250. func (ac *AzureConfigs) Equals(that *AzureConfigs) bool {
  251. if ac == nil && that == nil {
  252. return true
  253. }
  254. if ac == nil || that == nil {
  255. return false
  256. }
  257. // Check Storage
  258. if len(ac.Storage) != len(that.Storage) {
  259. return false
  260. }
  261. for i, thisStorage := range ac.Storage {
  262. thatStorage := that.Storage[i]
  263. if !thisStorage.Equals(thatStorage) {
  264. return false
  265. }
  266. }
  267. return true
  268. }
  269. type AlibabaConfigs struct {
  270. BOA []*alibaba.BOAConfiguration `json:"boa,omitempty"`
  271. }
  272. func (ac *AlibabaConfigs) Equals(that *AlibabaConfigs) bool {
  273. if ac == nil && that == nil {
  274. return true
  275. }
  276. if ac == nil || that == nil {
  277. return false
  278. }
  279. // Check BOA
  280. if len(ac.BOA) != len(that.BOA) {
  281. return false
  282. }
  283. for i, thisBOA := range ac.BOA {
  284. thatBOA := that.BOA[i]
  285. if !thisBOA.Equals(thatBOA) {
  286. return false
  287. }
  288. }
  289. return true
  290. }
  291. type OCIConfigs struct {
  292. UsageAPI []*oracle.UsageApiConfiguration `json:"usageApi,omitempty"`
  293. }
  294. func (oc *OCIConfigs) Equals(that *OCIConfigs) bool {
  295. if oc == nil && that == nil {
  296. return true
  297. }
  298. if oc == nil || that == nil {
  299. return false
  300. }
  301. // Check Usage API
  302. if len(oc.UsageAPI) != len(that.UsageAPI) {
  303. return false
  304. }
  305. for i, thisUsageAPI := range oc.UsageAPI {
  306. thatUsageAPI := that.UsageAPI[i]
  307. if !thisUsageAPI.Equals(thatUsageAPI) {
  308. return false
  309. }
  310. }
  311. return true
  312. }
  313. type STACKITConfigs struct {
  314. CostAPI []*stackit.CostConfiguration `json:"costApi,omitempty"`
  315. }
  316. func (sc *STACKITConfigs) Equals(that *STACKITConfigs) bool {
  317. if sc == nil && that == nil {
  318. return true
  319. }
  320. if sc == nil || that == nil {
  321. return false
  322. }
  323. if len(sc.CostAPI) != len(that.CostAPI) {
  324. return false
  325. }
  326. for i, thisCost := range sc.CostAPI {
  327. thatCost := that.CostAPI[i]
  328. if !thisCost.Equals(thatCost) {
  329. return false
  330. }
  331. }
  332. return true
  333. }