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  }