@startuml
namespace amifamily {
    class AL2 << (S,Aquamarine) >> {
        + DescribeImageQuery(ctx context.Context, ssmProvider ssm.Provider, k8sVersion string, amiVersion string) (DescribeImageQuery, error)
        + UserData(kubeletConfig *v1.KubeletConfiguration, taints []v1.Taint, labels <font color=blue>map</font>[string]string, caBundle *string, _ []*cloudprovider.InstanceType, customUserData *string, instanceStorePolicy *v1.InstanceStorePolicy) bootstrap.Bootstrapper
        + DefaultBlockDeviceMappings() []*v1.BlockDeviceMapping
        + EphemeralBlockDevice() *string

    }
    class AL2023 << (S,Aquamarine) >> {
        - resolvePath(architecture string, variant string, k8sVersion string, amiVersion string) string

        + DescribeImageQuery(ctx context.Context, ssmProvider ssm.Provider, k8sVersion string, amiVersion string) (DescribeImageQuery, error)
        + UserData(kubeletConfig *v1.KubeletConfiguration, taints []v1.Taint, labels <font color=blue>map</font>[string]string, caBundle *string, _ []*cloudprovider.InstanceType, customUserData *string, instanceStorePolicy *v1.InstanceStorePolicy) bootstrap.Bootstrapper
        + DefaultBlockDeviceMappings() []*v1.BlockDeviceMapping
        + EphemeralBlockDevice() *string

    }
    class AMI << (S,Aquamarine) >> {
        + Name string
        + AmiID string
        + CreationDate string
        + Deprecated bool
        + Requirements scheduling.Requirements

    }
    interface AMIFamily  {
        + DescribeImageQuery(ctx context.Context, ssmProvider ssm.Provider, k8sVersion string, amiVersion string) (DescribeImageQuery, error)
        + UserData(kubeletConfig *v1.KubeletConfiguration, taints []v1.Taint, labels <font color=blue>map</font>[string]string, caBundle *string, instanceTypes []*cloudprovider.InstanceType, customUserData *string, instanceStorePolicy *v1.InstanceStorePolicy) bootstrap.Bootstrapper
        + DefaultBlockDeviceMappings() []*v1.BlockDeviceMapping
        + DefaultMetadataOptions() *v1.MetadataOptions
        + EphemeralBlockDevice() *string
        + FeatureFlags() FeatureFlags

    }
    class AMIs << (S,Aquamarine) >> {
        + Sort() 

    }
    class Bottlerocket << (S,Aquamarine) >> {
        + DescribeImageQuery(ctx context.Context, ssmProvider ssm.Provider, k8sVersion string, amiVersion string) (DescribeImageQuery, error)
        + UserData(kubeletConfig *v1.KubeletConfiguration, taints []v1.Taint, labels <font color=blue>map</font>[string]string, caBundle *string, _ []*cloudprovider.InstanceType, customUserData *string, instanceStorePolicy *v1.InstanceStorePolicy) bootstrap.Bootstrapper
        + DefaultBlockDeviceMappings() []*v1.BlockDeviceMapping
        + EphemeralBlockDevice() *string
        + FeatureFlags() FeatureFlags

    }
    class Custom << (S,Aquamarine) >> {
        + UserData(_ *v1.KubeletConfiguration, _ []v1.Taint, _ <font color=blue>map</font>[string]string, _ *string, _ []*cloudprovider.InstanceType, customUserData *string, _ *v1.InstanceStorePolicy) bootstrap.Bootstrapper
        + DescribeImageQuery(_ context.Context, _ ssm.Provider, _ string, _ string) (DescribeImageQuery, error)
        + DefaultBlockDeviceMappings() []*v1.BlockDeviceMapping
        + EphemeralBlockDevice() *string

    }
    class DefaultAMIOutput << (S,Aquamarine) >> {
        + Query string
        + Requirements scheduling.Requirements

    }
    class DefaultFamily << (S,Aquamarine) >> {
        + FeatureFlags() FeatureFlags

    }
    class DefaultProvider << (S,Aquamarine) >> {
        - clk clock.Clock
        - cache *cache.Cache
        - ec2api aws.EC2API
        - cm *pretty.ChangeMonitor
        - versionProvider version.Provider
        - ssmProvider ssm.Provider

        - amis(ctx context.Context, queries []DescribeImageQuery) (AMIs, error)

        + List(ctx context.Context, nodeClass *v1.EC2NodeClass) (AMIs, error)
        + DescribeImageQueries(ctx context.Context, nodeClass *v1.EC2NodeClass) ([]DescribeImageQuery, error)

    }
    class DefaultResolver << (S,Aquamarine) >> {
        - defaultClusterDNS(opts *Options, kubeletConfig *v1.KubeletConfiguration) *v1.KubeletConfiguration
        - resolveLaunchTemplate(nodeClass *v1.EC2NodeClass, nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType, capacityType string, amiFamily AMIFamily, amiID string, maxPods int, efaCount int, options *Options) *LaunchTemplate

        + Resolve(nodeClass *v1.EC2NodeClass, nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType, capacityType string, options *Options) ([]*LaunchTemplate, error)

    }
    class DescribeImageQuery << (S,Aquamarine) >> {
        + Filters []types.Filter
        + Owners []string
        + KnownRequirements <font color=blue>map</font>[string][]scheduling.Requirements

        + DescribeImagesInput() *ec2.DescribeImagesInput
        + RequirementsForImageWithArchitecture(image string, arch string) []scheduling.Requirements

    }
    class FeatureFlags << (S,Aquamarine) >> {
        + UsesENILimitedMemoryOverhead bool
        + PodsPerCoreEnabled bool
        + EvictionSoftEnabled bool
        + SupportsENILimitedPodDensity bool

    }
    class LaunchTemplate << (S,Aquamarine) >> {
        + UserData bootstrap.Bootstrapper
        + BlockDeviceMappings []*v1.BlockDeviceMapping
        + MetadataOptions *v1.MetadataOptions
        + AMIID string
        + InstanceTypes []*cloudprovider.InstanceType
        + DetailedMonitoring bool
        + EFACount int
        + CapacityType string

    }
    class Options << (S,Aquamarine) >> {
        + ClusterName string
        + ClusterEndpoint string
        + ClusterCIDR *string
        + InstanceProfile string
        + CABundle *string
        + InstanceStorePolicy *v1.InstanceStorePolicy
        + SecurityGroups []v1.SecurityGroup
        + Tags <font color=blue>map</font>[string]string
        + Labels <font color=blue>map</font>[string]string
        + KubeDNSIP net.IP
        + AssociatePublicIPAddress *bool
        + NodeClassName string

        + DefaultMetadataOptions() *v1.MetadataOptions

    }
    interface Provider  {
        + List(ctx context.Context, nodeClass *v1.EC2NodeClass) (AMIs, error)

    }
    interface Resolver  {
        + Resolve( *v1.EC2NodeClass,  *v1.NodeClaim,  []*cloudprovider.InstanceType,  string,  *Options) ([]*LaunchTemplate, error)

    }
    class Variant << (S,Aquamarine) >> {
        + Requirements() scheduling.Requirements

    }
    class Windows << (S,Aquamarine) >> {
        + Version string
        + Build string

        + DescribeImageQuery(ctx context.Context, ssmProvider ssm.Provider, k8sVersion string, amiVersion string) (DescribeImageQuery, error)
        + UserData(kubeletConfig *v1.KubeletConfiguration, taints []v1.Taint, labels <font color=blue>map</font>[string]string, caBundle *string, _ []*cloudprovider.InstanceType, customUserData *string, _ *v1.InstanceStorePolicy) bootstrap.Bootstrapper
        + DefaultBlockDeviceMappings() []*v1.BlockDeviceMapping
        + EphemeralBlockDevice() *string
        + FeatureFlags() FeatureFlags

    }
    class amifamily.AMIs << (T, #FF7700) >>  {
    }
    class amifamily.Variant << (T, #FF7700) >>  {
    }
}
"amifamily.DefaultFamily" *-- "amifamily.AL2"
"amifamily.Options" *-- "amifamily.AL2"
"amifamily.DefaultFamily" *-- "amifamily.AL2023"
"amifamily.Options" *-- "amifamily.AL2023"
"amifamily.DefaultFamily" *-- "amifamily.Bottlerocket"
"amifamily.Options" *-- "amifamily.Bottlerocket"
"amifamily.DefaultFamily" *-- "amifamily.Custom"
"amifamily.Options" *-- "amifamily.Custom"
"sync.Mutex" *-- "amifamily.DefaultProvider"
"amifamily.Options" *-- "amifamily.LaunchTemplate"
"amifamily.DefaultFamily" *-- "amifamily.Windows"
"amifamily.Options" *-- "amifamily.Windows"

"amifamily.Provider" <|-- "amifamily.DefaultProvider"
"amifamily.Resolver" <|-- "amifamily.DefaultResolver"

namespace aws {
    class Environment << (S,Aquamarine) >> {
        + Region string
        + STSAPI *sts.Client
        + EC2API *ec2.Client
        + SSMAPI *ssm.Client
        + IAMAPI *iam.Client
        + FISAPI *fis.Client
        + EKSAPI *eks.Client
        + TimeStreamAPI aws.TimestreamWriteAPI
        + SQSProvider sqs.Provider
        + ClusterName string
        + ClusterEndpoint string
        + InterruptionQueue string
        + PrivateCluster bool
        + ZoneInfo []ZoneInfo

        + DefaultEC2NodeClass() *v1.EC2NodeClass
        + ExpectWindowsIPAMEnabled() 
        + ExpectWindowsIPAMDisabled() 
        + ExpectInstance(nodeName string) Assertion
        + ExpectIPv6ClusterDNS() string
        + ExpectSpotInterruptionExperiment(instanceIDs ...string) *types.Experiment
        + ExpectExperimentTemplateDeleted(id string) 
        + EventuallyExpectInstanceProfileExists(profileName string) types.InstanceProfile
        + GetInstanceProfileName(nodeClass *v1.EC2NodeClass) string
        + GetInstance(nodeName string) types.Instance
        + ExpectInstanceStopped(nodeName string) 
        + ExpectInstanceTerminated(nodeName string) 
        + GetInstanceByID(instanceID string) types.Instance
        + GetVolume(id string) types.Volume
        + GetVolumes(ids ...string) []types.Volume
        + GetNetworkInterface(id string) types.NetworkInterface
        + GetNetworkInterfaces(ids ...string) []types.NetworkInterface
        + GetSpotInstance(id string) types.SpotInstanceRequest
        + GetSubnets(tags <font color=blue>map</font>[string]string) <font color=blue>map</font>[string][]string
        + GetSubnetInfo(tags <font color=blue>map</font>[string]string) []SubnetInfo
        + GetSecurityGroups(tags <font color=blue>map</font>[string]string) []SecurityGroup
        + ExpectMessagesCreated(msgs ...<font color=blue>interface</font>{}) 
        + ExpectParsedProviderID(providerID string) string
        + K8sVersion() string
        + K8sVersionWithOffset(offset int) string
        + K8sMinorVersion() int
        + GetAMIBySSMPath(ssmPath string) string
        + GetDeprecatedAMI(amiID string, amifamily string) string
        + EventuallyExpectRunInstances(instanceInput *ec2.RunInstancesInput) types.Reservation
        + ExpectSpotInterruptionRole() *types.Role
        + ExpectAccountID() string
        + ExpectInstanceProfileCreated(instanceProfileName string, roleName string) 
        + ExpectInstanceProfileDeleted(instanceProfileName string, roleName string) 
        + MeasureProvisioningDurationFor(f <font color=blue>func</font>() , dimensions <font color=blue>map</font>[string]string) 
        + MeasureDeprovisioningDurationFor(f <font color=blue>func</font>() , dimensions <font color=blue>map</font>[string]string) 
        + MeasureDurationFor(f <font color=blue>func</font>() , eventType EventType, dimensions <font color=blue>map</font>[string]string) 
        + ExpectMetric(name string, value float64, labels <font color=blue>map</font>[string]string) 
        + BeforeEach() 
        + Cleanup() 
        + AfterEach() 

    }
    class NoOpTimeStreamAPI << (S,Aquamarine) >> {
        + WriteRecords(_ context.Context, _ *timestreamwrite.WriteRecordsInput, _ ...<font color=blue>func</font>(*timestreamwrite.Options) ) (*timestreamwrite.WriteRecordsOutput, error)

    }
    class SecurityGroup << (S,Aquamarine) >> {
        + Tags []types.Tag

    }
    class SubnetInfo << (S,Aquamarine) >> {
        + Name string
        + ID string

    }
    class ZoneInfo << (S,Aquamarine) >> {
        + Zone string
        + ZoneID string
        + ZoneType string

    }
    class aws.EventType << (T, #FF7700) >>  {
    }
}
"common.Environment" *-- "aws.Environment"
"aws.TimestreamWriteAPI" *-- "aws.NoOpTimeStreamAPI"
"types.GroupIdentifier" *-- "aws.SecurityGroup"
"aws.ZoneInfo" *-- "aws.SubnetInfo"

"sdk.TimestreamWriteAPI" <|-- "aws.NoOpTimeStreamAPI"

namespace batcher {
    class CreateFleetBatcher << (S,Aquamarine) >> {
        - batcher *

        + CreateFleet(ctx context.Context, createFleetInput *ec2.CreateFleetInput) (*ec2.CreateFleetOutput, error)

    }
    class DescribeInstancesBatcher << (S,Aquamarine) >> {
        - batcher *

        + DescribeInstances(ctx context.Context, describeInstancesInput *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error)

    }
    class EC2API << (S,Aquamarine) >> {
    }
    class TerminateInstancesBatcher << (S,Aquamarine) >> {
        - batcher *

        + TerminateInstances(ctx context.Context, terminateInstancesInput *ec2.TerminateInstancesInput) (*ec2.TerminateInstancesOutput, error)

    }
}
"batcher.CreateFleetBatcher" *-- "batcher.EC2API"
"batcher.DescribeInstancesBatcher" *-- "batcher.EC2API"
"batcher.TerminateInstancesBatcher" *-- "batcher.EC2API"


namespace bootstrap {
    class BootstrapCommand << (S,Aquamarine) >> {
        + Commands [][]string
        + Mode BootstrapCommandMode
        + Essential bool

    }
    interface Bootstrapper  {
        + Script() (string, error)

    }
    class Bottlerocket << (S,Aquamarine) >> {
        + Script() (string, error)

    }
    class BottlerocketConfig << (S,Aquamarine) >> {
        + SettingsRaw <font color=blue>map</font>[string]<font color=blue>interface</font>{}
        + Settings BottlerocketSettings

        + UnmarshalTOML(data []byte) error
        + MarshalTOML() ([]byte, error)

    }
    class BottlerocketCredentialProvider << (S,Aquamarine) >> {
        + Enabled *bool
        + CacheDuration *string
        + ImagePatterns []string
        + Environment <font color=blue>map</font>[string]string

    }
    class BottlerocketKubernetes << (S,Aquamarine) >> {
        + APIServer *string
        + CloudProvider *string
        + ClusterCertificate *string
        + ClusterName *string
        + ClusterDNSIP *string
        + CredentialProviders <font color=blue>map</font>[string]BottlerocketCredentialProvider
        + NodeLabels <font color=blue>map</font>[string]string
        + NodeTaints <font color=blue>map</font>[string][]string
        + MaxPods *int
        + StaticPods <font color=blue>map</font>[string]BottlerocketStaticPod
        + EvictionHard <font color=blue>map</font>[string]string
        + KubeReserved <font color=blue>map</font>[string]string
        + SystemReserved <font color=blue>map</font>[string]string
        + AllowedUnsafeSysctls []string
        + ServerTLSBootstrap *bool
        + RegistryQPS *int
        + RegistryBurst *int
        + EventQPS *int
        + EventBurst *int
        + KubeAPIQPS *int
        + KubeAPIBurst *int
        + ContainerLogMaxSize *string
        + ContainerLogMaxFiles *int
        + CPUManagerPolicy *string
        + CPUManagerReconcilePeriod *string
        + TopologyManagerScope *string
        + TopologyManagerPolicy *string
        + ImageGCHighThresholdPercent *string
        + ImageGCLowThresholdPercent *string
        + CPUCFSQuota *bool
        + ShutdownGracePeriod *string
        + ShutdownGracePeriodForCriticalPods *string
        + ClusterDomain *string
        + SeccompDefault *bool
        + PodPidsLimit *int

    }
    class BottlerocketSettings << (S,Aquamarine) >> {
        + Kubernetes BottlerocketKubernetes
        + BootstrapCommands <font color=blue>map</font>[string]BootstrapCommand

    }
    class BottlerocketStaticPod << (S,Aquamarine) >> {
        + Enabled *bool
        + Manifest *string

    }
    class Custom << (S,Aquamarine) >> {
        + Script() (string, error)

    }
    class EKS << (S,Aquamarine) >> {
        + ContainerRuntime string

        - eksBootstrapScript() string
        - mergeCustomUserData(userDatas ...string) (string, error)
        - isIPv6() bool
        - mimeify(customUserData string) (string, error)

        + Script() (string, error)

    }
    class Nodeadm << (S,Aquamarine) >> {
        - getNodeConfigYAML() (string, error)
        - generateInlineKubeletConfiguration() (<font color=blue>map</font>[string]runtime.RawExtension, error)
        - parseUserData() ([]mime.Entry, error)

        + Script() (string, error)

    }
    class Options << (S,Aquamarine) >> {
        + ClusterName string
        + ClusterEndpoint string
        + ClusterCIDR *string
        + KubeletConfig *v1.KubeletConfiguration
        + Taints []v1.Taint
        + Labels <font color=blue>map</font>[string]string
        + CABundle *string
        + ContainerRuntime *string
        + CustomUserData *string
        + InstanceStorePolicy *v1.InstanceStorePolicy

        - kubeletExtraArgs() []string
        - nodeTaintArg() string
        - nodeLabelArg() string

    }
    class bootstrap.BootstrapCommandMode << (T, #FF7700) >>  {
    }
}
"bootstrap.Options" *-- "bootstrap.Bottlerocket"
"bootstrap.Options" *-- "bootstrap.Custom"
"bootstrap.Options" *-- "bootstrap.EKS"
"bootstrap.Options" *-- "bootstrap.Nodeadm"

"bootstrap.Bootstrapper" <|-- "bootstrap.Bottlerocket"
"bootstrap.Bootstrapper" <|-- "bootstrap.Custom"
"bootstrap.Bootstrapper" <|-- "bootstrap.EKS"
"bootstrap.Bootstrapper" <|-- "bootstrap.Nodeadm"

namespace cache {
    class UnavailableOfferings << (S,Aquamarine) >> {
        - cache *cache.Cache

        + SeqNum uint64

        - key(instanceType types.InstanceType, zone string, capacityType string) string

        + IsUnavailable(instanceType types.InstanceType, zone string, capacityType string) bool
        + MarkUnavailable(ctx context.Context, unavailableReason string, instanceType types.InstanceType, zone string, capacityType string) 
        + MarkUnavailableForFleetErr(ctx context.Context, fleetErr types.CreateFleetError, capacityType string) 
        + Delete(instanceType types.InstanceType, zone string, capacityType string) 
        + Flush() 

    }
}


namespace capacity {
    class Controller << (S,Aquamarine) >> {
        - kubeClient client.Client
        - instancetypeProvider *instancetype.DefaultProvider

        + Reconcile(ctx context.Context, node *v1.Node) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
}


namespace cloudprovider {
    class CloudProvider << (S,Aquamarine) >> {
        - kubeClient client.Client
        - recorder events.Recorder
        - instanceTypeProvider instancetype.Provider
        - instanceProvider instance.Provider
        - amiProvider amifamily.Provider
        - securityGroupProvider securitygroup.Provider

        - resolveNodeClassFromNodeClaim(ctx context.Context, nodeClaim *v1.NodeClaim) (*v1.EC2NodeClass, error)
        - resolveNodeClassFromNodePool(ctx context.Context, nodePool *v1.NodePool) (*v1.EC2NodeClass, error)
        - resolveInstanceTypes(ctx context.Context, nodeClaim *v1.NodeClaim, nodeClass *v1.EC2NodeClass) ([]*cloudprovider.InstanceType, error)
        - resolveInstanceTypeFromInstance(ctx context.Context, instance *instance.Instance) (*cloudprovider.InstanceType, error)
        - resolveNodeClassFromInstance(ctx context.Context, instance *instance.Instance) (*v1.EC2NodeClass, error)
        - resolveNodePoolFromInstance(ctx context.Context, instance *instance.Instance) (*v1.NodePool, error)
        - instanceToNodeClaim(i *instance.Instance, instanceType *cloudprovider.InstanceType, nodeClass *v1.EC2NodeClass) *v1.NodeClaim
        - isNodeClassDrifted(ctx context.Context, nodeClaim *v1.NodeClaim, nodePool *v1.NodePool, nodeClass *v1.EC2NodeClass) (cloudprovider.DriftReason, error)
        - isAMIDrifted(ctx context.Context, nodeClaim *v1.NodeClaim, nodePool *v1.NodePool, instance *instance.Instance, nodeClass *v1.EC2NodeClass) (cloudprovider.DriftReason, error)
        - isSubnetDrifted(instance *instance.Instance, nodeClass *v1.EC2NodeClass) (cloudprovider.DriftReason, error)
        - areSecurityGroupsDrifted(ec2Instance *instance.Instance, nodeClass *v1.EC2NodeClass) (cloudprovider.DriftReason, error)
        - areStaticFieldsDrifted(nodeClaim *v1.NodeClaim, nodeClass *v1.EC2NodeClass) cloudprovider.DriftReason
        - getInstance(ctx context.Context, providerID string) (*instance.Instance, error)

        + Create(ctx context.Context, nodeClaim *v1.NodeClaim) (*v1.NodeClaim, error)
        + List(ctx context.Context) ([]*v1.NodeClaim, error)
        + Get(ctx context.Context, providerID string) (*v1.NodeClaim, error)
        + GetInstanceTypes(ctx context.Context, nodePool *v1.NodePool) ([]*cloudprovider.InstanceType, error)
        + Delete(ctx context.Context, nodeClaim *v1.NodeClaim) error
        + DisruptionReasons() []v1.DisruptionReason
        + IsDrifted(ctx context.Context, nodeClaim *v1.NodeClaim) (cloudprovider.DriftReason, error)
        + Name() string
        + GetSupportedNodeClasses() []status.Object

    }
}


namespace common {
    class Environment << (S,Aquamarine) >> {
        - cancel context.CancelFunc

        + Client client.Client
        + Config *rest.Config
        + KubeClient kubernetes.Interface
        + Monitor *Monitor
        + StartingNodeCount int

        - eventuallyExpectScaleDown() 
        - printControllerLogs(options *v1.PodLogOptions) 

        + Stop() 
        + DefaultNodePool(nodeClass *v1.EC2NodeClass) *v1.NodePool
        + ExpectCreated(objects ...client.Object) 
        + ExpectDeleted(objects ...client.Object) 
        + ExpectUpdated(objects ...client.Object) 
        + ExpectCreatedOrUpdated(objects ...client.Object) 
        + ExpectSettings() []v1.EnvVar
        + ExpectSettingsReplaced(vars ...v1.EnvVar) 
        + ExpectSettingsOverridden(vars ...v1.EnvVar) 
        + ExpectSettingsRemoved(vars ...v1.EnvVar) 
        + ExpectConfigMapExists(key types.NamespacedName) *v1.ConfigMap
        + ExpectConfigMapDataReplaced(key types.NamespacedName, data ...<font color=blue>map</font>[string]string) bool
        + ExpectConfigMapDataOverridden(key types.NamespacedName, data ...<font color=blue>map</font>[string]string) bool
        + ExpectPodENIEnabled() 
        + ExpectPodENIDisabled() 
        + ExpectPrefixDelegationEnabled() 
        + ExpectPrefixDelegationDisabled() 
        + ExpectExists(obj client.Object) client.Object
        + EventuallyExpectBound(pods ...*v1.Pod) 
        + EventuallyExpectHealthy(pods ...*v1.Pod) 
        + EventuallyExpectTerminating(pods ...*v1.Pod) 
        + EventuallyExpectTerminatingWithTimeout(timeout time.Duration, pods ...*v1.Pod) 
        + EventuallyExpectNoLeakedKubeNodeLease() 
        + EventuallyExpectHealthyWithTimeout(timeout time.Duration, pods ...*v1.Pod) 
        + ConsistentlyExpectTerminatingPods(duration time.Duration, pods ...*v1.Pod) 
        + ConsistentlyExpectActivePods(duration time.Duration, pods ...*v1.Pod) 
        + ConsistentlyExpectHealthyPods(duration time.Duration, pods ...*v1.Pod) 
        + EventuallyExpectKarpenterRestarted() 
        + ExpectKarpenterLeaseOwnerChanged() 
        + EventuallyExpectRollout(name string, namespace string) 
        + ExpectKarpenterPods() []*v1.Pod
        + ExpectActiveKarpenterPodName() string
        + ExpectActiveKarpenterPod() *v1.Pod
        + EventuallyExpectPendingPodCount(selector labels.Selector, numPods int) 
        + EventuallyExpectBoundPodCount(selector labels.Selector, numPods int) []*v1.Pod
        + EventuallyExpectHealthyPodCount(selector labels.Selector, numPods int) []*v1.Pod
        + EventuallyExpectHealthyPodCountWithTimeout(timeout time.Duration, selector labels.Selector, numPods int) []*v1.Pod
        + ExpectPodsMatchingSelector(selector labels.Selector) []*v1.Pod
        + EventuallyExpectUniqueNodeNames(selector labels.Selector, uniqueNames int) 
        + EventuallyExpectNotFound(objects ...client.Object) 
        + ExpectCreatedNodeCount(comparator string, count int) []*v1.Node
        + ExpectNodeCount(comparator string, count int) []*v1.Node
        + ExpectNodeClaimCount(comparator string, count int) []*v1.NodeClaim
        + ConsistentlyExpectNodeCount(comparator string, count int, duration time.Duration) []*v1.Node
        + ConsistentlyExpectNoDisruptions(nodeCount int, duration time.Duration) 
        + ConsistentlyExpectDisruptionsUntilNoneLeft(nodesAtStart int, maxNodesDisrupting int, timeout time.Duration) 
        + EventuallyExpectTaintedNodeCount(comparator string, count int) []*v1.Node
        + EventuallyExpectNodesUntaintedWithTimeout(timeout time.Duration, nodes ...*v1.Node) 
        + EventuallyExpectNodeClaimCount(comparator string, count int) []*v1.NodeClaim
        + EventuallyExpectNodeCount(comparator string, count int) []*v1.Node
        + EventuallyExpectNodeCountWithSelector(comparator string, count int, selector labels.Selector) []*v1.Node
        + EventuallyExpectCreatedNodeCount(comparator string, count int) []*v1.Node
        + EventuallyExpectDeletedNodeCount(comparator string, count int) []*v1.Node
        + EventuallyExpectDeletedNodeCountWithSelector(comparator string, count int, selector labels.Selector) []*v1.Node
        + EventuallyExpectInitializedNodeCount(comparator string, count int) []*v1.Node
        + EventuallyExpectCreatedNodeClaimCount(comparator string, count int) []*v1.NodeClaim
        + EventuallyExpectNodeClaimsReady(nodeClaims ...*v1.NodeClaim) 
        + EventuallyExpectDrifted(nodeClaims ...*v1.NodeClaim) 
        + ConsistentlyExpectNodeClaimsNotDrifted(duration time.Duration, nodeClaims ...*v1.NodeClaim) 
        + EventuallyExpectConsolidatable(nodeClaims ...*v1.NodeClaim) 
        + GetNode(nodeName string) v1.Node
        + ExpectNoCrashes() 
        + EventuallyExpectMinUtilization(resource v1.ResourceName, comparator string, value float64) 
        + EventuallyExpectAvgUtilization(resource v1.ResourceName, comparator string, value float64) 
        + ExpectDaemonSetEnvironmentVariableUpdated(obj client.ObjectKey, name string, value string, containers ...string) 
        + ForcePodsToSpread(nodes ...*v1.Node) 
        + ExpectActivePodsForNode(nodeName string) []*v1.Pod
        + ExpectCABundle() string
        + GetDaemonSetCount(np *v1.NodePool) int
        + GetDaemonSetOverhead(np *v1.NodePool) v1.ResourceList
        + BeforeEach() 
        + ExpectCleanCluster() 
        + Cleanup() 
        + AfterEach() 
        + CleanupObjects(cleanableObjects ...client.Object) 
        + ExpectTestingFinalizerRemoved(obj client.Object) error

    }
    class Monitor << (S,Aquamarine) >> {
        - ctx context.Context
        - kubeClient client.Client
        - mu sync.RWMutex
        - nodesAtReset <font color=blue>map</font>[string]*v1.Node

        - poll() state
        - nodeUtilization(resource v1.ResourceName) []float64

        + Reset() 
        + RestartCount(namespace string) <font color=blue>map</font>[string]int
        + NodeCount() int
        + NodeCountAtReset() int
        + CreatedNodeCount() int
        + NodesAtReset() []*v1.Node
        + Nodes() []*v1.Node
        + CreatedNodes() []*v1.Node
        + DeletedNodes() []*v1.Node
        + PendingPods(selector labels.Selector) []*v1.Pod
        + PendingPodsCount(selector labels.Selector) int
        + RunningPods(selector labels.Selector) []*v1.Pod
        + RunningPodsCount(selector labels.Selector) int
        + AvgUtilization(resource v1.ResourceName) float64
        + MinUtilization(resource v1.ResourceName) float64

    }
    class common.ContextKey << (T, #FF7700) >>  {
    }
    interface copyable  {
        + DeepCopy() T

    }
    class state << (S,Aquamarine) >> {
        - pods v1.PodList
        - nodes <font color=blue>map</font>[string]*v1.Node
        - nodePods <font color=blue>map</font>[string][]*v1.Pod
        - nodeRequests <font color=blue>map</font>[string]v1.ResourceList

    }
}
"context.Context" *-- "common.Environment"


namespace debug {
    class EventClient << (S,Aquamarine) >> {
        - start time.Time
        - kubeClient client.Client

        - dumpPodEvents(ctx context.Context) error
        - dumpNodeEvents(ctx context.Context) error

        + DumpEvents(ctx context.Context) error

    }
    class Monitor << (S,Aquamarine) >> {
        - ctx context.Context
        - cancel context.CancelFunc
        - wg sync.WaitGroup
        - mgr manager.Manager

        + MustStart() 
        + Stop() 

    }
    class NodeClaimController << (S,Aquamarine) >> {
        - kubeClient client.Client

        + Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error)
        + GetInfo(nc *v1.NodeClaim) string
        + Register(_ context.Context, m manager.Manager) error

    }
    class NodeController << (S,Aquamarine) >> {
        - kubeClient client.Client

        + Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error)
        + GetInfo(ctx context.Context, n *v1.Node) string
        + Register(ctx context.Context, m manager.Manager) error

    }
    class PodController << (S,Aquamarine) >> {
        - kubeClient client.Client

        + Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error)
        + GetInfo(p *v1.Pod) string
        + Register(_ context.Context, m manager.Manager) error

    }
}


namespace fake {
    class CapacityPool << (S,Aquamarine) >> {
        + CapacityType string
        + InstanceType string
        + Zone string

    }
    class CloudProvider << (S,Aquamarine) >> {
        + InstanceTypes []*cloudprovider.InstanceType
        + ValidAMIs []string

        + Create(_ context.Context, _ *v1.NodeClaim) (*v1.NodeClaim, error)
        + GetInstanceTypes(_ context.Context, _ *v1.NodePool) ([]*cloudprovider.InstanceType, error)
        + IsDrifted(_ context.Context, nodeClaim *v1.NodeClaim) (cloudprovider.DriftReason, error)
        + Get( context.Context,  string) (*v1.NodeClaim, error)
        + List( context.Context) ([]*v1.NodeClaim, error)
        + Delete( context.Context,  *v1.NodeClaim) error
        + DisruptionReasons() []v1.DisruptionReason
        + Name() string
        + GetSupportedNodeClasses() []status.Object

    }
    class EC2API << (S,Aquamarine) >> {
        + Reset() 
        + CreateFleet(_ context.Context, input *ec2.CreateFleetInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.CreateFleetOutput, error)
        + TerminateInstances(_ context.Context, input *ec2.TerminateInstancesInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.TerminateInstancesOutput, error)
        + CreateLaunchTemplate(_ context.Context, input *ec2.CreateLaunchTemplateInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.CreateLaunchTemplateOutput, error)
        + CreateTags(_ context.Context, input *ec2.CreateTagsInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.CreateTagsOutput, error)
        + DescribeInstances(_ context.Context, input *ec2.DescribeInstancesInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeInstancesOutput, error)
        + DescribeImages(_ context.Context, input *ec2.DescribeImagesInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeImagesOutput, error)
        + DescribeLaunchTemplates(_ context.Context, input *ec2.DescribeLaunchTemplatesInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeLaunchTemplatesOutput, error)
        + DeleteLaunchTemplate(_ context.Context, input *ec2.DeleteLaunchTemplateInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DeleteLaunchTemplateOutput, error)
        + DescribeSubnets(_ context.Context, input *ec2.DescribeSubnetsInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeSubnetsOutput, error)
        + DescribeSecurityGroups(_ context.Context, input *ec2.DescribeSecurityGroupsInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeSecurityGroupsOutput, error)
        + DescribeAvailabilityZones( context.Context,  *ec2.DescribeAvailabilityZonesInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeAvailabilityZonesOutput, error)
        + DescribeInstanceTypes(_ context.Context, _ *ec2.DescribeInstanceTypesInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeInstanceTypesOutput, error)
        + DescribeInstanceTypeOfferings(_ context.Context, _ *ec2.DescribeInstanceTypeOfferingsInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeInstanceTypeOfferingsOutput, error)
        + DescribeSpotPriceHistory(_ context.Context, input *ec2.DescribeSpotPriceHistoryInput, _ ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeSpotPriceHistoryOutput, error)

    }
    class EC2Behavior << (S,Aquamarine) >> {
        + DescribeImagesOutput 
        + DescribeLaunchTemplatesOutput 
        + DescribeSubnetsOutput 
        + DescribeSecurityGroupsOutput 
        + DescribeInstanceTypesOutput 
        + DescribeInstanceTypeOfferingsOutput 
        + DescribeAvailabilityZonesOutput 
        + DescribeSpotPriceHistoryInput 
        + DescribeSpotPriceHistoryOutput 
        + CreateFleetBehavior 
        + TerminateInstancesBehavior 
        + DescribeInstancesBehavior 
        + CreateTagsBehavior 
        + CalledWithCreateLaunchTemplateInput 
        + CalledWithDescribeImagesInput 
        + Instances sync.Map
        + LaunchTemplates sync.Map
        + InsufficientCapacityPools 
        + NextError AtomicError

    }
    class EKSAPI << (S,Aquamarine) >> {
        + Reset() 
        + DescribeCluster(_ context.Context, input *eks.DescribeClusterInput, _ ...<font color=blue>func</font>(*eks.Options) ) (*eks.DescribeClusterOutput, error)

    }
    class EKSAPIBehavior << (S,Aquamarine) >> {
        + DescribeClusterBehavior 

    }
    class IAMAPI << (S,Aquamarine) >> {
        + InstanceProfiles <font color=blue>map</font>[string]*types.InstanceProfile

        + Reset() 
        + GetInstanceProfile(_ context.Context, input *iam.GetInstanceProfileInput, _ ...<font color=blue>func</font>(*iam.Options) ) (*iam.GetInstanceProfileOutput, error)
        + CreateInstanceProfile(_ context.Context, input *iam.CreateInstanceProfileInput, _ ...<font color=blue>func</font>(*iam.Options) ) (*iam.CreateInstanceProfileOutput, error)
        + DeleteInstanceProfile(_ context.Context, input *iam.DeleteInstanceProfileInput, _ ...<font color=blue>func</font>(*iam.Options) ) (*iam.DeleteInstanceProfileOutput, error)
        + TagInstanceProfile(_ context.Context, input *iam.TagInstanceProfileInput, _ ...<font color=blue>func</font>(*iam.Options) ) (*iam.TagInstanceProfileOutput, error)
        + AddRoleToInstanceProfile(_ context.Context, input *iam.AddRoleToInstanceProfileInput, _ ...<font color=blue>func</font>(*iam.Options) ) (*iam.AddRoleToInstanceProfileOutput, error)
        + RemoveRoleFromInstanceProfile(_ context.Context, input *iam.RemoveRoleFromInstanceProfileInput, _ ...<font color=blue>func</font>(*iam.Options) ) (*iam.RemoveRoleFromInstanceProfileOutput, error)

    }
    class IAMAPIBehavior << (S,Aquamarine) >> {
        + GetInstanceProfileBehavior 
        + CreateInstanceProfileBehavior 
        + DeleteInstanceProfileBehavior 
        + AddRoleToInstanceProfileBehavior 
        + TagInstanceProfileBehavior 
        + RemoveRoleFromInstanceProfileBehavior 

    }
    class PricingAPI << (S,Aquamarine) >> {
        + Reset() 
        + GetProducts(_ context.Context, _ *pricing.GetProductsInput, _ ...<font color=blue>func</font>(*pricing.Options) ) (*pricing.GetProductsOutput, error)

    }
    class PricingBehavior << (S,Aquamarine) >> {
        + NextError AtomicError
        + GetProductsOutput 

    }
    class SQSAPI << (S,Aquamarine) >> {
        + Reset() 
        + GetQueueUrl(_ context.Context, input *sqs.GetQueueUrlInput, _ ...<font color=blue>func</font>(*sqs.Options) ) (*sqs.GetQueueUrlOutput, error)
        + ReceiveMessage(_ context.Context, input *sqs.ReceiveMessageInput, _ ...<font color=blue>func</font>(*sqs.Options) ) (*sqs.ReceiveMessageOutput, error)
        + DeleteMessage(_ context.Context, input *sqs.DeleteMessageInput, _ ...<font color=blue>func</font>(*sqs.Options) ) (*sqs.DeleteMessageOutput, error)

    }
    class SQSBehavior << (S,Aquamarine) >> {
        + GetQueueURLBehavior 
        + ReceiveMessageBehavior 
        + DeleteMessageBehavior 

    }
    class SSMAPI << (S,Aquamarine) >> {
        - defaultParameters <font color=blue>map</font>[string]string

        + Parameters <font color=blue>map</font>[string]string
        + GetParameterOutput *ssm.GetParameterOutput
        + WantErr error

        + GetParameter(_ context.Context, input *ssm.GetParameterInput, _ ...<font color=blue>func</font>(*ssm.Options) ) (*ssm.GetParameterOutput, error)
        + Reset() 

    }
}
"aws.EC2API" *-- "fake.EC2API"
"fake.EC2Behavior" *-- "fake.EC2API"
"aws.EKSAPI" *-- "fake.EKSAPI"
"fake.EKSAPIBehavior" *-- "fake.EKSAPI"
"aws.IAMAPI" *-- "fake.IAMAPI"
"fake.IAMAPIBehavior" *-- "fake.IAMAPI"
"sync.Mutex" *-- "fake.IAMAPI"
"aws.PricingAPI" *-- "fake.PricingAPI"
"fake.PricingBehavior" *-- "fake.PricingAPI"
"aws.SQSAPI" *-- "fake.SQSAPI"
"fake.SQSBehavior" *-- "fake.SQSAPI"
"aws.SSMAPI" *-- "fake.SSMAPI"

"sdk.EC2API" <|-- "fake.EC2API"
"sdk.EKSAPI" <|-- "fake.EKSAPI"
"sdk.IAMAPI" <|-- "fake.IAMAPI"
"sdk.PricingAPI" <|-- "fake.PricingAPI"
"sdk.SSMAPI" <|-- "fake.SSMAPI"

namespace garbagecollection {
    class Controller << (S,Aquamarine) >> {
        - kubeClient client.Client
        - cloudProvider cloudprovider.CloudProvider
        - successfulCount uint64

        - garbageCollect(ctx context.Context, nodeClaim *v1.NodeClaim, nodeList *v1.NodeList) error

        + Reconcile(ctx context.Context) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
}


namespace hash {
    class Controller << (S,Aquamarine) >> {
        - kubeClient client.Client

        - updateNodeClaimHash(ctx context.Context, nodeClass *v1.EC2NodeClass) error

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
}

"status.nodeClassStatusReconciler" <|-- "hash.Controller"

namespace instance {
    class DefaultProvider << (S,Aquamarine) >> {
        - region string
        - ec2api aws.EC2API
        - unavailableOfferings *cache.UnavailableOfferings
        - subnetProvider subnet.Provider
        - launchTemplateProvider launchtemplate.Provider
        - ec2Batcher *batcher.EC2API

        - launchInstance(ctx context.Context, nodeClass *v1.EC2NodeClass, nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType, tags <font color=blue>map</font>[string]string) (types.CreateFleetInstance, error)
        - checkODFallback(nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType, launchTemplateConfigs []types.FleetLaunchTemplateConfigRequest) error
        - getLaunchTemplateConfigs(ctx context.Context, nodeClass *v1.EC2NodeClass, nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType, zonalSubnets <font color=blue>map</font>[string]*subnet.Subnet, capacityType string, tags <font color=blue>map</font>[string]string) ([]types.FleetLaunchTemplateConfigRequest, error)
        - getOverrides(instanceTypes []*cloudprovider.InstanceType, zonalSubnets <font color=blue>map</font>[string]*subnet.Subnet, reqs scheduling.Requirements, image string) []types.FleetLaunchTemplateOverridesRequest
        - updateUnavailableOfferingsCache(ctx context.Context, errors []types.CreateFleetError, capacityType string) 
        - getCapacityType(nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType) string
        - filterInstanceTypes(nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType) []*cloudprovider.InstanceType
        - isMixedCapacityLaunch(nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType) bool

        + Create(ctx context.Context, nodeClass *v1.EC2NodeClass, nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType) (*Instance, error)
        + Get(ctx context.Context, id string) (*Instance, error)
        + List(ctx context.Context) ([]*Instance, error)
        + Delete(ctx context.Context, id string) error
        + CreateTags(ctx context.Context, id string, tags <font color=blue>map</font>[string]string) error

    }
    class Instance << (S,Aquamarine) >> {
        + LaunchTime time.Time
        + State types.InstanceStateName
        + ID string
        + ImageID string
        + Type types.InstanceType
        + Zone string
        + CapacityType string
        + SecurityGroupIDs []string
        + SubnetID string
        + Tags <font color=blue>map</font>[string]string
        + EFAEnabled bool

    }
    interface Provider  {
        + Create( context.Context,  *v1.EC2NodeClass,  *v1.NodeClaim,  []*cloudprovider.InstanceType) (*Instance, error)
        + Get( context.Context,  string) (*Instance, error)
        + List( context.Context) ([]*Instance, error)
        + Delete( context.Context,  string) error
        + CreateTags( context.Context,  string,  <font color=blue>map</font>[string]string) error

    }
}

"instance.Provider" <|-- "instance.DefaultProvider"

namespace instanceprofile {
    class DefaultProvider << (S,Aquamarine) >> {
        - region string
        - iamapi aws.IAMAPI
        - cache *cache.Cache

        + Create(ctx context.Context, m ResourceOwner) (string, error)
        + Delete(ctx context.Context, m ResourceOwner) error

    }
    interface Provider  {
        + Create( context.Context,  ResourceOwner) (string, error)
        + Delete( context.Context,  ResourceOwner) error

    }
    interface ResourceOwner  {
        + GetUID() types.UID
        + InstanceProfileName( string,  string) string
        + InstanceProfileRole() string
        + InstanceProfileTags( string) <font color=blue>map</font>[string]string

    }
}

"instanceprofile.Provider" <|-- "instanceprofile.DefaultProvider"

namespace instancetype {
    class Controller << (S,Aquamarine) >> {
        - instanceTypeProvider *instancetype.DefaultProvider

        + Reconcile(ctx context.Context) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
    class DefaultProvider << (S,Aquamarine) >> {
        - ec2api aws.EC2API
        - subnetProvider subnet.Provider
        - instanceTypesResolver Resolver
        - muInstanceTypesInfo sync.RWMutex
        - instanceTypesInfo []types.InstanceTypeInfo
        - muInstanceTypesOfferings sync.RWMutex
        - instanceTypesOfferings <font color=blue>map</font>[string]
        - instanceTypesCache *cache.Cache
        - discoveredCapacityCache *cache.Cache
        - cm *pretty.ChangeMonitor
        - instanceTypesSeqNum uint64
        - instanceTypesOfferingsSeqNum uint64

        + List(ctx context.Context, nodeClass *v1.EC2NodeClass) ([]*cloudprovider.InstanceType, error)
        + UpdateInstanceTypes(ctx context.Context) error
        + UpdateInstanceTypeOfferings(ctx context.Context) error
        + UpdateInstanceTypeCapacityFromNode(ctx context.Context, kubeClient client.Client, node *v1.Node) error
        + Reset() 

    }
    class DefaultResolver << (S,Aquamarine) >> {
        - region string
        - pricingProvider pricing.Provider
        - unavailableOfferings *cache.UnavailableOfferings

        - createOfferings(ctx context.Context, instanceType types.InstanceTypeInfo, zoneData []ZoneData) []cloudprovider.Offering

        + CacheKey(nodeClass *v1.EC2NodeClass) string
        + Resolve(ctx context.Context, info types.InstanceTypeInfo, zoneData []ZoneData, nodeClass *v1.EC2NodeClass) *cloudprovider.InstanceType

    }
    class NetworkCard << (S,Aquamarine) >> {
        + MaximumNetworkInterfaces int64
        + NetworkCardIndex int64
        + NetworkPerformance string

    }
    interface Provider  {
        + List( context.Context,  *v1.EC2NodeClass) ([]*cloudprovider.InstanceType, error)

    }
    interface Resolver  {
        + CacheKey(nodeClass *v1.EC2NodeClass) string
        + Resolve(ctx context.Context, info types.InstanceTypeInfo, zoneData []ZoneData, nodeClass *v1.EC2NodeClass) *cloudprovider.InstanceType

    }
    class VPCLimits << (S,Aquamarine) >> {
        + Interface int
        + IPv4PerInterface int
        + IsTrunkingCompatible bool
        + BranchInterface int
        + NetworkCards []NetworkCard
        + DefaultNetworkCardIndex int
        + Hypervisor string
        + IsBareMetal bool

    }
    class ZoneData << (S,Aquamarine) >> {
        + Name string
        + ID string
        + Available bool

    }
}

"instancetype.Provider" <|-- "instancetype.DefaultProvider"
"instancetype.Resolver" <|-- "instancetype.DefaultResolver"

namespace interruption {
    class Controller << (S,Aquamarine) >> {
        - kubeClient client.Client
        - clk clock.Clock
        - recorder events.Recorder
        - sqsProvider sqs.Provider
        - unavailableOfferingsCache *cache.UnavailableOfferings
        - parser *EventParser
        - cm *pretty.ChangeMonitor

        - parseMessage(raw *types.Message) (messages.Message, error)
        - handleMessage(ctx context.Context, nodeClaimInstanceIDMap <font color=blue>map</font>[string]*v1.NodeClaim, nodeInstanceIDMap <font color=blue>map</font>[string]*v1.Node, msg messages.Message) error
        - deleteMessage(ctx context.Context, msg *types.Message) error
        - handleNodeClaim(ctx context.Context, msg messages.Message, nodeClaim *v1.NodeClaim, node *v1.Node) error
        - deleteNodeClaim(ctx context.Context, msg messages.Message, nodeClaim *v1.NodeClaim, node *v1.Node) error
        - notifyForMessage(msg messages.Message, nodeClaim *v1.NodeClaim, n *v1.Node) 
        - makeNodeClaimInstanceIDMap(ctx context.Context) (<font color=blue>map</font>[string]*v1.NodeClaim, error)
        - makeNodeInstanceIDMap(ctx context.Context) (<font color=blue>map</font>[string]*v1.Node, error)

        + Reconcile(ctx context.Context) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
    class interruption.Action << (T, #FF7700) >>  {
    }
}


namespace invalidation {
    class Controller << (S,Aquamarine) >> {
        - cache *cache.Cache
        - amiProvider amifamily.Provider

        + Name() string
        + Reconcile(ctx context.Context) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
}


namespace kompat {
    class Compatibility << (S,Aquamarine) >> {
        + AppVersion string
        + MinK8sVersion string
        + MaxK8sVersion string

    }
    class Kompat << (S,Aquamarine) >> {
        + Name string
        + Compatibility []Compatibility

        - expand() <font color=blue>map</font>[string][]string

        + Validate() error
        + JSON() string
        + YAML() string
        + Markdown(_ ...Options) string

    }
    class List << (S,Aquamarine) >> {
        - k8sVersions() []string

        + JSON() string
        + YAML() string
        + Markdown(opts ...Options) string

    }
    class Options << (S,Aquamarine) >> {
        + LastN int
        + Version string

    }
    class kompat.List << (T, #FF7700) >>  {
    }
}


namespace launchtemplate {
    class DefaultProvider << (S,Aquamarine) >> {
        - ec2api aws.EC2API
        - eksapi aws.EKSAPI
        - amiFamily amifamily.Resolver
        - securityGroupProvider securitygroup.Provider
        - subnetProvider subnet.Provider
        - cache *cache.Cache
        - cm *pretty.ChangeMonitor

        + KubeDNSIP net.IP
        + CABundle *string
        + ClusterEndpoint string
        + ClusterCIDR 

        - createAMIOptions(ctx context.Context, nodeClass *v1.EC2NodeClass, labels <font color=blue>map</font>[string]string, tags <font color=blue>map</font>[string]string) (*amifamily.Options, error)
        - ensureLaunchTemplate(ctx context.Context, options *amifamily.LaunchTemplate) (types.LaunchTemplate, error)
        - createLaunchTemplate(ctx context.Context, options *amifamily.LaunchTemplate) (types.LaunchTemplate, error)
        - generateNetworkInterfaces(options *amifamily.LaunchTemplate) []types.LaunchTemplateInstanceNetworkInterfaceSpecificationRequest
        - blockDeviceMappings(blockDeviceMappings []*v1.BlockDeviceMapping) []types.LaunchTemplateBlockDeviceMappingRequest
        - volumeSize(quantity *resource.Quantity) *int32
        - hydrateCache(ctx context.Context) 
        - cachedEvictedFunc(ctx context.Context) <font color=blue>func</font>(string, <font color=blue>interface</font>{}) 

        + EnsureAll(ctx context.Context, nodeClass *v1.EC2NodeClass, nodeClaim *v1.NodeClaim, instanceTypes []*cloudprovider.InstanceType, capacityType string, tags <font color=blue>map</font>[string]string) ([]*LaunchTemplate, error)
        + InvalidateCache(ctx context.Context, ltName string, ltID string) 
        + DeleteAll(ctx context.Context, nodeClass *v1.EC2NodeClass) error
        + ResolveClusterCIDR(ctx context.Context) error

    }
    class LaunchTemplate << (S,Aquamarine) >> {
        + Name string
        + InstanceTypes []*cloudprovider.InstanceType
        + ImageID string

    }
    interface Provider  {
        + EnsureAll( context.Context,  *v1.EC2NodeClass,  *v1.NodeClaim,  []*cloudprovider.InstanceType,  string,  <font color=blue>map</font>[string]string) ([]*LaunchTemplate, error)
        + DeleteAll( context.Context,  *v1.EC2NodeClass) error
        + InvalidateCache( context.Context,  string,  string) 
        + ResolveClusterCIDR( context.Context) error

    }
}
"sync.Mutex" *-- "launchtemplate.DefaultProvider"

"launchtemplate.Provider" <|-- "launchtemplate.DefaultProvider"

namespace main {
    class FakeFieldIndexer << (S,Aquamarine) >> {
        + IndexField(_ context.Context, _ client.Object, _ string, _ client.IndexerFunc) error

    }
    class FakeManager << (S,Aquamarine) >> {
        + GetClient() client.Client
        + GetConfig() *rest.Config
        + GetFieldIndexer() client.FieldIndexer
        + Elected() <font color=blue>chan</font> <font color=blue>struct</font>{}

    }
    class GlobalOptions << (S,Aquamarine) >> {
        + Verbose bool
        + Version bool
        + Output string

    }
    class Options << (S,Aquamarine) >> {
        - partition string
        - output string
        - sourceOutput string
        - urlInput string

    }
    class RootOptions << (S,Aquamarine) >> {
        + LastNVersions int
        + K8sVersion string
        + Branch string

    }
    class cluster << (S,Aquamarine) >> {
        + Name string
        + GitRef string
        + Cleanup bool

    }
    class metricInfo << (S,Aquamarine) >> {
        - namespace string
        - subsystem string
        - name string
        - help string

        - qualifiedName() string

    }
}
"manager.Manager" *-- "main.FakeManager"


namespace messages {
    interface Message  {
        + EC2InstanceIDs() []string
        + Kind() Kind
        + StartTime() time.Time

    }
    class Metadata << (S,Aquamarine) >> {
        + Account string
        + DetailType string
        + ID string
        + Region string
        + Resources []string
        + Source string
        + Time time.Time
        + Version string

        + StartTime() time.Time

    }
    interface Parser  {
        + Parse( string) (Message, error)
        + Version() string
        + Source() string
        + DetailType() string

    }
    class messages.Kind << (T, #FF7700) >>  {
    }
}


namespace metrics {
    interface Client  {
        + FireMetric(ctx context.Context, tableName string, metricName string, metricValue float64, region string) error

    }
    class TimeStream << (S,Aquamarine) >> {
        - timestreamClient *timestreamwrite.Client

        + FireMetric(ctx context.Context, tableName string, name string, value float64, region string) error

    }
}

"metrics.Client" <|-- "metrics.TimeStream"

namespace operator {
    class Operator << (S,Aquamarine) >> {
        + Config aws.Config
        + UnavailableOfferingsCache *cache.UnavailableOfferings
        + SSMCache *cache.Cache
        + SubnetProvider subnet.Provider
        + SecurityGroupProvider securitygroup.Provider
        + InstanceProfileProvider instanceprofile.Provider
        + AMIProvider amifamily.Provider
        + AMIResolver amifamily.Resolver
        + LaunchTemplateProvider launchtemplate.Provider
        + PricingProvider pricing.Provider
        + VersionProvider version.Provider
        + InstanceTypesProvider *instancetype.DefaultProvider
        + InstanceProvider instance.Provider
        + SSMProvider ssm.Provider

    }
}
"operator.Operator" *-- "operator.Operator"


namespace options {
    class Options << (S,Aquamarine) >> {
        + ClusterCABundle string
        + ClusterName string
        + ClusterEndpoint string
        + IsolatedVPC bool
        + VMMemoryOverheadPercent float64
        + InterruptionQueue string
        + ReservedENIs int

        - validateEndpoint() error
        - validateVMMemoryOverheadPercent() error
        - validateReservedENIs() error
        - validateRequiredFields() error

        + AddFlags(fs *options.FlagSet) 
        + Parse(fs *options.FlagSet, args ...string) error
        + ToContext(ctx context.Context) context.Context
        + Validate() error

    }
    class optionsKey << (S,Aquamarine) >> {
    }
}


namespace pricing {
    class DefaultProvider << (S,Aquamarine) >> {
        - ec2 aws.EC2API
        - pricing aws.PricingAPI
        - region string
        - cm *pretty.ChangeMonitor
        - muOnDemand sync.RWMutex
        - onDemandPrices <font color=blue>map</font>[types.InstanceType]float64
        - muSpot sync.RWMutex
        - spotPrices <font color=blue>map</font>[types.InstanceType]zonal
        - spotPricingUpdated bool

        - fetchOnDemandPricing(ctx context.Context, additionalFilters ...types.Filter) (<font color=blue>map</font>[types.InstanceType]float64, error)
        - spotPage(ctx context.Context, output *ec2.DescribeSpotPriceHistoryOutput) <font color=blue>map</font>[types.InstanceType]zonal
        - onDemandPage(ctx context.Context, output *pricing.GetProductsOutput) <font color=blue>map</font>[types.InstanceType]float64

        + InstanceTypes() []types.InstanceType
        + OnDemandPrice(instanceType types.InstanceType) (float64, bool)
        + SpotPrice(instanceType types.InstanceType, zone string) (float64, bool)
        + UpdateOnDemandPricing(ctx context.Context) error
        + UpdateSpotPricing(ctx context.Context) error
        + LivenessProbe(_ *http.Request) error
        + Reset() 

    }
    interface Provider  {
        + LivenessProbe( *http.Request) error
        + InstanceTypes() []types.InstanceType
        + OnDemandPrice( types.InstanceType) (float64, bool)
        + SpotPrice( types.InstanceType,  string) (float64, bool)
        + UpdateOnDemandPricing( context.Context) error
        + UpdateSpotPricing( context.Context) error

    }
    class zonal << (S,Aquamarine) >> {
        - defaultPrice float64
        - prices <font color=blue>map</font>[string]float64

    }
}

"pricing.Provider" <|-- "pricing.DefaultProvider"

namespace resourcetypes {
    class ENI << (S,Aquamarine) >> {
        - ec2Client *ec2.Client

        - getAllENIs(ctx context.Context, params *ec2.DescribeNetworkInterfacesInput) ([]types.NetworkInterface, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, ids []string) ([]string, error)

    }
    class Instance << (S,Aquamarine) >> {
        - ec2Client *ec2.Client

        - getAllInstances(ctx context.Context, params *ec2.DescribeInstancesInput) ([]types.Instance, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, ids []string) ([]string, error)

    }
    class InstanceProfile << (S,Aquamarine) >> {
        - iamClient *iam.Client

        - getAllInstanceProfiles(ctx context.Context) ([]types.InstanceProfile, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, names []string) ([]string, error)

    }
    class LaunchTemplate << (S,Aquamarine) >> {
        - ec2Client *ec2.Client

        - getAllLaunchTemplates(ctx context.Context, params *ec2.DescribeLaunchTemplatesInput) ([]types.LaunchTemplate, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, names []string) ([]string, error)

    }
    class OIDC << (S,Aquamarine) >> {
        - iamClient *iam.Client

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, arns []string) ([]string, error)

    }
    class SecurityGroup << (S,Aquamarine) >> {
        - ec2Client *ec2.Client

        - getAllSecurityGroups(ctx context.Context, params *ec2.DescribeSecurityGroupsInput) ([]types.SecurityGroup, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, ids []string) ([]string, error)

    }
    class Stack << (S,Aquamarine) >> {
        - cloudFormationClient *cloudformation.Client

        - getAllStacks(ctx context.Context) ([]types.Stack, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, names []string) ([]string, error)

    }
    interface Type  {
        + String() string
        + Global() bool
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + Cleanup(ctx context.Context, ids []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)

    }
    class VPCEndpoint << (S,Aquamarine) >> {
        - ec2Client *ec2.Client

        - getAllVpcEndpoints(ctx context.Context, params *ec2.DescribeVpcEndpointsInput) ([]types.VpcEndpoint, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, ids []string) ([]string, error)

    }
    class VPCPeeringConnection << (S,Aquamarine) >> {
        - ec2Client *ec2.Client

        - getAllVpcPeeringConnections(ctx context.Context, params *ec2.DescribeVpcPeeringConnectionsInput) ([]types.VpcPeeringConnection, error)

        + String() string
        + Global() bool
        + GetExpired(ctx context.Context, expirationTime time.Time, excludedClusters []string) ([]string, error)
        + CountAll(ctx context.Context) (int, error)
        + Get(ctx context.Context, clusterName string) ([]string, error)
        + Cleanup(ctx context.Context, ids []string) ([]string, error)

    }
}

"resourcetypes.Type" <|-- "resourcetypes.ENI"
"resourcetypes.Type" <|-- "resourcetypes.Instance"
"resourcetypes.Type" <|-- "resourcetypes.InstanceProfile"
"resourcetypes.Type" <|-- "resourcetypes.LaunchTemplate"
"resourcetypes.Type" <|-- "resourcetypes.OIDC"
"resourcetypes.Type" <|-- "resourcetypes.SecurityGroup"
"resourcetypes.Type" <|-- "resourcetypes.Stack"
"resourcetypes.Type" <|-- "resourcetypes.VPCEndpoint"
"resourcetypes.Type" <|-- "resourcetypes.VPCPeeringConnection"

namespace sdk {
    interface EC2API  {
        + DescribeImages( context.Context,  *ec2.DescribeImagesInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeImagesOutput, error)
        + DescribeLaunchTemplates( context.Context,  *ec2.DescribeLaunchTemplatesInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeLaunchTemplatesOutput, error)
        + DescribeSubnets( context.Context,  *ec2.DescribeSubnetsInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeSubnetsOutput, error)
        + DescribeSecurityGroups( context.Context,  *ec2.DescribeSecurityGroupsInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeSecurityGroupsOutput, error)
        + DescribeInstanceTypes( context.Context,  *ec2.DescribeInstanceTypesInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeInstanceTypesOutput, error)
        + DescribeInstanceTypeOfferings( context.Context,  *ec2.DescribeInstanceTypeOfferingsInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeInstanceTypeOfferingsOutput, error)
        + DescribeSpotPriceHistory( context.Context,  *ec2.DescribeSpotPriceHistoryInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeSpotPriceHistoryOutput, error)
        + CreateFleet( context.Context,  *ec2.CreateFleetInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.CreateFleetOutput, error)
        + TerminateInstances( context.Context,  *ec2.TerminateInstancesInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.TerminateInstancesOutput, error)
        + DescribeInstances( context.Context,  *ec2.DescribeInstancesInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DescribeInstancesOutput, error)
        + CreateTags( context.Context,  *ec2.CreateTagsInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.CreateTagsOutput, error)
        + CreateLaunchTemplate( context.Context,  *ec2.CreateLaunchTemplateInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.CreateLaunchTemplateOutput, error)
        + DeleteLaunchTemplate( context.Context,  *ec2.DeleteLaunchTemplateInput,  ...<font color=blue>func</font>(*ec2.Options) ) (*ec2.DeleteLaunchTemplateOutput, error)

    }
    interface EKSAPI  {
        + DescribeCluster( context.Context,  *eks.DescribeClusterInput,  ...<font color=blue>func</font>(*eks.Options) ) (*eks.DescribeClusterOutput, error)

    }
    interface IAMAPI  {
        + GetInstanceProfile( context.Context,  *iam.GetInstanceProfileInput,  ...<font color=blue>func</font>(*iam.Options) ) (*iam.GetInstanceProfileOutput, error)
        + CreateInstanceProfile( context.Context,  *iam.CreateInstanceProfileInput,  ...<font color=blue>func</font>(*iam.Options) ) (*iam.CreateInstanceProfileOutput, error)
        + DeleteInstanceProfile( context.Context,  *iam.DeleteInstanceProfileInput,  ...<font color=blue>func</font>(*iam.Options) ) (*iam.DeleteInstanceProfileOutput, error)
        + AddRoleToInstanceProfile( context.Context,  *iam.AddRoleToInstanceProfileInput,  ...<font color=blue>func</font>(*iam.Options) ) (*iam.AddRoleToInstanceProfileOutput, error)
        + TagInstanceProfile( context.Context,  *iam.TagInstanceProfileInput,  ...<font color=blue>func</font>(*iam.Options) ) (*iam.TagInstanceProfileOutput, error)
        + RemoveRoleFromInstanceProfile( context.Context,  *iam.RemoveRoleFromInstanceProfileInput,  ...<font color=blue>func</font>(*iam.Options) ) (*iam.RemoveRoleFromInstanceProfileOutput, error)

    }
    interface PricingAPI  {
        + GetProducts( context.Context,  *pricing.GetProductsInput,  ...<font color=blue>func</font>(*pricing.Options) ) (*pricing.GetProductsOutput, error)

    }
    interface SQSAPI  {
        + ReceiveMessage( context.Context,  *sqs.ReceiveMessageInput,  ...<font color=blue>func</font>(*sqs.Options) ) (*sqs.ReceiveMessageOutput, error)
        + DeleteMessage( context.Context,  *sqs.DeleteMessageInput,  ...<font color=blue>func</font>(*sqs.Options) ) (*sqs.DeleteMessageOutput, error)
        + SendMessage( context.Context,  *sqs.SendMessageInput,  ...<font color=blue>func</font>(*sqs.Options) ) (*sqs.SendMessageOutput, error)

    }
    interface SSMAPI  {
        + GetParameter( context.Context,  *ssm.GetParameterInput,  ...<font color=blue>func</font>(*ssm.Options) ) (*ssm.GetParameterOutput, error)

    }
    interface TimestreamWriteAPI  {
        + WriteRecords(ctx context.Context, params *timestreamwrite.WriteRecordsInput, optFns ...<font color=blue>func</font>(*timestreamwrite.Options) ) (*timestreamwrite.WriteRecordsOutput, error)

    }
}


namespace securitygroup {
    class DefaultProvider << (S,Aquamarine) >> {
        - ec2api aws.EC2API
        - cache *cache.Cache
        - cm *pretty.ChangeMonitor

        - getSecurityGroups(ctx context.Context, filterSets [][]types.Filter) ([]types.SecurityGroup, error)

        + List(ctx context.Context, nodeClass *v1.EC2NodeClass) ([]types.SecurityGroup, error)

    }
    interface Provider  {
        + List( context.Context,  *v1.EC2NodeClass) ([]types.SecurityGroup, error)

    }
}
"sync.Mutex" *-- "securitygroup.DefaultProvider"

"securitygroup.Provider" <|-- "securitygroup.DefaultProvider"

namespace sqs {
    class DefaultProvider << (S,Aquamarine) >> {
        - client aws.SQSAPI
        - queueURL string

        + Name() string
        + GetSQSMessages(ctx context.Context) ([]*types.Message, error)
        + SendMessage(ctx context.Context, body <font color=blue>interface</font>{}) (string, error)
        + DeleteSQSMessage(ctx context.Context, msg *types.Message) error

    }
    interface Provider  {
        + Name() string
        + GetSQSMessages( context.Context) ([]*types.Message, error)
        + SendMessage( context.Context,  <font color=blue>interface</font>{}) (string, error)
        + DeleteSQSMessage( context.Context,  *types.Message) error

    }
}

"sqs.Provider" <|-- "sqs.DefaultProvider"

namespace ssm {
    class CacheEntry << (S,Aquamarine) >> {
        + Parameter Parameter
        + Value string

    }
    class DefaultProvider << (S,Aquamarine) >> {
        - cache *cache.Cache
        - ssmapi aws.SSMAPI

        + Get(ctx context.Context, parameter Parameter) (string, error)

    }
    class Parameter << (S,Aquamarine) >> {
        + Name string
        + IsMutable bool

        + GetParameterInput() *ssm.GetParameterInput
        + CacheKey() string

    }
    interface Provider  {
        + Get( context.Context,  Parameter) (string, error)

    }
}
"sync.Mutex" *-- "ssm.DefaultProvider"

"ssm.Provider" <|-- "ssm.DefaultProvider"

namespace statechange {
    class Detail << (S,Aquamarine) >> {
        + InstanceID string
        + State string

    }
    class Message << (S,Aquamarine) >> {
        + Detail Detail

        + EC2InstanceIDs() []string
        + Kind() messages.Kind

    }
}
"messages.Metadata" *-- "statechange.Message"


namespace status {
    class AMI << (S,Aquamarine) >> {
        - amiProvider amifamily.Provider

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)

    }
    class Controller << (S,Aquamarine) >> {
        - kubeClient client.Client
        - ami *AMI
        - instanceprofile *InstanceProfile
        - subnet *Subnet
        - securitygroup *SecurityGroup
        - readiness *Readiness

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
    class InstanceProfile << (S,Aquamarine) >> {
        - instanceProfileProvider instanceprofile.Provider

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)

    }
    class Readiness << (S,Aquamarine) >> {
        - launchTemplateProvider launchtemplate.Provider

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)

    }
    class SecurityGroup << (S,Aquamarine) >> {
        - securityGroupProvider securitygroup.Provider

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)

    }
    class Subnet << (S,Aquamarine) >> {
        - subnetProvider subnet.Provider

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)

    }
    interface nodeClassStatusReconciler  {
        + Reconcile( context.Context,  *v1.EC2NodeClass) (reconcile.Result, error)

    }
}

"status.nodeClassStatusReconciler" <|-- "status.AMI"
"status.nodeClassStatusReconciler" <|-- "status.Controller"
"status.nodeClassStatusReconciler" <|-- "status.InstanceProfile"
"status.nodeClassStatusReconciler" <|-- "status.Readiness"
"status.nodeClassStatusReconciler" <|-- "status.SecurityGroup"
"status.nodeClassStatusReconciler" <|-- "status.Subnet"

namespace subnet {
    class DefaultProvider << (S,Aquamarine) >> {
        - ec2api aws.EC2API
        - cache *cache.Cache
        - availableIPAddressCache *cache.Cache
        - associatePublicIPAddressCache *cache.Cache
        - cm *pretty.ChangeMonitor
        - inflightIPs <font color=blue>map</font>[string]int32

        - minPods(instanceTypes []*cloudprovider.InstanceType, reqs scheduling.Requirements) int32

        + List(ctx context.Context, nodeClass *v1.EC2NodeClass) ([]types.Subnet, error)
        + ZonalSubnetsForLaunch(ctx context.Context, nodeClass *v1.EC2NodeClass, instanceTypes []*cloudprovider.InstanceType, capacityType string) (<font color=blue>map</font>[string]*Subnet, error)
        + UpdateInflightIPs(createFleetInput *ec2.CreateFleetInput, createFleetOutput *ec2.CreateFleetOutput, instanceTypes []*cloudprovider.InstanceType, subnets []*Subnet, capacityType string) 
        + LivenessProbe(_ *http.Request) error

    }
    interface Provider  {
        + LivenessProbe( *http.Request) error
        + List( context.Context,  *v1.EC2NodeClass) ([]types.Subnet, error)
        + ZonalSubnetsForLaunch( context.Context,  *v1.EC2NodeClass,  []*cloudprovider.InstanceType,  string) (<font color=blue>map</font>[string]*Subnet, error)
        + UpdateInflightIPs( *ec2.CreateFleetInput,  *ec2.CreateFleetOutput,  []*cloudprovider.InstanceType,  []*Subnet,  string) 

    }
    class Subnet << (S,Aquamarine) >> {
        + ID string
        + Zone string
        + ZoneID string
        + AvailableIPAddressCount int32

    }
}
"sync.Mutex" *-- "subnet.DefaultProvider"

"subnet.Provider" <|-- "subnet.DefaultProvider"

namespace tagging {
    class Controller << (S,Aquamarine) >> {
        - kubeClient client.Client
        - instanceProvider instance.Provider

        - tagInstance(ctx context.Context, nc *v1.NodeClaim, id string) error

        + Reconcile(ctx context.Context, nodeClaim *v1.NodeClaim) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
}


namespace termination {
    class Controller << (S,Aquamarine) >> {
        - kubeClient client.Client
        - recorder events.Recorder
        - instanceProfileProvider instanceprofile.Provider
        - launchTemplateProvider launchtemplate.Provider

        - finalize(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)

        + Reconcile(ctx context.Context, nodeClass *v1.EC2NodeClass) (reconcile.Result, error)
        + Register(_ context.Context, m manager.Manager) error

    }
}

"status.nodeClassStatusReconciler" <|-- "termination.Controller"

namespace test {
    class Environment << (S,Aquamarine) >> {
        + Clock *testing.FakeClock
        + EC2API *fake.EC2API
        + EKSAPI *fake.EKSAPI
        + SSMAPI *fake.SSMAPI
        + IAMAPI *fake.IAMAPI
        + PricingAPI *fake.PricingAPI
        + EC2Cache *cache.Cache
        + KubernetesVersionCache *cache.Cache
        + InstanceTypeCache *cache.Cache
        + UnavailableOfferingsCache *cache.UnavailableOfferings
        + LaunchTemplateCache *cache.Cache
        + SubnetCache *cache.Cache
        + AvailableIPAdressCache *cache.Cache
        + AssociatePublicIPAddressCache *cache.Cache
        + SecurityGroupCache *cache.Cache
        + InstanceProfileCache *cache.Cache
        + SSMCache *cache.Cache
        + DiscoveredCapacityCache *cache.Cache
        + InstanceTypesResolver *instancetype.DefaultResolver
        + InstanceTypesProvider *instancetype.DefaultProvider
        + InstanceProvider *instance.DefaultProvider
        + SubnetProvider *subnet.DefaultProvider
        + SecurityGroupProvider *securitygroup.DefaultProvider
        + InstanceProfileProvider *instanceprofile.DefaultProvider
        + PricingProvider *pricing.DefaultProvider
        + AMIProvider *amifamily.DefaultProvider
        + AMIResolver *amifamily.DefaultResolver
        + VersionProvider *version.DefaultProvider
        + LaunchTemplateProvider *launchtemplate.DefaultProvider

        + Reset() 

    }
    class OptionsFields << (S,Aquamarine) >> {
        + ClusterCABundle *string
        + ClusterName *string
        + ClusterEndpoint *string
        + IsolatedVPC *bool
        + VMMemoryOverheadPercent *float64
        + InterruptionQueue *string
        + ReservedENIs *int

    }
}


namespace v1 {
    class AMI << (S,Aquamarine) >> {
        + ID string
        + Name string
        + Requirements []v1.NodeSelectorRequirement

        + DeepCopyInto(out *AMI) 
        + DeepCopy() *AMI

    }
    class AMISelectorTerm << (S,Aquamarine) >> {
        + Alias string
        + Tags <font color=blue>map</font>[string]string
        + ID string
        + Name string
        + Owner string

        + DeepCopyInto(out *AMISelectorTerm) 
        + DeepCopy() *AMISelectorTerm

    }
    class Alias << (S,Aquamarine) >> {
        + Family string
        + Version string

        + String() string
        + DeepCopyInto(out *Alias) 
        + DeepCopy() *Alias

    }
    class BlockDevice << (S,Aquamarine) >> {
        + DeleteOnTermination *bool
        + Encrypted *bool
        + IOPS *int64
        + KMSKeyID *string
        + SnapshotID *string
        + Throughput *int64
        + VolumeSize *resource.Quantity
        + VolumeType *string

        + DeepCopyInto(out *BlockDevice) 
        + DeepCopy() *BlockDevice

    }
    class BlockDeviceMapping << (S,Aquamarine) >> {
        + DeviceName *string
        + EBS *BlockDevice
        + RootVolume bool

        + DeepCopyInto(out *BlockDeviceMapping) 
        + DeepCopy() *BlockDeviceMapping

    }
    class EC2NodeClass << (S,Aquamarine) >> {
        + Spec EC2NodeClassSpec
        + Status EC2NodeClassStatus

        + Hash() string
        + InstanceProfileName(clusterName string, region string) string
        + InstanceProfileRole() string
        + InstanceProfileTags(clusterName string) <font color=blue>map</font>[string]string
        + AMIFamily() string
        + Alias() *Alias
        + SetDefaults(_ context.Context) 
        + StatusConditions() status.ConditionSet
        + GetConditions() []status.Condition
        + SetConditions(conditions []status.Condition) 
        + DeepCopyInto(out *EC2NodeClass) 
        + DeepCopy() *EC2NodeClass
        + DeepCopyObject() runtime.Object

    }
    class EC2NodeClassList << (S,Aquamarine) >> {
        + Items []EC2NodeClass

        + DeepCopyInto(out *EC2NodeClassList) 
        + DeepCopy() *EC2NodeClassList
        + DeepCopyObject() runtime.Object

    }
    class EC2NodeClassSpec << (S,Aquamarine) >> {
        + SubnetSelectorTerms []SubnetSelectorTerm
        + SecurityGroupSelectorTerms []SecurityGroupSelectorTerm
        + AssociatePublicIPAddress *bool
        + AMISelectorTerms []AMISelectorTerm
        + AMIFamily *string
        + UserData *string
        + Role string
        + InstanceProfile *string
        + Tags <font color=blue>map</font>[string]string
        + Kubelet *KubeletConfiguration
        + BlockDeviceMappings []*BlockDeviceMapping
        + InstanceStorePolicy *InstanceStorePolicy
        + DetailedMonitoring *bool
        + MetadataOptions *MetadataOptions
        + Context *string

        + DeepCopyInto(out *EC2NodeClassSpec) 
        + DeepCopy() *EC2NodeClassSpec

    }
    class EC2NodeClassStatus << (S,Aquamarine) >> {
        + Subnets []Subnet
        + SecurityGroups []SecurityGroup
        + AMIs []AMI
        + InstanceProfile string
        + Conditions []status.Condition

        + DeepCopyInto(out *EC2NodeClassStatus) 
        + DeepCopy() *EC2NodeClassStatus

    }
    class KubeletConfiguration << (S,Aquamarine) >> {
        + ClusterDNS []string
        + MaxPods *int32
        + PodsPerCore *int32
        + SystemReserved <font color=blue>map</font>[string]string
        + KubeReserved <font color=blue>map</font>[string]string
        + EvictionHard <font color=blue>map</font>[string]string
        + EvictionSoft <font color=blue>map</font>[string]string
        + EvictionSoftGracePeriod <font color=blue>map</font>[string]v1.Duration
        + EvictionMaxPodGracePeriod *int32
        + ImageGCHighThresholdPercent *int32
        + ImageGCLowThresholdPercent *int32
        + CPUCFSQuota *bool

        + DeepCopyInto(out *KubeletConfiguration) 
        + DeepCopy() *KubeletConfiguration

    }
    class MetadataOptions << (S,Aquamarine) >> {
        + HTTPEndpoint *string
        + HTTPProtocolIPv6 *string
        + HTTPPutResponseHopLimit *int64
        + HTTPTokens *string

        + DeepCopyInto(out *MetadataOptions) 
        + DeepCopy() *MetadataOptions

    }
    class SecurityGroup << (S,Aquamarine) >> {
        + ID string
        + Name string

        + DeepCopyInto(out *SecurityGroup) 
        + DeepCopy() *SecurityGroup

    }
    class SecurityGroupSelectorTerm << (S,Aquamarine) >> {
        + Tags <font color=blue>map</font>[string]string
        + ID string
        + Name string

        + DeepCopyInto(out *SecurityGroupSelectorTerm) 
        + DeepCopy() *SecurityGroupSelectorTerm

    }
    class Subnet << (S,Aquamarine) >> {
        + ID string
        + Zone string
        + ZoneID string

        + DeepCopyInto(out *Subnet) 
        + DeepCopy() *Subnet

    }
    class SubnetSelectorTerm << (S,Aquamarine) >> {
        + Tags <font color=blue>map</font>[string]string
        + ID string

        + DeepCopyInto(out *SubnetSelectorTerm) 
        + DeepCopy() *SubnetSelectorTerm

    }
    class v1.InstanceStorePolicy << (T, #FF7700) >>  {
    }
}
"v1.ObjectMeta" *-- "v1.EC2NodeClass"
"v1.TypeMeta" *-- "v1.EC2NodeClass"
"v1.ListMeta" *-- "v1.EC2NodeClassList"
"v1.TypeMeta" *-- "v1.EC2NodeClassList"


namespace version {
    class DefaultProvider << (S,Aquamarine) >> {
        - cache *cache.Cache
        - cm *pretty.ChangeMonitor
        - kubernetesInterface kubernetes.Interface

        + Get(ctx context.Context) (string, error)

    }
    interface Provider  {
        + Get(ctx context.Context) (string, error)

    }
}

"version.Provider" <|-- "version.DefaultProvider"

"__builtin__.string" #.. "amifamily.Variant"
"__builtin__.string" #.. "aws.EventType"
"__builtin__.string" #.. "bootstrap.BootstrapCommandMode"
"__builtin__.string" #.. "common.ContextKey"
"__builtin__.string" #.. "interruption.Action"
"__builtin__.string" #.. "messages.Kind"
"__builtin__.string" #.. "v1.InstanceStorePolicy"
"amifamily.[]AMI" #.. "amifamily.AMIs"
"kompat.[]Kompat" #.. "kompat.List"
@enduml
