I hate to say this but I think we need solid abstraction of the cloud providers otherwise you'll end up locked into one, and that probably won't be much fun in the long term.
Agreed about the abstraction. In my view it works best when the abstraction is related to higher-level concepts that are implemented on top of the different clouds, like e.g. self-service, events and automation. This is where ManageIQ focuses.
Abstracting at the same level, while useful and provided by ManageIQ, gets into the "lowest common denominator vs cloud specific APIs" trade off. This is where libraries like e.g. Fog play.
Ultimately you need to make the choice about whether you're going to write applications in a way that make use of elements (like language frameworks) that are portable across providers along with the fairly standard software defined services.
Today, there is abstraction across a number of those standard services but, if you look at AWS for example, there's a lot of AWS-specific services that you're going to have to reimplement--largely from scratch--if you move off AWS. That may be a rational bet for some companies to make if one or more of those services provide a lot of value. But I'd hope it's a bet that they make deliberately rather than falling into it and waking up one day to discover that they have no practical way to move providers.
My view/hope is that at least for basic application level services, that the abstraction is going to be provided by containers and their orchestration platforms (e.g. Docker/Kube). It can credibly give you scaling, data persistence, network isolation, service discovery, load balancing, and with some work, a database (when packaged in a container with a persistent volume). An app using only these basic services basically has zero cloud lock-in.
On top of this there are many additional useful services that AWS, GCP and Azure provide. Using those does indeed give you some level of lock in, but only when these services are not available as a generic TCP/IP services (or not performant when accessed from a different cloud). This is where application designers need to make a trade off.
Agree 100%. In addition to language frameworks, as you say, you also have orchestration, application definition, failover, storage persistence, etc. services that can be made largely portable between providers. Containers, while probably not necessary, likely help by letting you decompose things and package them up in a way that you can move them between providers.