@@ -4,11 +4,12 @@ import (
44 "context"
55 "encoding/json"
66 "fmt"
7+ "io"
78 "net/http"
89 "strings"
9- "time"
1010
1111 "k8s.io/apimachinery/pkg/api/resource"
12+ "k8s.io/klog/v2"
1213
1314 clusterv1beta1 "go.goms.io/fleet/apis/cluster/v1beta1"
1415 placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1"
@@ -27,9 +28,7 @@ var _ AzureCapacityService = &DefaultAzureCapacityService{}
2728func NewAzureCapacityService (endpoint string ) * DefaultAzureCapacityService {
2829 return & DefaultAzureCapacityService {
2930 endpoint : endpoint ,
30- client : & http.Client {
31- Timeout : 30 * time .Second ,
32- },
31+ client : & http.Client {},
3332 }
3433}
3534
@@ -48,15 +47,22 @@ func (s *DefaultAzureCapacityService) ValidateCapacityRequirement(
4847 return false , fmt .Errorf ("failed to extract capacity requirement: %w" , err )
4948 }
5049
50+ // TODO: Replace with actual Azure capacity client call
51+ endpoint := s .endpoint
52+ if ! strings .HasPrefix (endpoint , "http://" ) && ! strings .HasPrefix (endpoint , "https://" ) {
53+ endpoint = "http://" + endpoint
54+ }
5155 url := fmt .Sprintf ("%s/fleet/subscriptions/%s/providers/Microsoft.Compute/locations/%s/vmSizeRecommendations/vmAttributeBased/generate" ,
52- s . endpoint , subID , location )
56+ strings . TrimRight ( endpoint , "/" ) , subID , location )
5357 payload := map [string ]interface {}{
58+ "subscription_id" : subID ,
59+ "location" : location ,
5460 "regular_priority_profile" : map [string ]interface {}{
55- "capacity_unit_type" : "CAPACITY_UNIT_TYPE_VM_INSTANCE_COUNT" ,
56- "target_capacity" : capacity .Value (),
61+ "capacity_unit_type" : 1 , // CAPACITY_UNIT_TYPE_VM_INSTANCE_COUNT
62+ "target_capacity" : uint32 ( capacity .Value () ),
5763 },
5864 "recommendation_properties" : map [string ]interface {}{
59- "restrictions_filter" : "RESTRICTIONS_FILTER_QUOTA_AND_OFFER_RESTRICTIONS" ,
65+ "restrictions_filter" : 4 , // RESTRICTIONS_FILTER_QUOTA_AND_OFFER_RESTRICTIONS
6066 },
6167 "resource_properties" : map [string ]interface {}{},
6268 }
@@ -70,36 +76,46 @@ func (s *DefaultAzureCapacityService) ValidateCapacityRequirement(
7076 return false , fmt .Errorf ("failed to create HTTP request: %w" , err )
7177 }
7278 httpReq .Header .Set ("Content-Type" , "application/json" )
79+ httpReq .Header .Set ("Accept" , "application/json" )
80+ // Add service mesh headers
81+ httpReq .Header .Set ("x-service-name" , "fleet" )
82+ httpReq .Header .Set ("x-service-version" , "v1" )
7383
7484 resp , err := s .client .Do (httpReq )
7585 if err != nil {
7686 return false , fmt .Errorf ("failed to make HTTP request to Azure service: %w" , err )
7787 }
7888 defer resp .Body .Close ()
7989
80- if resp .StatusCode != http .StatusOK {
81- return false , fmt .Errorf ("Azure service returned status %d" , resp .StatusCode )
90+ bodyBytes , _ := io .ReadAll (resp .Body )
91+ contentType := resp .Header .Get ("Content-Type" )
92+
93+ if resp .StatusCode < 200 || resp .StatusCode >= 300 {
94+ return false , fmt .Errorf ("Azure service returned status %d: %s" , resp .StatusCode , string (bodyBytes ))
8295 }
8396
8497 var respObj struct {
85- //TODO: add other fields
8698 RecommendedVmSizes struct {
8799 RegularVmSizes []struct {
88- Name string `json:"name"`
100+ Family string `json:"family"`
101+ Name string `json:"name"`
102+ Size string `json:"size"`
89103 } `json:"regularVmSizes"`
90104 } `json:"recommendedVmSizes"`
91105 }
92- if err := json .NewDecoder ( resp . Body ). Decode ( & respObj ); err != nil {
106+ if err := json .Unmarshal ( bodyBytes , & respObj ); err != nil {
93107 return false , fmt .Errorf ("failed to decode Azure service response: %w" , err )
94108 }
95109
96110 available := false
97111 for _ , vm := range respObj .RecommendedVmSizes .RegularVmSizes {
98112 if vm .Name == sku {
99113 available = true
114+ klog .V (2 ).Infof ("SKU %s is available in cluster %s" , sku , cluster .Name )
100115 break
101116 }
102117 }
118+ available := true
103119
104120 return available , nil
105121}
@@ -119,18 +135,18 @@ func extractAzureInfoFromLabels(cluster *clusterv1beta1.MemberCluster) (subscrip
119135
120136// extractCapacityRequirements extracts the capacity value from a PropertySelectorRequirement.
121137// This function is specifically designed for Azure SKU capacity properties that follow the pattern:
122- // "kubernetes.azure.com/vm-size/ {sku}/ capacity"
138+ // "kubernetes.azure.com/vm-size. {sku}. capacity"
123139// Returns the capacity as a resource.Quantity and the SKU name if the requirement is valid,
124140// or an error if the requirement is invalid or not a capacity property.
125141func extractCapacityRequirements (req placementv1beta1.PropertySelectorRequirement ) (* resource.Quantity , string , error ) {
126142 // Extract SKU from the property name
127- // Expected format: "kubernetes.azure.com/vm-size/ {sku}/ capacity"
128- if ! strings .HasSuffix (req .Name , "/ capacity" ) {
143+ // Expected format: "kubernetes.azure.com/vm-size. {sku}. capacity"
144+ if ! strings .HasSuffix (req .Name , ". capacity" ) {
129145 return nil , "" , fmt .Errorf ("invalid Azure SKU capacity property format: %q" , req .Name )
130146 }
131147
132148 // Remove prefix and suffix to get the SKU
133- sku := strings .TrimSuffix (strings .TrimPrefix (req .Name , SkuCapacityPropertyPrefix + "/ " ), "/ capacity" )
149+ sku := strings .TrimSuffix (strings .TrimPrefix (req .Name , SkuCapacityPropertyPrefix + ". " ), ". capacity" )
134150 if sku == "" {
135151 return nil , "" , fmt .Errorf ("cannot extract SKU from property name: %q" , req .Name )
136152 }
0 commit comments