github.com/aavshr/aws-sdk-go@v1.41.3/aws/endpoints/decode.go (about) 1 package endpoints 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 8 "github.com/aavshr/aws-sdk-go/aws/awserr" 9 ) 10 11 type modelDefinition map[string]json.RawMessage 12 13 // A DecodeModelOptions are the options for how the endpoints model definition 14 // are decoded. 15 type DecodeModelOptions struct { 16 SkipCustomizations bool 17 } 18 19 // Set combines all of the option functions together. 20 func (d *DecodeModelOptions) Set(optFns ...func(*DecodeModelOptions)) { 21 for _, fn := range optFns { 22 fn(d) 23 } 24 } 25 26 // DecodeModel unmarshals a Regions and Endpoint model definition file into 27 // a endpoint Resolver. If the file format is not supported, or an error occurs 28 // when unmarshaling the model an error will be returned. 29 // 30 // Casting the return value of this func to a EnumPartitions will 31 // allow you to get a list of the partitions in the order the endpoints 32 // will be resolved in. 33 // 34 // resolver, err := endpoints.DecodeModel(reader) 35 // 36 // partitions := resolver.(endpoints.EnumPartitions).Partitions() 37 // for _, p := range partitions { 38 // // ... inspect partitions 39 // } 40 func DecodeModel(r io.Reader, optFns ...func(*DecodeModelOptions)) (Resolver, error) { 41 var opts DecodeModelOptions 42 opts.Set(optFns...) 43 44 // Get the version of the partition file to determine what 45 // unmarshaling model to use. 46 modelDef := modelDefinition{} 47 if err := json.NewDecoder(r).Decode(&modelDef); err != nil { 48 return nil, newDecodeModelError("failed to decode endpoints model", err) 49 } 50 51 var version string 52 if b, ok := modelDef["version"]; ok { 53 version = string(b) 54 } else { 55 return nil, newDecodeModelError("endpoints version not found in model", nil) 56 } 57 58 if version == "3" { 59 return decodeV3Endpoints(modelDef, opts) 60 } 61 62 return nil, newDecodeModelError( 63 fmt.Sprintf("endpoints version %s, not supported", version), nil) 64 } 65 66 func decodeV3Endpoints(modelDef modelDefinition, opts DecodeModelOptions) (Resolver, error) { 67 b, ok := modelDef["partitions"] 68 if !ok { 69 return nil, newDecodeModelError("endpoints model missing partitions", nil) 70 } 71 72 ps := partitions{} 73 if err := json.Unmarshal(b, &ps); err != nil { 74 return nil, newDecodeModelError("failed to decode endpoints model", err) 75 } 76 77 if opts.SkipCustomizations { 78 return ps, nil 79 } 80 81 // Customization 82 for i := 0; i < len(ps); i++ { 83 p := &ps[i] 84 custAddS3DualStack(p) 85 custRegionalS3(p) 86 custRmIotDataService(p) 87 custFixAppAutoscalingChina(p) 88 custFixAppAutoscalingUsGov(p) 89 } 90 91 return ps, nil 92 } 93 94 func custAddS3DualStack(p *partition) { 95 if !(p.ID == "aws" || p.ID == "aws-cn" || p.ID == "aws-us-gov") { 96 return 97 } 98 99 custAddDualstack(p, "s3") 100 custAddDualstack(p, "s3-control") 101 } 102 103 func custRegionalS3(p *partition) { 104 if p.ID != "aws" { 105 return 106 } 107 108 service, ok := p.Services["s3"] 109 if !ok { 110 return 111 } 112 113 // If global endpoint already exists no customization needed. 114 if _, ok := service.Endpoints["aws-global"]; ok { 115 return 116 } 117 118 service.PartitionEndpoint = "aws-global" 119 service.Endpoints["us-east-1"] = endpoint{} 120 service.Endpoints["aws-global"] = endpoint{ 121 Hostname: "s3.amazonaws.com", 122 CredentialScope: credentialScope{ 123 Region: "us-east-1", 124 }, 125 } 126 127 p.Services["s3"] = service 128 } 129 130 func custAddDualstack(p *partition, svcName string) { 131 s, ok := p.Services[svcName] 132 if !ok { 133 return 134 } 135 136 s.Defaults.HasDualStack = boxedTrue 137 s.Defaults.DualStackHostname = "{service}.dualstack.{region}.{dnsSuffix}" 138 139 p.Services[svcName] = s 140 } 141 142 func custRmIotDataService(p *partition) { 143 delete(p.Services, "data.iot") 144 } 145 146 func custFixAppAutoscalingChina(p *partition) { 147 if p.ID != "aws-cn" { 148 return 149 } 150 151 const serviceName = "application-autoscaling" 152 s, ok := p.Services[serviceName] 153 if !ok { 154 return 155 } 156 157 const expectHostname = `autoscaling.{region}.amazonaws.com` 158 if e, a := s.Defaults.Hostname, expectHostname; e != a { 159 fmt.Printf("custFixAppAutoscalingChina: ignoring customization, expected %s, got %s\n", e, a) 160 return 161 } 162 163 s.Defaults.Hostname = expectHostname + ".cn" 164 p.Services[serviceName] = s 165 } 166 167 func custFixAppAutoscalingUsGov(p *partition) { 168 if p.ID != "aws-us-gov" { 169 return 170 } 171 172 const serviceName = "application-autoscaling" 173 s, ok := p.Services[serviceName] 174 if !ok { 175 return 176 } 177 178 if a := s.Defaults.CredentialScope.Service; a != "" { 179 fmt.Printf("custFixAppAutoscalingUsGov: ignoring customization, expected empty credential scope service, got %s\n", a) 180 return 181 } 182 183 if a := s.Defaults.Hostname; a != "" { 184 fmt.Printf("custFixAppAutoscalingUsGov: ignoring customization, expected empty hostname, got %s\n", a) 185 return 186 } 187 188 s.Defaults.CredentialScope.Service = "application-autoscaling" 189 s.Defaults.Hostname = "autoscaling.{region}.amazonaws.com" 190 191 p.Services[serviceName] = s 192 } 193 194 type decodeModelError struct { 195 awsError 196 } 197 198 func newDecodeModelError(msg string, err error) decodeModelError { 199 return decodeModelError{ 200 awsError: awserr.New("DecodeEndpointsModelError", msg, err), 201 } 202 }