brendanhay / amazonka

A comprehensive Amazon Web Services SDK for Haskell.
https://amazonka.brendanhay.nz
Other
599 stars 227 forks source link

No way to fetch values of named Tags in IMDS Instance Metadata #954

Closed ulidtko closed 1 year ago

ulidtko commented 1 year ago

Hi!

Just got to trying the 2.0.0 release, well done :muscle: Sincerely appreciated.

An immediate issue with EC2 Metadata: using amazonka, it's impossible to fetch actual values of instance Tags.

To showcase what I mean, here I'm primarily interested in the Name instance tag:

$ curl http://instance-data/latest/meta-data/tags/instance/Name
app-dev-04
# ↑↑↑ the Name tag value I need to fetch in app

$ curl http://instance-data/latest/meta-data/tags/instance/
Cost_center
Customer
Environment
Name
Type
# ↑↑↑ all instance tags, \n-separated... keys only! no values!

Given this:

https://github.com/brendanhay/amazonka/blob/e081929d5a81f30397c9c9a219b154da1a922fb8/lib/amazonka/src/Amazonka/EC2/Metadata.hs#L576-L587

— it's only possible to do the 2nd curl, obtaining the result "Cost_center\nCustomer\nEnvironment\nName\nType" — which for my purpose is (obviously, I hope) utterly useless. The 1st curl which I need, is impossible to express.

I've attempted to work around by:

data InstanceNameTag = InstanceNameTag
instance AmazonkaCore.ToText InstanceNameTag where toText _ = "instance/Name"

    {- ... -}
    instanceName <- IMDS.metadata man InstanceNameTag

— but ofcourse, it's a type error :confused:

src/Application/Metrics.hs:159:37: error:
    • Couldn't match expected type ‘Metadata’
                  with actual type ‘InstanceNameTag’
    • In the second argument of ‘metadata’, namely ‘InstanceNameTag’
      In a stmt of a 'do' block:
        instanceName <- metadata man InstanceNameTag
      In the expression:
        do instanceId <- metadata man InstanceId <&> decodeUtf8
           machineName <- metadata man (Tags Instance) <&> showT
           instanceName <- metadata man InstanceNameTag
           let (internalIpv4, internalPort) = ...
           ....
    |       
159 |   instanceName <- IMDS.metadata man InstanceNameTag
    |                                     ^^^^^^^^^^^^^^^

Would it sound sensible to add a constructor like so

data Tags
  = Instance
  | InstanceTag !Text

— to allow querying any named tag using amazonka? Or extend Metadata instead?

Or am I missing some other way to extend here on the side of library-user?

I can develop a patch and file a PR if any of above sounds any good. Just let me know.

ulidtko commented 1 year ago

A direct "curl" via http-client got me a workaround:

    imdsInstanceName = do
      req <- parseRequest "http://instance-data/latest/meta-data/instance/tags/Name"
      httpLbs req man <&> decodeUtf8 . responseBody

But it's a pity that amazonka doesn't support this! Especially since #831 implements IMDSv2 which is more of a hassle to roll-your-own.

endgame commented 1 year ago

Some thoughts:

  1. Should we have an Other constructor on data Metadata so that we can have reasonable workarounds until things get fixed.?
  2. Would it sound sensible to add a constructor like so: data Tags = Instance | InstanceTag !Text

    Yes. I'd take a PR for this. It'd need some explicit documentation because this is not obvious from the main page. Maybe a link to https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html#instance-metadata-ex-7 ?