Depending on your use case, ec2_eip is not idempotent. I would like to attach a new EIP to an instance iff the instance doesn’t already have an EIP attached.
Currently, the module operates in two modes:
if you don’t specify an existing EIP address, the module will attach a new arbitrary EIP regardless of whether the instance already has one attached (not idempotent).
if you do specify an existing EIP address, then the module will attach that EIP iff the EIP is not attached to any instance.
It seems like case (1) should be idempotent and assume that an instance with an already-attached EIP requires no change.
Idempotent is one of those frequently misused words.
Mathematically it basically means F(x) = F(F(x)) for all x. Calling the same thing twice should return the thing that you got when you called it the first time.
For this reason, we don’t frequently use this word to describe bugs about things not doing what you’d suspect, or even if it’s just reporting changes that don’t happen.
As such, I’d rather get down to the root of the problem.
It seems if you are asking for an EIP and don’t specify which one, you’re probably asking for a new one.
You seem to think that asking for an EIP should not give you a new one, because the instance already has one.
This may imply a new mode flag (defaulting to the present behavior) should possibly exist for the module. What do others think?
I agree with Michael on the variable expectations on idempotency here.
Is the command ‘date’ idempotent? It can be invoked with no arguments and almost always returns a different value - but results in no perceivable state change on the system where the command was called.
What about the ‘touch’ command? It takes an argument, always ‘does the same thing’ (update mtime to ‘now’ whatever the value of now may be)… results in a perceivable state change.
If “now” is viewed as a relative constant, the result of this action on the system is idempotent in spirit. If the absolute value of time is the constant in mind, then it’s never idempotent - even in spirit.
It’s a slippery slope
In this specific case, I think the spirit would be better served if:
You could query the instance to check whether or not it had an EIP allocated to it
Use the results of the query and express it as a ‘when’ condition that triggered or skipped the eip command. If you had a specific EIP in mind, then the when condition could be expressed as an equality with the specific EIP as well
I noticed I was running out of EIPs, each call created a new one but didn’t associate it (as the instance already had one!) … so I just added a “when” the instance.public_ip == none … works like a charm
I personally think that if no public IP is specified, but an instance ID is provided, then nothing should be done if that instance already has an elastic IP attached to it.
If we want to simply allocate a new Elastic IP, then I agree that that should simply be a new state flag, state=‘allocate’, as Micheal suggested.