aws

package
v1.0.1-0...-5dc2c13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 21, 2018 License: Apache-2.0 Imports: 50 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Provisioned IOPS SSD
	VolumeTypeIO1 = "io1"
	// General Purpose SSD
	VolumeTypeGP2 = "gp2"
	// Cold HDD (sc1)
	VolumeTypeSC1 = "sc1"
	// Throughput Optimized HDD
	VolumeTypeST1 = "st1"
)

AWS volume types

View Source
const (
	MinTotalIOPS = 100
	MaxTotalIOPS = 20000
)

AWS provisioning limits. Source: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html

View Source
const (
	ProxyProtocolPolicyName = "k8s-proxyprotocol-enabled"

	SSLNegotiationPolicyNameFormat = "k8s-SSLNegotiationPolicy-%s"
)
View Source
const (
	// ResourceLifecycleOwned is the value we use when tagging resources to indicate
	// that the resource is considered owned and managed by the cluster,
	// and in particular that the lifecycle is tied to the lifecycle of the cluster.
	ResourceLifecycleOwned = "owned"
	// ResourceLifecycleShared is the value we use when tagging resources to indicate
	// that the resource is shared between multiple clusters, and should not be destroyed
	// if the cluster is destroyed.
	ResourceLifecycleShared = "shared"
)
View Source
const DefaultVolumeType = "gp2"

DefaultVolumeType specifies which storage to use for newly created Volumes TODO: Remove when user/admin can configure volume types and thus we don't need hardcoded defaults.

View Source
const MaxReadThenCreateRetries = 30

MaxReadThenCreateRetries sets the maximum number of attempts we will make when we read to see if something exists and then try to create it if we didn't find it. This can fail once in a consistent system if done in parallel In an eventually consistent system, it could fail unboundedly

View Source
const NLBClientRuleDescription = "kubernetes.io/rule/nlb/client"

NLBClientRuleDescription is the comment used on a security group rule to indicate that it is used for client traffic

View Source
const NLBHealthCheckRuleDescription = "kubernetes.io/rule/nlb/health"

NLBHealthCheckRuleDescription is the comment used on a security group rule to indicate that it is used for health checks

View Source
const NLBMtuDiscoveryRuleDescription = "kubernetes.io/rule/nlb/mtu"

NLBMtuDiscoveryRuleDescription is the comment used on a security group rule to indicate that it is used for mtu discovery

View Source
const ProviderName = "aws"

ProviderName is the name of this cloud provider.

View Source
const ServiceAnnotationLoadBalancerAccessLogEmitInterval = "service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval"

ServiceAnnotationLoadBalancerAccessLogEmitInterval is the annotation used to specify access log emit interval.

View Source
const ServiceAnnotationLoadBalancerAccessLogEnabled = "service.beta.kubernetes.io/aws-load-balancer-access-log-enabled"

ServiceAnnotationLoadBalancerAccessLogEnabled is the annotation used on the service to enable or disable access logs.

View Source
const ServiceAnnotationLoadBalancerAccessLogS3BucketName = "service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name"

ServiceAnnotationLoadBalancerAccessLogS3BucketName is the annotation used to specify access log s3 bucket name.

View Source
const ServiceAnnotationLoadBalancerAccessLogS3BucketPrefix = "service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix"

ServiceAnnotationLoadBalancerAccessLogS3BucketPrefix is the annotation used to specify access log s3 bucket prefix.

View Source
const ServiceAnnotationLoadBalancerAdditionalTags = "service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags"

ServiceAnnotationLoadBalancerAdditionalTags is the annotation used on the service to specify a comma-separated list of key-value pairs which will be recorded as additional tags in the ELB. For example: "Key1=Val1,Key2=Val2,KeyNoVal1=,KeyNoVal2"

View Source
const ServiceAnnotationLoadBalancerBEProtocol = "service.beta.kubernetes.io/aws-load-balancer-backend-protocol"

ServiceAnnotationLoadBalancerBEProtocol is the annotation used on the service to specify the protocol spoken by the backend (pod) behind a listener. If `http` (default) or `https`, an HTTPS listener that terminates the

connection and parses headers is created.

If set to `ssl` or `tcp`, a "raw" SSL listener is used. If set to `http` and `aws-load-balancer-ssl-cert` is not used then a HTTP listener is used.

View Source
const ServiceAnnotationLoadBalancerCertificate = "service.beta.kubernetes.io/aws-load-balancer-ssl-cert"

ServiceAnnotationLoadBalancerCertificate is the annotation used on the service to request a secure listener. Value is a valid certificate ARN. For more, see http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html CertARN is an IAM or CM certificate ARN, e.g. arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012

View Source
const ServiceAnnotationLoadBalancerConnectionDrainingEnabled = "service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled"

ServiceAnnotationLoadBalancerConnectionDrainingEnabled is the annnotation used on the service to enable or disable connection draining.

View Source
const ServiceAnnotationLoadBalancerConnectionDrainingTimeout = "service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout"

ServiceAnnotationLoadBalancerConnectionDrainingTimeout is the annotation used on the service to specify a connection draining timeout.

View Source
const ServiceAnnotationLoadBalancerConnectionIdleTimeout = "service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout"

ServiceAnnotationLoadBalancerConnectionIdleTimeout is the annotation used on the service to specify the idle connection timeout.

View Source
const ServiceAnnotationLoadBalancerCrossZoneLoadBalancingEnabled = "service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled"

ServiceAnnotationLoadBalancerCrossZoneLoadBalancingEnabled is the annotation used on the service to enable or disable cross-zone load balancing.

View Source
const ServiceAnnotationLoadBalancerExtraSecurityGroups = "service.beta.kubernetes.io/aws-load-balancer-extra-security-groups"

ServiceAnnotationLoadBalancerExtraSecurityGroups is the annotation used one the service to specify additional security groups to be added to ELB created

View Source
const ServiceAnnotationLoadBalancerHCHealthyThreshold = "service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold"

ServiceAnnotationLoadBalancerHCHealthyThreshold is the annotation used on the service to specify the number of successive successful health checks required for a backend to be considered healthy for traffic.

View Source
const ServiceAnnotationLoadBalancerHCInterval = "service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval"

ServiceAnnotationLoadBalancerHCInterval is the annotation used on the service to specify, in seconds, the interval between health checks.

View Source
const ServiceAnnotationLoadBalancerHCTimeout = "service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout"

ServiceAnnotationLoadBalancerHCTimeout is the annotation used on the service to specify, in seconds, how long to wait before marking a health check as failed.

View Source
const ServiceAnnotationLoadBalancerHCUnhealthyThreshold = "service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold"

ServiceAnnotationLoadBalancerHCUnhealthyThreshold is the annotation used on the service to specify the number of unsuccessful health checks required for a backend to be considered unhealthy for traffic

View Source
const ServiceAnnotationLoadBalancerInternal = "service.beta.kubernetes.io/aws-load-balancer-internal"

ServiceAnnotationLoadBalancerInternal is the annotation used on the service to indicate that we want an internal ELB.

View Source
const ServiceAnnotationLoadBalancerProxyProtocol = "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol"

ServiceAnnotationLoadBalancerProxyProtocol is the annotation used on the service to enable the proxy protocol on an ELB. Right now we only accept the value "*" which means enable the proxy protocol on all ELB backends. In the future we could adjust this to allow setting the proxy protocol only on certain backends.

View Source
const ServiceAnnotationLoadBalancerSSLNegotiationPolicy = "service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy"

ServiceAnnotationLoadBalancerSSLNegotiationPolicy is the annotation used on the service to specify a SSL negotiation settings for the HTTPS/SSL listeners of your load balancer. Defaults to AWS's default

View Source
const ServiceAnnotationLoadBalancerSSLPorts = "service.beta.kubernetes.io/aws-load-balancer-ssl-ports"

ServiceAnnotationLoadBalancerSSLPorts is the annotation used on the service to specify a comma-separated list of ports that will use SSL/HTTPS listeners. Defaults to '*' (all).

View Source
const ServiceAnnotationLoadBalancerType = "service.beta.kubernetes.io/aws-load-balancer-type"

ServiceAnnotationLoadBalancerType is the annotation used on the service to indicate what type of Load Balancer we want. Right now, the only accepted value is "nlb"

View Source
const TagNameKubernetesClusterLegacy = "KubernetesCluster"

TagNameKubernetesClusterLegacy is the legacy tag name we use to differentiate multiple logically independent clusters running in the same AZ. The problem with it was that it did not allow shared resources.

View Source
const TagNameKubernetesClusterPrefix = "kubernetes.io/cluster/"

TagNameKubernetesClusterPrefix is the tag name we use to differentiate multiple logically independent clusters running in the same AZ. The tag key = TagNameKubernetesClusterPrefix + clusterID The tag value is an ownership value

View Source
const TagNameKubernetesService = "kubernetes.io/service-name"

TagNameKubernetesService is the tag name we use to differentiate multiple services. Used currently for ELBs only.

View Source
const TagNameSubnetInternalELB = "kubernetes.io/role/internal-elb"

TagNameSubnetInternalELB is the tag name used on a subnet to designate that it should be used for internal ELBs

View Source
const TagNameSubnetPublicELB = "kubernetes.io/role/elb"

TagNameSubnetPublicELB is the tag name used on a subnet to designate that it should be used for internet ELBs

Variables

View Source
var WellKnownRegions = [...]string{

	"ap-northeast-1",
	"ap-northeast-2",
	"ap-south-1",
	"ap-southeast-1",
	"ap-southeast-2",
	"ca-central-1",
	"eu-central-1",
	"eu-west-1",
	"eu-west-2",
	"sa-east-1",
	"us-east-1",
	"us-east-2",
	"us-west-1",
	"us-west-2",

	"cn-north-1",
	"us-gov-west-1",
}

WellKnownRegions is the complete list of regions known to the AWS cloudprovider and credentialprovider.

Functions

func GetAWSVolumeID

func GetAWSVolumeID(kubeVolumeID string) (string, error)

func RecognizeRegion

func RecognizeRegion(region string)

RecognizeRegion is called for each AWS region we know about. It currently registers a credential provider for that region. There are two paths to discovering a region:

  • we hard-code some well-known regions
  • if a region is discovered from instance metadata, we add that

func RecognizeWellKnownRegions

func RecognizeWellKnownRegions()

RecognizeWellKnownRegions calls RecognizeRegion on each WellKnownRegion

func ResizeInstanceGroup

func ResizeInstanceGroup(asg ASG, instanceGroupName string, size int) error

ResizeInstanceGroup sets the size of the specificed instancegroup Exported so it can be used by the e2e tests, which don't want to instantiate a full cloudprovider.

Types

type ASG

ASG is a simple pass-through of the Autoscaling client interface, which allows for testing.

type Backoff

type Backoff struct {
	// contains filtered or unexported fields
}

Backoff manages a backoff that varies based on the recently observed failures

func (*Backoff) ComputeDelayForRequest

func (b *Backoff) ComputeDelayForRequest(now time.Time) time.Duration

Computes the delay required for a request, also updating internal state to count this request

func (*Backoff) ReportError

func (b *Backoff) ReportError()

Called when we observe a throttling error

type Cloud

type Cloud struct {
	// contains filtered or unexported fields
}

Cloud is an implementation of Interface, LoadBalancer and Instances for Amazon Web Services.

func (*Cloud) AddSSHKeyToAllInstances

func (c *Cloud) AddSSHKeyToAllInstances(ctx context.Context, user string, keyData []byte) error

AddSSHKeyToAllInstances is currently not implemented.

func (*Cloud) AttachDisk

func (c *Cloud) AttachDisk(diskName KubernetesVolumeID, nodeName types.NodeName) (string, error)

AttachDisk implements Volumes.AttachDisk

func (*Cloud) Clusters

func (c *Cloud) Clusters() (cloudprovider.Clusters, bool)

Clusters returns the list of clusters.

func (*Cloud) CreateDisk

func (c *Cloud) CreateDisk(volumeOptions *VolumeOptions) (KubernetesVolumeID, error)

CreateDisk implements Volumes.CreateDisk

func (*Cloud) CreateRoute

func (c *Cloud) CreateRoute(ctx context.Context, clusterName string, nameHint string, route *cloudprovider.Route) error

CreateRoute implements Routes.CreateRoute Create the described route

func (*Cloud) CurrentNodeName

func (c *Cloud) CurrentNodeName(ctx context.Context, hostname string) (types.NodeName, error)

CurrentNodeName returns the name of the current node

func (*Cloud) DeleteDisk

func (c *Cloud) DeleteDisk(volumeName KubernetesVolumeID) (bool, error)

DeleteDisk implements Volumes.DeleteDisk

func (*Cloud) DeleteRoute

func (c *Cloud) DeleteRoute(ctx context.Context, clusterName string, route *cloudprovider.Route) error

DeleteRoute implements Routes.DeleteRoute Delete the specified route

func (*Cloud) DescribeInstanceGroup

func (c *Cloud) DescribeInstanceGroup(instanceGroupName string) (InstanceGroupInfo, error)

Implement InstanceGroups.DescribeInstanceGroup Queries the cloud provider for information about the specified instance group

func (*Cloud) DetachDisk

func (c *Cloud) DetachDisk(diskName KubernetesVolumeID, nodeName types.NodeName) (string, error)

DetachDisk implements Volumes.DetachDisk

func (*Cloud) DiskIsAttached

func (c *Cloud) DiskIsAttached(diskName KubernetesVolumeID, nodeName types.NodeName) (bool, error)

DiskIsAttached implements Volumes.DiskIsAttached

func (*Cloud) DisksAreAttached

func (c *Cloud) DisksAreAttached(nodeDisks map[types.NodeName][]KubernetesVolumeID) (map[types.NodeName]map[KubernetesVolumeID]bool, error)

func (*Cloud) EnsureLoadBalancer

func (c *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, apiService *v1.Service, nodes []*v1.Node) (*v1.LoadBalancerStatus, error)

EnsureLoadBalancer implements LoadBalancer.EnsureLoadBalancer

func (*Cloud) EnsureLoadBalancerDeleted

func (c *Cloud) EnsureLoadBalancerDeleted(ctx context.Context, clusterName string, service *v1.Service) error

EnsureLoadBalancerDeleted implements LoadBalancer.EnsureLoadBalancerDeleted.

func (*Cloud) GetCandidateZonesForDynamicVolume

func (c *Cloud) GetCandidateZonesForDynamicVolume() (sets.String, error)

GetCandidateZonesForDynamicVolume retrieves a list of all the zones in which nodes are running It currently involves querying all instances

func (*Cloud) GetDiskPath

func (c *Cloud) GetDiskPath(volumeName KubernetesVolumeID) (string, error)

GetDiskPath implements Volumes.GetDiskPath

func (*Cloud) GetLabelsForVolume

func (c *Cloud) GetLabelsForVolume(ctx context.Context, pv *v1.PersistentVolume) (map[string]string, error)

func (*Cloud) GetLoadBalancer

func (c *Cloud) GetLoadBalancer(ctx context.Context, clusterName string, service *v1.Service) (*v1.LoadBalancerStatus, bool, error)

GetLoadBalancer is an implementation of LoadBalancer.GetLoadBalancer

func (*Cloud) GetLoadBalancerName

func (c *Cloud) GetLoadBalancerName(ctx context.Context, clusterName string, service *v1.Service) string

GetLoadBalancerName is an implementation of LoadBalancer.GetLoadBalancerName

func (*Cloud) GetVolumeLabels

func (c *Cloud) GetVolumeLabels(volumeName KubernetesVolumeID) (map[string]string, error)

GetVolumeLabels implements Volumes.GetVolumeLabels

func (*Cloud) GetZone

func (c *Cloud) GetZone(ctx context.Context) (cloudprovider.Zone, error)

GetZone implements Zones.GetZone

func (*Cloud) GetZoneByNodeName

func (c *Cloud) GetZoneByNodeName(ctx context.Context, nodeName types.NodeName) (cloudprovider.Zone, error)

GetZoneByNodeName implements Zones.GetZoneByNodeName This is particularly useful in external cloud providers where the kubelet does not initialize node data.

func (*Cloud) GetZoneByProviderID

func (c *Cloud) GetZoneByProviderID(ctx context.Context, providerID string) (cloudprovider.Zone, error)

GetZoneByProviderID implements Zones.GetZoneByProviderID This is particularly useful in external cloud providers where the kubelet does not initialize node data.

func (*Cloud) HasClusterID

func (c *Cloud) HasClusterID() bool

HasClusterID returns true if the cluster has a clusterID

func (*Cloud) Initialize

func (c *Cloud) Initialize(clientBuilder controller.ControllerClientBuilder)

Initialize passes a Kubernetes clientBuilder interface to the cloud provider

func (*Cloud) InstanceExistsByProviderID

func (c *Cloud) InstanceExistsByProviderID(ctx context.Context, providerID string) (bool, error)

InstanceExistsByProviderID returns true if the instance with the given provider id still exists. If false is returned with no error, the instance will be immediately deleted by the cloud controller manager.

func (*Cloud) InstanceID

func (c *Cloud) InstanceID(ctx context.Context, nodeName types.NodeName) (string, error)

InstanceID returns the cloud provider ID of the node with the specified nodeName.

func (*Cloud) InstanceShutdownByProviderID

func (c *Cloud) InstanceShutdownByProviderID(ctx context.Context, providerID string) (bool, error)

InstanceShutdownByProviderID returns true if the instance is in safe state to detach volumes

func (*Cloud) InstanceType

func (c *Cloud) InstanceType(ctx context.Context, nodeName types.NodeName) (string, error)

InstanceType returns the type of the node with the specified nodeName.

func (*Cloud) InstanceTypeByProviderID

func (c *Cloud) InstanceTypeByProviderID(ctx context.Context, providerID string) (string, error)

InstanceTypeByProviderID returns the cloudprovider instance type of the node with the specified unique providerID This method will not be called from the node that is requesting this ID. i.e. metadata service and other local methods cannot be used here

func (*Cloud) Instances

func (c *Cloud) Instances() (cloudprovider.Instances, bool)

Instances returns an implementation of Instances for Amazon Web Services.

func (*Cloud) ListRoutes

func (c *Cloud) ListRoutes(ctx context.Context, clusterName string) ([]*cloudprovider.Route, error)

ListRoutes implements Routes.ListRoutes List all routes that match the filter

func (*Cloud) LoadBalancer

func (c *Cloud) LoadBalancer() (cloudprovider.LoadBalancer, bool)

LoadBalancer returns an implementation of LoadBalancer for Amazon Web Services.

func (*Cloud) NodeAddresses

func (c *Cloud) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error)

NodeAddresses is an implementation of Instances.NodeAddresses.

func (*Cloud) NodeAddressesByProviderID

func (c *Cloud) NodeAddressesByProviderID(ctx context.Context, providerID string) ([]v1.NodeAddress, error)

NodeAddressesByProviderID returns the node addresses of an instances with the specified unique providerID This method will not be called from the node that is requesting this ID. i.e. metadata service and other local methods cannot be used here

func (*Cloud) ProviderName

func (c *Cloud) ProviderName() string

ProviderName returns the cloud provider ID.

func (*Cloud) ResizeDisk

func (c *Cloud) ResizeDisk(
	diskName KubernetesVolumeID,
	oldSize resource.Quantity,
	newSize resource.Quantity) (resource.Quantity, error)

func (*Cloud) ResizeInstanceGroup

func (c *Cloud) ResizeInstanceGroup(instanceGroupName string, size int) error

Implement InstanceGroups.ResizeInstanceGroup Set the size to the fixed size

func (*Cloud) Routes

func (c *Cloud) Routes() (cloudprovider.Routes, bool)

Routes returns an implementation of Routes for Amazon Web Services.

func (*Cloud) UpdateLoadBalancer

func (c *Cloud) UpdateLoadBalancer(ctx context.Context, clusterName string, service *v1.Service, nodes []*v1.Node) error

UpdateLoadBalancer implements LoadBalancer.UpdateLoadBalancer

func (*Cloud) Zones

func (c *Cloud) Zones() (cloudprovider.Zones, bool)

Zones returns an implementation of Zones for Amazon Web Services.

type CloudConfig

type CloudConfig struct {
	Global struct {
		// TODO: Is there any use for this?  We can get it from the instance metadata service
		// Maybe if we're not running on AWS, e.g. bootstrap; for now it is not very useful
		Zone string

		// The AWS VPC flag enables the possibility to run the master components
		// on a different aws account, on a different cloud provider or on-premises.
		// If the flag is set also the KubernetesClusterTag must be provided
		VPC string
		// SubnetID enables using a specific subnet to use for ELB's
		SubnetID string
		// RouteTableID enables using a specific RouteTable
		RouteTableID string

		// RoleARN is the IAM role to assume when interaction with AWS APIs.
		RoleARN string

		// KubernetesClusterTag is the legacy cluster id we'll use to identify our cluster resources
		KubernetesClusterTag string
		// KubernetesClusterID is the cluster id we'll use to identify our cluster resources
		KubernetesClusterID string

		//The aws provider creates an inbound rule per load balancer on the node security
		//group. However, this can run into the AWS security group rule limit of 50 if
		//many LoadBalancers are created.
		//
		//This flag disables the automatic ingress creation. It requires that the user
		//has setup a rule that allows inbound traffic on kubelet ports from the
		//local VPC subnet (so load balancers can access it). E.g. 10.82.0.0/16 30000-32000.
		DisableSecurityGroupIngress bool

		//AWS has a hard limit of 500 security groups. For large clusters creating a security group for each ELB
		//can cause the max number of security groups to be reached. If this is set instead of creating a new
		//Security group for each ELB this security group will be used instead.
		ElbSecurityGroup string

		//During the instantiation of an new AWS cloud provider, the detected region
		//is validated against a known set of regions.
		//
		//In a non-standard, AWS like environment (e.g. Eucalyptus), this check may
		//be undesirable.  Setting this to true will disable the check and provide
		//a warning that the check was skipped.  Please note that this is an
		//experimental feature and work-in-progress for the moment.  If you find
		//yourself in an non-AWS cloud and open an issue, please indicate that in the
		//issue body.
		DisableStrictZoneCheck bool
	}
}

CloudConfig wraps the settings for the AWS cloud provider.

type CrossRequestRetryDelay

type CrossRequestRetryDelay struct {
	// contains filtered or unexported fields
}

CrossRequestRetryDelay inserts delays before AWS calls, when we are observing RequestLimitExceeded errors Note that we share a CrossRequestRetryDelay across multiple AWS requests; this is a process-wide back-off, whereas the aws-sdk-go implements a per-request exponential backoff/retry

func NewCrossRequestRetryDelay

func NewCrossRequestRetryDelay() *CrossRequestRetryDelay

Create a new CrossRequestRetryDelay

func (*CrossRequestRetryDelay) AfterRetry

func (c *CrossRequestRetryDelay) AfterRetry(r *request.Request)

Added to the AfterRetry chain; called after any error

func (*CrossRequestRetryDelay) BeforeSign

func (c *CrossRequestRetryDelay) BeforeSign(r *request.Request)

Added to the Sign chain; called before each request

type DeviceAllocator

type DeviceAllocator interface {
	// GetNext returns a free device name or error when there is no free device
	// name. Only the device suffix is returned, e.g. "ba" for "/dev/xvdba".
	// It's up to the called to add appropriate "/dev/sd" or "/dev/xvd" prefix.
	GetNext(existingDevices ExistingDevices) (mountDevice, error)

	// Deprioritize the device so as it can't be used immediately again
	Deprioritize(mountDevice)

	// Lock the deviceAllocator
	Lock()

	// Unlock the deviceAllocator
	Unlock()
}

On AWS, we should assign new (not yet used) device names to attached volumes. If we reuse a previously used name, we may get the volume "attaching" forever, see https://aws.amazon.com/premiumsupport/knowledge-center/ebs-stuck-attaching/. DeviceAllocator finds available device name, taking into account already assigned device names from ExistingDevices map. It tries to find the next device name to the previously assigned one (from previous DeviceAllocator call), so all available device names are used eventually and it minimizes device name reuse. All these allocations are in-memory, nothing is written to / read from /dev directory.

func NewDeviceAllocator

func NewDeviceAllocator() DeviceAllocator

Allocates device names according to scheme ba..bz, ca..cz it moves along the ring and always picks next device until device list is exhausted.

type EC2

type EC2 interface {
	// Query EC2 for instances matching the filter
	DescribeInstances(request *ec2.DescribeInstancesInput) ([]*ec2.Instance, error)

	// Attach a volume to an instance
	AttachVolume(*ec2.AttachVolumeInput) (*ec2.VolumeAttachment, error)
	// Detach a volume from an instance it is attached to
	DetachVolume(request *ec2.DetachVolumeInput) (resp *ec2.VolumeAttachment, err error)
	// Lists volumes
	DescribeVolumes(request *ec2.DescribeVolumesInput) ([]*ec2.Volume, error)
	// Create an EBS volume
	CreateVolume(request *ec2.CreateVolumeInput) (resp *ec2.Volume, err error)
	// Delete an EBS volume
	DeleteVolume(*ec2.DeleteVolumeInput) (*ec2.DeleteVolumeOutput, error)

	ModifyVolume(*ec2.ModifyVolumeInput) (*ec2.ModifyVolumeOutput, error)

	DescribeVolumeModifications(*ec2.DescribeVolumesModificationsInput) ([]*ec2.VolumeModification, error)

	DescribeSecurityGroups(request *ec2.DescribeSecurityGroupsInput) ([]*ec2.SecurityGroup, error)

	CreateSecurityGroup(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error)
	DeleteSecurityGroup(request *ec2.DeleteSecurityGroupInput) (*ec2.DeleteSecurityGroupOutput, error)

	AuthorizeSecurityGroupIngress(*ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error)
	RevokeSecurityGroupIngress(*ec2.RevokeSecurityGroupIngressInput) (*ec2.RevokeSecurityGroupIngressOutput, error)

	DescribeSubnets(*ec2.DescribeSubnetsInput) ([]*ec2.Subnet, error)

	CreateTags(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error)

	DescribeRouteTables(request *ec2.DescribeRouteTablesInput) ([]*ec2.RouteTable, error)
	CreateRoute(request *ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error)
	DeleteRoute(request *ec2.DeleteRouteInput) (*ec2.DeleteRouteOutput, error)

	ModifyInstanceAttribute(request *ec2.ModifyInstanceAttributeInput) (*ec2.ModifyInstanceAttributeOutput, error)

	DescribeVpcs(input *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error)
}

EC2 is an abstraction over AWS', to allow mocking/other implementations Note that the DescribeX functions return a list, so callers don't need to deal with paging TODO: Should we rename this to AWS (EBS & ELB are not technically part of EC2)

type EC2Metadata

type EC2Metadata interface {
	// Query the EC2 metadata service (used to discover instance-id etc)
	GetMetadata(path string) (string, error)
}

EC2Metadata is an abstraction over the AWS metadata service.

type ELB

type ELB interface {
	CreateLoadBalancer(*elb.CreateLoadBalancerInput) (*elb.CreateLoadBalancerOutput, error)
	DeleteLoadBalancer(*elb.DeleteLoadBalancerInput) (*elb.DeleteLoadBalancerOutput, error)
	DescribeLoadBalancers(*elb.DescribeLoadBalancersInput) (*elb.DescribeLoadBalancersOutput, error)
	AddTags(*elb.AddTagsInput) (*elb.AddTagsOutput, error)
	RegisterInstancesWithLoadBalancer(*elb.RegisterInstancesWithLoadBalancerInput) (*elb.RegisterInstancesWithLoadBalancerOutput, error)
	DeregisterInstancesFromLoadBalancer(*elb.DeregisterInstancesFromLoadBalancerInput) (*elb.DeregisterInstancesFromLoadBalancerOutput, error)
	CreateLoadBalancerPolicy(*elb.CreateLoadBalancerPolicyInput) (*elb.CreateLoadBalancerPolicyOutput, error)
	SetLoadBalancerPoliciesForBackendServer(*elb.SetLoadBalancerPoliciesForBackendServerInput) (*elb.SetLoadBalancerPoliciesForBackendServerOutput, error)
	SetLoadBalancerPoliciesOfListener(input *elb.SetLoadBalancerPoliciesOfListenerInput) (*elb.SetLoadBalancerPoliciesOfListenerOutput, error)
	DescribeLoadBalancerPolicies(input *elb.DescribeLoadBalancerPoliciesInput) (*elb.DescribeLoadBalancerPoliciesOutput, error)

	DetachLoadBalancerFromSubnets(*elb.DetachLoadBalancerFromSubnetsInput) (*elb.DetachLoadBalancerFromSubnetsOutput, error)
	AttachLoadBalancerToSubnets(*elb.AttachLoadBalancerToSubnetsInput) (*elb.AttachLoadBalancerToSubnetsOutput, error)

	CreateLoadBalancerListeners(*elb.CreateLoadBalancerListenersInput) (*elb.CreateLoadBalancerListenersOutput, error)
	DeleteLoadBalancerListeners(*elb.DeleteLoadBalancerListenersInput) (*elb.DeleteLoadBalancerListenersOutput, error)

	ApplySecurityGroupsToLoadBalancer(*elb.ApplySecurityGroupsToLoadBalancerInput) (*elb.ApplySecurityGroupsToLoadBalancerOutput, error)

	ConfigureHealthCheck(*elb.ConfigureHealthCheckInput) (*elb.ConfigureHealthCheckOutput, error)

	DescribeLoadBalancerAttributes(*elb.DescribeLoadBalancerAttributesInput) (*elb.DescribeLoadBalancerAttributesOutput, error)
	ModifyLoadBalancerAttributes(*elb.ModifyLoadBalancerAttributesInput) (*elb.ModifyLoadBalancerAttributesOutput, error)
}

ELB is a simple pass-through of AWS' ELB client interface, which allows for testing

type ELBV2

type ELBV2 interface {
	AddTags(input *elbv2.AddTagsInput) (*elbv2.AddTagsOutput, error)

	CreateLoadBalancer(*elbv2.CreateLoadBalancerInput) (*elbv2.CreateLoadBalancerOutput, error)
	DescribeLoadBalancers(*elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error)
	DeleteLoadBalancer(*elbv2.DeleteLoadBalancerInput) (*elbv2.DeleteLoadBalancerOutput, error)

	ModifyLoadBalancerAttributes(*elbv2.ModifyLoadBalancerAttributesInput) (*elbv2.ModifyLoadBalancerAttributesOutput, error)
	DescribeLoadBalancerAttributes(*elbv2.DescribeLoadBalancerAttributesInput) (*elbv2.DescribeLoadBalancerAttributesOutput, error)

	CreateTargetGroup(*elbv2.CreateTargetGroupInput) (*elbv2.CreateTargetGroupOutput, error)
	DescribeTargetGroups(*elbv2.DescribeTargetGroupsInput) (*elbv2.DescribeTargetGroupsOutput, error)
	ModifyTargetGroup(*elbv2.ModifyTargetGroupInput) (*elbv2.ModifyTargetGroupOutput, error)
	DeleteTargetGroup(*elbv2.DeleteTargetGroupInput) (*elbv2.DeleteTargetGroupOutput, error)

	DescribeTargetHealth(input *elbv2.DescribeTargetHealthInput) (*elbv2.DescribeTargetHealthOutput, error)

	DescribeTargetGroupAttributes(*elbv2.DescribeTargetGroupAttributesInput) (*elbv2.DescribeTargetGroupAttributesOutput, error)
	ModifyTargetGroupAttributes(*elbv2.ModifyTargetGroupAttributesInput) (*elbv2.ModifyTargetGroupAttributesOutput, error)

	RegisterTargets(*elbv2.RegisterTargetsInput) (*elbv2.RegisterTargetsOutput, error)
	DeregisterTargets(*elbv2.DeregisterTargetsInput) (*elbv2.DeregisterTargetsOutput, error)

	CreateListener(*elbv2.CreateListenerInput) (*elbv2.CreateListenerOutput, error)
	DescribeListeners(*elbv2.DescribeListenersInput) (*elbv2.DescribeListenersOutput, error)
	DeleteListener(*elbv2.DeleteListenerInput) (*elbv2.DeleteListenerOutput, error)
	ModifyListener(*elbv2.ModifyListenerInput) (*elbv2.ModifyListenerOutput, error)

	WaitUntilLoadBalancersDeleted(*elbv2.DescribeLoadBalancersInput) error
}

ELBV2 is a simple pass-through of AWS' ELBV2 client interface, which allows for testing

type ExistingDevices

type ExistingDevices map[mountDevice]awsVolumeID

ExistingDevices is a map of assigned devices. Presence of a key with a device name in the map means that the device is allocated. Value is irrelevant and can be used for anything that DeviceAllocator user wants. Only the relevant part of device name should be in the map, e.g. "ba" for "/dev/xvdba".

type FakeASG

type FakeASG struct {
	// contains filtered or unexported fields
}

type FakeAWSServices

type FakeAWSServices struct {
	// contains filtered or unexported fields
}

func NewFakeAWSServices

func NewFakeAWSServices(clusterId string) *FakeAWSServices

func (*FakeAWSServices) Autoscaling

func (s *FakeAWSServices) Autoscaling(region string) (ASG, error)

func (*FakeAWSServices) Compute

func (s *FakeAWSServices) Compute(region string) (EC2, error)

func (*FakeAWSServices) KeyManagement

func (s *FakeAWSServices) KeyManagement(region string) (KMS, error)

func (*FakeAWSServices) LoadBalancing

func (s *FakeAWSServices) LoadBalancing(region string) (ELB, error)

func (*FakeAWSServices) LoadBalancingV2

func (s *FakeAWSServices) LoadBalancingV2(region string) (ELBV2, error)

func (*FakeAWSServices) Metadata

func (s *FakeAWSServices) Metadata() (EC2Metadata, error)

func (*FakeAWSServices) WithAz

func (s *FakeAWSServices) WithAz(az string) *FakeAWSServices

type FakeEC2

type FakeEC2 interface {
	EC2
	CreateSubnet(*ec2.Subnet) (*ec2.CreateSubnetOutput, error)
	RemoveSubnets()
	CreateRouteTable(*ec2.RouteTable) (*ec2.CreateRouteTableOutput, error)
	RemoveRouteTables()
}

type FakeEC2Impl

type FakeEC2Impl struct {
	Subnets                  []*ec2.Subnet
	DescribeSubnetsInput     *ec2.DescribeSubnetsInput
	RouteTables              []*ec2.RouteTable
	DescribeRouteTablesInput *ec2.DescribeRouteTablesInput
	// contains filtered or unexported fields
}

func (*FakeEC2Impl) AttachVolume

func (ec2i *FakeEC2Impl) AttachVolume(request *ec2.AttachVolumeInput) (resp *ec2.VolumeAttachment, err error)

func (*FakeEC2Impl) CreateRoute

func (ec2i *FakeEC2Impl) CreateRoute(request *ec2.CreateRouteInput) (*ec2.CreateRouteOutput, error)

func (*FakeEC2Impl) CreateRouteTable

func (ec2i *FakeEC2Impl) CreateRouteTable(request *ec2.RouteTable) (*ec2.CreateRouteTableOutput, error)

func (*FakeEC2Impl) CreateSecurityGroup

func (*FakeEC2Impl) CreateSubnet

func (ec2i *FakeEC2Impl) CreateSubnet(request *ec2.Subnet) (*ec2.CreateSubnetOutput, error)

func (*FakeEC2Impl) CreateTags

func (ec2i *FakeEC2Impl) CreateTags(*ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error)

func (*FakeEC2Impl) CreateVolume

func (ec2i *FakeEC2Impl) CreateVolume(request *ec2.CreateVolumeInput) (resp *ec2.Volume, err error)

func (*FakeEC2Impl) DeleteRoute

func (ec2i *FakeEC2Impl) DeleteRoute(request *ec2.DeleteRouteInput) (*ec2.DeleteRouteOutput, error)

func (*FakeEC2Impl) DeleteSecurityGroup

func (*FakeEC2Impl) DeleteVolume

func (ec2i *FakeEC2Impl) DeleteVolume(request *ec2.DeleteVolumeInput) (resp *ec2.DeleteVolumeOutput, err error)

func (*FakeEC2Impl) DescribeInstances

func (ec2i *FakeEC2Impl) DescribeInstances(request *ec2.DescribeInstancesInput) ([]*ec2.Instance, error)

func (*FakeEC2Impl) DescribeRouteTables

func (ec2i *FakeEC2Impl) DescribeRouteTables(request *ec2.DescribeRouteTablesInput) ([]*ec2.RouteTable, error)

func (*FakeEC2Impl) DescribeSecurityGroups

func (ec2i *FakeEC2Impl) DescribeSecurityGroups(request *ec2.DescribeSecurityGroupsInput) ([]*ec2.SecurityGroup, error)

func (*FakeEC2Impl) DescribeSubnets

func (ec2i *FakeEC2Impl) DescribeSubnets(request *ec2.DescribeSubnetsInput) ([]*ec2.Subnet, error)

func (*FakeEC2Impl) DescribeVolumeModifications

func (ec2i *FakeEC2Impl) DescribeVolumeModifications(*ec2.DescribeVolumesModificationsInput) ([]*ec2.VolumeModification, error)

func (*FakeEC2Impl) DescribeVolumes

func (ec2i *FakeEC2Impl) DescribeVolumes(request *ec2.DescribeVolumesInput) ([]*ec2.Volume, error)

func (*FakeEC2Impl) DescribeVpcs

func (ec2i *FakeEC2Impl) DescribeVpcs(request *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error)

func (*FakeEC2Impl) DetachVolume

func (ec2i *FakeEC2Impl) DetachVolume(request *ec2.DetachVolumeInput) (resp *ec2.VolumeAttachment, err error)

func (*FakeEC2Impl) ModifyInstanceAttribute

func (ec2i *FakeEC2Impl) ModifyInstanceAttribute(request *ec2.ModifyInstanceAttributeInput) (*ec2.ModifyInstanceAttributeOutput, error)

func (*FakeEC2Impl) ModifyVolume

func (ec2i *FakeEC2Impl) ModifyVolume(*ec2.ModifyVolumeInput) (*ec2.ModifyVolumeOutput, error)

func (*FakeEC2Impl) RemoveRouteTables

func (ec2i *FakeEC2Impl) RemoveRouteTables()

func (*FakeEC2Impl) RemoveSubnets

func (ec2i *FakeEC2Impl) RemoveSubnets()

type FakeELB

type FakeELB struct {
	// contains filtered or unexported fields
}

func (*FakeELB) AddTags

func (elb *FakeELB) AddTags(input *elb.AddTagsInput) (*elb.AddTagsOutput, error)

func (*FakeELB) ConfigureHealthCheck

func (elb *FakeELB) ConfigureHealthCheck(*elb.ConfigureHealthCheckInput) (*elb.ConfigureHealthCheckOutput, error)

func (*FakeELB) CreateLoadBalancer

func (elb *FakeELB) CreateLoadBalancer(*elb.CreateLoadBalancerInput) (*elb.CreateLoadBalancerOutput, error)

func (*FakeELB) DeleteLoadBalancer

func (elb *FakeELB) DeleteLoadBalancer(input *elb.DeleteLoadBalancerInput) (*elb.DeleteLoadBalancerOutput, error)

func (*FakeELB) DescribeLoadBalancerPolicies

func (elb *FakeELB) DescribeLoadBalancerPolicies(input *elb.DescribeLoadBalancerPoliciesInput) (*elb.DescribeLoadBalancerPoliciesOutput, error)

func (*FakeELB) DescribeLoadBalancers

func (elb *FakeELB) DescribeLoadBalancers(input *elb.DescribeLoadBalancersInput) (*elb.DescribeLoadBalancersOutput, error)

type FakeELBV2

type FakeELBV2 struct {
	// contains filtered or unexported fields
}

func (*FakeELBV2) AddTags

func (self *FakeELBV2) AddTags(input *elbv2.AddTagsInput) (*elbv2.AddTagsOutput, error)

func (*FakeELBV2) CreateListener

func (*FakeELBV2) CreateLoadBalancer

func (*FakeELBV2) CreateTargetGroup

func (*FakeELBV2) DeleteListener

func (*FakeELBV2) DeleteLoadBalancer

func (*FakeELBV2) DeleteTargetGroup

func (*FakeELBV2) DeregisterTargets

func (*FakeELBV2) DescribeListeners

func (*FakeELBV2) DescribeLoadBalancers

func (*FakeELBV2) DescribeTargetGroups

func (*FakeELBV2) DescribeTargetHealth

func (self *FakeELBV2) DescribeTargetHealth(input *elbv2.DescribeTargetHealthInput) (*elbv2.DescribeTargetHealthOutput, error)

func (*FakeELBV2) ModifyListener

func (*FakeELBV2) ModifyTargetGroup

func (*FakeELBV2) RegisterTargets

func (*FakeELBV2) WaitUntilLoadBalancersDeleted

func (self *FakeELBV2) WaitUntilLoadBalancersDeleted(*elbv2.DescribeLoadBalancersInput) error

type FakeKMS

type FakeKMS struct {
	// contains filtered or unexported fields
}

func (*FakeKMS) DescribeKey

func (kms *FakeKMS) DescribeKey(*kms.DescribeKeyInput) (*kms.DescribeKeyOutput, error)

type FakeMetadata

type FakeMetadata struct {
	// contains filtered or unexported fields
}

func (*FakeMetadata) GetMetadata

func (m *FakeMetadata) GetMetadata(key string) (string, error)

type IPPermissionSet

type IPPermissionSet map[string]*ec2.IpPermission

func NewIPPermissionSet

func NewIPPermissionSet(items ...*ec2.IpPermission) IPPermissionSet

func (IPPermissionSet) Difference

Difference returns a set of objects that are not in s2 For example: s1 = {a1, a2, a3} s2 = {a1, a2, a4, a5} s1.Difference(s2) = {a3} s2.Difference(s1) = {a4, a5}

func (IPPermissionSet) Equal

func (s1 IPPermissionSet) Equal(s2 IPPermissionSet) bool

Equal returns true if and only if s1 is equal (as a set) to s2. Two sets are equal if their membership is identical. (In practice, this means same elements, order doesn't matter)

func (IPPermissionSet) Insert

func (s IPPermissionSet) Insert(items ...*ec2.IpPermission)

Insert adds items to the set.

func (IPPermissionSet) IsSuperset

func (s1 IPPermissionSet) IsSuperset(s2 IPPermissionSet) bool

IsSuperset returns true if and only if s1 is a superset of s2.

func (IPPermissionSet) Len

func (s IPPermissionSet) Len() int

Len returns the size of the set.

func (IPPermissionSet) List

func (s IPPermissionSet) List() []*ec2.IpPermission

List returns the contents as a slice. Order is not defined.

func (IPPermissionSet) Ungroup

func (s IPPermissionSet) Ungroup() IPPermissionSet

Ungroup splits permissions out into individual permissions EC2 will combine permissions with the same port but different SourceRanges together, for example We ungroup them so we can process them

type InstanceGroupInfo

type InstanceGroupInfo interface {
	// The number of instances currently running under control of this group
	CurrentSize() (int, error)
}

InstanceGroupInfo is returned by InstanceGroups.Describe, and exposes information about the group.

func DescribeInstanceGroup

func DescribeInstanceGroup(asg ASG, instanceGroupName string) (InstanceGroupInfo, error)

DescribeInstanceGroup gets info about the specified instancegroup Exported so it can be used by the e2e tests, which don't want to instantiate a full cloudprovider.

type InstanceGroups

type InstanceGroups interface {
	// Set the size to the fixed size
	ResizeInstanceGroup(instanceGroupName string, size int) error
	// Queries the cloud provider for information about the specified instance group
	DescribeInstanceGroup(instanceGroupName string) (InstanceGroupInfo, error)
}

InstanceGroups is an interface for managing cloud-managed instance groups / autoscaling instance groups TODO: Allow other clouds to implement this

type KMS

type KMS interface {
	DescribeKey(*kms.DescribeKeyInput) (*kms.DescribeKeyOutput, error)
}

KMS is a simple pass-through of the Key Management Service client interface, which allows for testing.

type KubernetesVolumeID

type KubernetesVolumeID string

KubernetesVolumeID represents the id for a volume in the kubernetes API; a few forms are recognized:

  • aws://<zone>/<awsVolumeId>
  • aws:///<awsVolumeId>
  • <awsVolumeId>

func (KubernetesVolumeID) MapToAWSVolumeID

func (name KubernetesVolumeID) MapToAWSVolumeID() (awsVolumeID, error)

MapToAWSVolumeID extracts the awsVolumeID from the KubernetesVolumeID

type ResourceLifecycle

type ResourceLifecycle string

type Services

type Services interface {
	Compute(region string) (EC2, error)
	LoadBalancing(region string) (ELB, error)
	LoadBalancingV2(region string) (ELBV2, error)
	Autoscaling(region string) (ASG, error)
	Metadata() (EC2Metadata, error)
	KeyManagement(region string) (KMS, error)
}

Services is an abstraction over AWS, to allow mocking/other implementations

type VolumeOptions

type VolumeOptions struct {
	CapacityGB       int
	Tags             map[string]string
	VolumeType       string
	AvailabilityZone string
	// IOPSPerGB x CapacityGB will give total IOPS of the volume to create.
	// Calculated total IOPS will be capped at MaxTotalIOPS.
	IOPSPerGB int
	Encrypted bool
	// fully qualified resource name to the key to use for encryption.
	// example: arn:aws:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef
	KmsKeyId string
}

VolumeOptions specifies capacity and tags for a volume.

type Volumes

type Volumes interface {
	// Attach the disk to the node with the specified NodeName
	// nodeName can be empty to mean "the instance on which we are running"
	// Returns the device (e.g. /dev/xvdf) where we attached the volume
	AttachDisk(diskName KubernetesVolumeID, nodeName types.NodeName) (string, error)
	// Detach the disk from the node with the specified NodeName
	// nodeName can be empty to mean "the instance on which we are running"
	// Returns the device where the volume was attached
	DetachDisk(diskName KubernetesVolumeID, nodeName types.NodeName) (string, error)

	// Create a volume with the specified options
	CreateDisk(volumeOptions *VolumeOptions) (volumeName KubernetesVolumeID, err error)
	// Delete the specified volume
	// Returns true iff the volume was deleted
	// If the was not found, returns (false, nil)
	DeleteDisk(volumeName KubernetesVolumeID) (bool, error)

	// Get labels to apply to volume on creation
	GetVolumeLabels(volumeName KubernetesVolumeID) (map[string]string, error)

	// Get volume's disk path from volume name
	// return the device path where the volume is attached
	GetDiskPath(volumeName KubernetesVolumeID) (string, error)

	// Check if the volume is already attached to the node with the specified NodeName
	DiskIsAttached(diskName KubernetesVolumeID, nodeName types.NodeName) (bool, error)

	// Check if disks specified in argument map are still attached to their respective nodes.
	DisksAreAttached(map[types.NodeName][]KubernetesVolumeID) (map[types.NodeName]map[KubernetesVolumeID]bool, error)

	// Expand the disk to new size
	ResizeDisk(diskName KubernetesVolumeID, oldSize resource.Quantity, newSize resource.Quantity) (resource.Quantity, error)
}

Volumes is an interface for managing cloud-provisioned volumes TODO: Allow other clouds to implement this

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL