provider_test.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package provider
  2. import (
  3. "testing"
  4. "github.com/opencost/opencost/core/pkg/clustercache"
  5. "github.com/opencost/opencost/core/pkg/storage"
  6. "github.com/opencost/opencost/pkg/config"
  7. v1 "k8s.io/api/core/v1"
  8. "k8s.io/apimachinery/pkg/api/resource"
  9. )
  10. func TestParseLocalDiskID(t *testing.T) {
  11. tests := map[string]struct {
  12. input string
  13. want string
  14. }{
  15. "empty string": {
  16. input: "",
  17. want: "",
  18. },
  19. "generic string": {
  20. input: "test",
  21. want: "test",
  22. },
  23. "AWS node provider id": {
  24. input: "aws:///us-east-2a/i-0fea4fd46592d050b",
  25. want: "i-0fea4fd46592d050b",
  26. },
  27. "GCP node provider id": {
  28. input: "gce://guestbook-11111/us-central1-a/gke-niko-n1-standard-2-wlkla-8d48e58a-hfy7",
  29. want: "gke-niko-n1-standard-2-wlkla-8d48e58a-hfy7",
  30. },
  31. "Azure vmss provider id": {
  32. input: "azure:///subscriptions/ae337b64-e7ba-3387-b043-187289efe4e3/resourceGroups/mc_test_eastus2/providers/Microsoft.Compute/virtualMachineScaleSets/aks-userpool-12345678-vmss/virtualMachines/11",
  33. want: "azure:///subscriptions/ae337b64-e7ba-3387-b043-187289efe4e3/resourcegroups/mc_test_eastus2/providers/microsoft.compute/disks/aks-userpool-12345678-vmss00000b_osdisk",
  34. },
  35. "Azure vm provider id": {
  36. input: "azure:///subscriptions/ae337b64-e7ba-3387-b043-187289efe4e3/resourceGroups/mc_test_eastus2/providers/Microsoft.Compute/virtualMachines/master-0",
  37. want: "azure:///subscriptions/ae337b64-e7ba-3387-b043-187289efe4e3/resourcegroups/mc_test_eastus2/providers/microsoft.compute/disks/master-0_osdisk",
  38. },
  39. }
  40. for name, tt := range tests {
  41. t.Run(name, func(t *testing.T) {
  42. if got := ParseLocalDiskID(tt.input); got != tt.want {
  43. t.Errorf("ParseLocalDiskID() = %v, want %v", got, tt.want)
  44. }
  45. })
  46. }
  47. }
  48. func TestProviderConfigUpdateFromMapPreservesHourlyPrices(t *testing.T) {
  49. confMan := config.NewConfigFileManager(storage.NewMemoryStorage())
  50. providerConfig := NewProviderConfig(confMan, "default.json")
  51. updated, err := providerConfig.UpdateFromMap(map[string]string{
  52. "CPU": "0.031611",
  53. "spotCPU": "0.006655",
  54. "RAM": "0.004237",
  55. "spotRAM": "0.000892",
  56. "GPU": "0.95",
  57. "spotGPU": "0.308",
  58. "storage": "0.00005479452",
  59. })
  60. if err != nil {
  61. t.Fatalf("UpdateFromMap returned error: %v", err)
  62. }
  63. if updated.CPU != "0.031611" {
  64. t.Errorf("CPU = %q, want hourly value %q", updated.CPU, "0.031611")
  65. }
  66. if updated.SpotCPU != "0.006655" {
  67. t.Errorf("SpotCPU = %q, want hourly value %q", updated.SpotCPU, "0.006655")
  68. }
  69. if updated.RAM != "0.004237" {
  70. t.Errorf("RAM = %q, want hourly value %q", updated.RAM, "0.004237")
  71. }
  72. if updated.SpotRAM != "0.000892" {
  73. t.Errorf("SpotRAM = %q, want hourly value %q", updated.SpotRAM, "0.000892")
  74. }
  75. if updated.GPU != "0.95" {
  76. t.Errorf("GPU = %q, want hourly value %q", updated.GPU, "0.95")
  77. }
  78. if updated.SpotGPU != "0.308" {
  79. t.Errorf("SpotGPU = %q, want hourly value %q", updated.SpotGPU, "0.308")
  80. }
  81. if updated.Storage != "0.00005479452" {
  82. t.Errorf("Storage = %q, want hourly value %q", updated.Storage, "0.00005479452")
  83. }
  84. }
  85. func TestCustomProviderGetKeyDetectsGPUCapacity(t *testing.T) {
  86. cases := []struct {
  87. name string
  88. provider *CustomProvider
  89. labels map[string]string
  90. capacity v1.ResourceList
  91. wantGPUType string
  92. wantGPUCount int
  93. }{
  94. {
  95. name: "nvidia GPU capacity",
  96. capacity: v1.ResourceList{
  97. "nvidia.com/gpu": resource.MustParse("2"),
  98. },
  99. wantGPUType: "nvidia.com/gpu",
  100. wantGPUCount: 2,
  101. },
  102. {
  103. name: "virtual GPU capacity",
  104. capacity: v1.ResourceList{
  105. "k8s.amazonaws.com/vgpu": resource.MustParse("3"),
  106. },
  107. wantGPUType: "k8s.amazonaws.com/vgpu",
  108. wantGPUCount: 3,
  109. },
  110. {
  111. name: "configured GPU label takes precedence over capacity type",
  112. provider: &CustomProvider{
  113. GPULabel: "gpu.example/type",
  114. },
  115. labels: map[string]string{
  116. "gpu.example/type": "a100",
  117. },
  118. capacity: v1.ResourceList{
  119. "nvidia.com/gpu": resource.MustParse("4"),
  120. },
  121. wantGPUType: "a100",
  122. wantGPUCount: 4,
  123. },
  124. {
  125. name: "no GPU capacity",
  126. capacity: v1.ResourceList{},
  127. wantGPUType: "",
  128. wantGPUCount: 0,
  129. },
  130. }
  131. for _, tt := range cases {
  132. t.Run(tt.name, func(t *testing.T) {
  133. customProvider := tt.provider
  134. if customProvider == nil {
  135. customProvider = &CustomProvider{}
  136. }
  137. labels := tt.labels
  138. if labels == nil {
  139. labels = map[string]string{}
  140. }
  141. key := customProvider.GetKey(labels, &clustercache.Node{
  142. Labels: labels,
  143. Status: v1.NodeStatus{
  144. Capacity: tt.capacity,
  145. },
  146. })
  147. if got := key.GPUType(); got != tt.wantGPUType {
  148. t.Errorf("GPUType() = %q, want %q", got, tt.wantGPUType)
  149. }
  150. if got := key.GPUCount(); got != tt.wantGPUCount {
  151. t.Errorf("GPUCount() = %d, want %d", got, tt.wantGPUCount)
  152. }
  153. })
  154. }
  155. }
  156. func TestCustomProviderNodePricingUsesDetectedGPUCount(t *testing.T) {
  157. customProvider := &CustomProvider{
  158. Pricing: map[string]*NodePrice{
  159. "default": {
  160. CPU: "0.031611",
  161. RAM: "0.004237",
  162. },
  163. "default,gpu": {
  164. CPU: "0.031611",
  165. RAM: "0.004237",
  166. GPU: "0.95",
  167. },
  168. },
  169. }
  170. key := customProvider.GetKey(map[string]string{}, &clustercache.Node{
  171. Status: v1.NodeStatus{
  172. Capacity: v1.ResourceList{
  173. "nvidia.com/gpu": resource.MustParse("2"),
  174. },
  175. },
  176. })
  177. node, _, err := customProvider.NodePricing(key)
  178. if err != nil {
  179. t.Fatalf("NodePricing returned error: %v", err)
  180. }
  181. if node.VCPUCost != "0.031611" {
  182. t.Errorf("VCPUCost = %q, want %q", node.VCPUCost, "0.031611")
  183. }
  184. if node.RAMCost != "0.004237" {
  185. t.Errorf("RAMCost = %q, want %q", node.RAMCost, "0.004237")
  186. }
  187. if node.GPUCost != "0.95" {
  188. t.Errorf("GPUCost = %q, want %q", node.GPUCost, "0.95")
  189. }
  190. if node.GPU != "2" {
  191. t.Errorf("GPU = %q, want %q", node.GPU, "2")
  192. }
  193. }