github.com/in4it/ecs-deploy@v0.0.42-0.20240508120354-ed77ff16df25/provider/ecs/appmesh.go (about)

     1  package ecs
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/aws/aws-sdk-go/aws"
     7  	"github.com/aws/aws-sdk-go/aws/session"
     8  	"github.com/aws/aws-sdk-go/service/appmesh"
     9  	"github.com/in4it/ecs-deploy/service"
    10  	"github.com/juju/loggo"
    11  )
    12  
    13  // logging
    14  var appmeshLogger = loggo.GetLogger("appmesh")
    15  
    16  // AppMesh struct
    17  type AppMesh struct {
    18  }
    19  
    20  //AppMeshHealthCheck is a struct that contains the healthcheck for the appmesh
    21  type AppMeshHealthCheck struct {
    22  	HealthyThreshold   int64
    23  	IntervalMillis     int64
    24  	Path               string
    25  	Port               int64
    26  	Protocol           string
    27  	TimeoutMillis      int64
    28  	UnhealthyThreshold int64
    29  }
    30  
    31  func (a *AppMesh) listVirtualNodes(meshName string) (map[string]string, error) {
    32  	svc := appmesh.New(session.New())
    33  	pageNum := 0
    34  	result := make(map[string]string)
    35  	input := &appmesh.ListVirtualNodesInput{
    36  		MeshName: aws.String(meshName),
    37  	}
    38  	err := svc.ListVirtualNodesPages(input,
    39  		func(page *appmesh.ListVirtualNodesOutput, lastPage bool) bool {
    40  			pageNum++
    41  			for _, virtualNode := range page.VirtualNodes {
    42  				result[aws.StringValue(virtualNode.VirtualNodeName)] = aws.StringValue(virtualNode.Arn)
    43  			}
    44  			return pageNum <= 100
    45  		})
    46  	if err != nil {
    47  		appmeshLogger.Errorf(err.Error())
    48  		return result, err
    49  	}
    50  	return result, nil
    51  }
    52  
    53  func (a *AppMesh) listVirtualServices(meshName string) (map[string]string, error) {
    54  	svc := appmesh.New(session.New())
    55  	pageNum := 0
    56  	result := make(map[string]string)
    57  	input := &appmesh.ListVirtualServicesInput{
    58  		MeshName: aws.String(meshName),
    59  	}
    60  	err := svc.ListVirtualServicesPages(input,
    61  		func(page *appmesh.ListVirtualServicesOutput, lastPage bool) bool {
    62  			pageNum++
    63  			for _, virtualNode := range page.VirtualServices {
    64  				result[aws.StringValue(virtualNode.VirtualServiceName)] = aws.StringValue(virtualNode.Arn)
    65  			}
    66  			return pageNum <= 100
    67  		})
    68  	if err != nil {
    69  		appmeshLogger.Errorf(err.Error())
    70  		return result, err
    71  	}
    72  	return result, nil
    73  }
    74  
    75  func (a *AppMesh) listVirtualRouters(meshName string) (map[string]string, error) {
    76  	svc := appmesh.New(session.New())
    77  	pageNum := 0
    78  	result := make(map[string]string)
    79  	input := &appmesh.ListVirtualRoutersInput{
    80  		MeshName: aws.String(meshName),
    81  	}
    82  	err := svc.ListVirtualRoutersPages(input,
    83  		func(page *appmesh.ListVirtualRoutersOutput, lastPage bool) bool {
    84  			pageNum++
    85  			for _, virtualRouter := range page.VirtualRouters {
    86  				result[aws.StringValue(virtualRouter.VirtualRouterName)] = aws.StringValue(virtualRouter.Arn)
    87  			}
    88  			return pageNum <= 100
    89  		})
    90  	if err != nil {
    91  		appmeshLogger.Errorf(err.Error())
    92  		return result, err
    93  	}
    94  	return result, nil
    95  }
    96  
    97  func (a *AppMesh) createVirtualNode(virtualNodeName, virtualNodeDNS, meshName string, servicePort int64, healthcheck AppMeshHealthCheck, backends []string) error {
    98  	var appmeshBackends []*appmesh.Backend
    99  
   100  	for _, backend := range backends {
   101  		appmeshBackends = append(appmeshBackends, &appmesh.Backend{
   102  			VirtualService: &appmesh.VirtualServiceBackend{
   103  				VirtualServiceName: aws.String(backend),
   104  			},
   105  		})
   106  	}
   107  
   108  	svc := appmesh.New(session.New())
   109  	input := &appmesh.CreateVirtualNodeInput{
   110  		MeshName: aws.String(meshName),
   111  		Spec: &appmesh.VirtualNodeSpec{
   112  			Backends: appmeshBackends,
   113  			Listeners: []*appmesh.Listener{
   114  				{
   115  					HealthCheck: &appmesh.HealthCheckPolicy{
   116  						HealthyThreshold:   aws.Int64(healthcheck.HealthyThreshold),
   117  						IntervalMillis:     aws.Int64(healthcheck.IntervalMillis),
   118  						Path:               aws.String(healthcheck.Path),
   119  						Port:               aws.Int64(healthcheck.Port),
   120  						Protocol:           aws.String(healthcheck.Protocol),
   121  						TimeoutMillis:      aws.Int64(healthcheck.TimeoutMillis),
   122  						UnhealthyThreshold: aws.Int64(healthcheck.UnhealthyThreshold),
   123  					},
   124  					PortMapping: &appmesh.PortMapping{
   125  						Port:     aws.Int64(servicePort),
   126  						Protocol: aws.String("http"),
   127  					},
   128  				},
   129  			},
   130  			ServiceDiscovery: &appmesh.ServiceDiscovery{
   131  				Dns: &appmesh.DnsServiceDiscovery{
   132  					Hostname: aws.String(virtualNodeDNS),
   133  				},
   134  			},
   135  		},
   136  		VirtualNodeName: aws.String(virtualNodeName),
   137  	}
   138  
   139  	_, err := svc.CreateVirtualNode(input)
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  func (a *AppMesh) updateVirtualNode(virtualNodeName, virtualNodeDNS, meshName string, servicePort int64, healthcheck AppMeshHealthCheck, backends []string) error {
   148  	var appmeshBackends []*appmesh.Backend
   149  
   150  	for _, backend := range backends {
   151  		appmeshBackends = append(appmeshBackends, &appmesh.Backend{
   152  			VirtualService: &appmesh.VirtualServiceBackend{
   153  				VirtualServiceName: aws.String(backend),
   154  			},
   155  		})
   156  	}
   157  
   158  	svc := appmesh.New(session.New())
   159  	input := &appmesh.UpdateVirtualNodeInput{
   160  		MeshName: aws.String(meshName),
   161  		Spec: &appmesh.VirtualNodeSpec{
   162  			Backends: appmeshBackends,
   163  			Listeners: []*appmesh.Listener{
   164  				{
   165  					HealthCheck: &appmesh.HealthCheckPolicy{
   166  						HealthyThreshold:   aws.Int64(healthcheck.HealthyThreshold),
   167  						IntervalMillis:     aws.Int64(healthcheck.IntervalMillis),
   168  						Path:               aws.String(healthcheck.Path),
   169  						Port:               aws.Int64(healthcheck.Port),
   170  						Protocol:           aws.String(healthcheck.Protocol),
   171  						TimeoutMillis:      aws.Int64(healthcheck.TimeoutMillis),
   172  						UnhealthyThreshold: aws.Int64(healthcheck.UnhealthyThreshold),
   173  					},
   174  					PortMapping: &appmesh.PortMapping{
   175  						Port:     aws.Int64(servicePort),
   176  						Protocol: aws.String("http"),
   177  					},
   178  				},
   179  			},
   180  			ServiceDiscovery: &appmesh.ServiceDiscovery{
   181  				Dns: &appmesh.DnsServiceDiscovery{
   182  					Hostname: aws.String(virtualNodeDNS),
   183  				},
   184  			},
   185  		},
   186  		VirtualNodeName: aws.String(virtualNodeName),
   187  	}
   188  
   189  	_, err := svc.UpdateVirtualNode(input)
   190  	if err != nil {
   191  		return err
   192  	}
   193  
   194  	return nil
   195  }
   196  
   197  func (a *AppMesh) createVirtualServiceWithVirtualNode(virtualServiceName, virtualNodeName, meshName string) error {
   198  	svc := appmesh.New(session.New())
   199  	input := &appmesh.CreateVirtualServiceInput{
   200  		MeshName: aws.String(meshName),
   201  		Spec: &appmesh.VirtualServiceSpec{
   202  			Provider: &appmesh.VirtualServiceProvider{
   203  				VirtualNode: &appmesh.VirtualNodeServiceProvider{
   204  					VirtualNodeName: aws.String(virtualNodeName),
   205  				},
   206  			},
   207  		},
   208  		VirtualServiceName: aws.String(virtualServiceName),
   209  	}
   210  
   211  	_, err := svc.CreateVirtualService(input)
   212  	if err != nil {
   213  		return err
   214  	}
   215  
   216  	return nil
   217  }
   218  
   219  func (a *AppMesh) createVirtualServiceWithVirtualRouter(virtualServiceName, virtualRouterName, meshName string) error {
   220  	svc := appmesh.New(session.New())
   221  	input := &appmesh.CreateVirtualServiceInput{
   222  		MeshName: aws.String(meshName),
   223  		Spec: &appmesh.VirtualServiceSpec{
   224  			Provider: &appmesh.VirtualServiceProvider{
   225  				VirtualRouter: &appmesh.VirtualRouterServiceProvider{
   226  					VirtualRouterName: aws.String(virtualRouterName),
   227  				},
   228  			},
   229  		},
   230  		VirtualServiceName: aws.String(virtualServiceName),
   231  	}
   232  
   233  	_, err := svc.CreateVirtualService(input)
   234  	if err != nil {
   235  		return err
   236  	}
   237  
   238  	return nil
   239  }
   240  
   241  func (a *AppMesh) updateVirtualServiceWithVirtualRouter(virtualServiceName, virtualRouterName, meshName string) error {
   242  	svc := appmesh.New(session.New())
   243  	input := &appmesh.UpdateVirtualServiceInput{
   244  		MeshName: aws.String(meshName),
   245  		Spec: &appmesh.VirtualServiceSpec{
   246  			Provider: &appmesh.VirtualServiceProvider{
   247  				VirtualRouter: &appmesh.VirtualRouterServiceProvider{
   248  					VirtualRouterName: aws.String(virtualRouterName),
   249  				},
   250  			},
   251  		},
   252  		VirtualServiceName: aws.String(virtualServiceName),
   253  	}
   254  
   255  	_, err := svc.UpdateVirtualService(input)
   256  	if err != nil {
   257  		return err
   258  	}
   259  
   260  	return nil
   261  }
   262  
   263  func (a *AppMesh) createVirtualRouter(virtualRouterName string, meshName string, servicePort int64) error {
   264  	svc := appmesh.New(session.New())
   265  	input := &appmesh.CreateVirtualRouterInput{
   266  		MeshName: aws.String(meshName),
   267  		Spec: &appmesh.VirtualRouterSpec{
   268  			Listeners: []*appmesh.VirtualRouterListener{
   269  				{
   270  					PortMapping: &appmesh.PortMapping{
   271  						Port:     aws.Int64(servicePort),
   272  						Protocol: aws.String("http"),
   273  					},
   274  				},
   275  			},
   276  		},
   277  		VirtualRouterName: aws.String(virtualRouterName),
   278  	}
   279  
   280  	_, err := svc.CreateVirtualRouter(input)
   281  	if err != nil {
   282  		return err
   283  	}
   284  
   285  	return nil
   286  }
   287  
   288  func (a *AppMesh) createRoute(routeName, virtualRouterName, virtualNodeName, hostname string, mesh service.DeployAppMesh) error {
   289  	perRetryTimeout, err := time.ParseDuration(mesh.RetryPolicy.PerRetryTimeout)
   290  	if err != nil {
   291  		return err
   292  	}
   293  	svc := appmesh.New(session.New())
   294  	input := &appmesh.CreateRouteInput{
   295  		MeshName: aws.String(mesh.Name),
   296  		Spec: &appmesh.RouteSpec{
   297  			HttpRoute: &appmesh.HttpRoute{
   298  				Match: &appmesh.HttpRouteMatch{
   299  					Prefix: aws.String("/"),
   300  					/*Headers: []*appmesh.HttpRouteHeader{
   301  						{
   302  							Name: aws.String("Host"),
   303  							Match: &appmesh.HeaderMatchMethod{
   304  								Exact: aws.String(hostname),
   305  							},
   306  						},
   307  					},*/
   308  				},
   309  				Action: &appmesh.HttpRouteAction{
   310  					WeightedTargets: []*appmesh.WeightedTarget{
   311  						{
   312  							VirtualNode: aws.String(virtualNodeName),
   313  							Weight:      aws.Int64(100),
   314  						},
   315  					},
   316  				},
   317  				RetryPolicy: &appmesh.HttpRetryPolicy{
   318  					HttpRetryEvents: aws.StringSlice(mesh.RetryPolicy.HTTPRetryEvents),
   319  					MaxRetries:      aws.Int64(mesh.RetryPolicy.MaxRetries),
   320  					PerRetryTimeout: &appmesh.Duration{
   321  						Unit:  aws.String("ms"),
   322  						Value: aws.Int64(perRetryTimeout.Milliseconds()),
   323  					},
   324  					TcpRetryEvents: aws.StringSlice(mesh.RetryPolicy.TcpRetryEvents),
   325  				},
   326  			},
   327  			Priority: aws.Int64(100),
   328  		},
   329  		RouteName:         aws.String(routeName),
   330  		VirtualRouterName: aws.String(virtualRouterName),
   331  	}
   332  
   333  	_, err = svc.CreateRoute(input)
   334  	if err != nil {
   335  		return err
   336  	}
   337  
   338  	return nil
   339  }