 All right, let's go ahead and get this session started here. I think it's just about right on time. Folks are coming in here, but that's all good. There's plenty of room more on the right side here, too. Come on in. All right, so this is the cross-plane introduction and deep dive session. My name is Jared Watts. There's co-speaker Nick Cope coming on right away here. We are both creators, maintainers, steering committee folks for cross-plane, so it is definitely a project that is near and dear to our hearts. All right. So this is a combined session, as we do every year, with both an intro and a deep dive part, right? So we're going to get into the introduction stuff that some of you all may have seen. It may be a refresher for some of you, but we've got to start with what cross-plane actually is. So the best way to think about cross-plane is that it is a framework for building your own opinionated, cloud-native control plane. You shouldn't have to write any code to do that. We'll talk a little bit later on in this session about ways that you can now actually write code, but you should be able to do it, you know, create your own opinionated control plane in a declarative fashion. So the cloud providers, they've been running control planes for years, right? They manage their infrastructure with control planes, and so cross-plane gives you a way to be able to essentially build your own in your own opinionated way to run your infrastructure. It's important to think about cross-plane as a project in the middle there with a top layer and a bottom layer. So on the bottom, you've got an extensibility story for providers that can teach cross-plane pretty much to manage any infrastructure in any environment as long as it has an API. And then on the top layer, you can essentially compose resources together and then offer them as a new platform API and as an abstraction to your developers so it's extensible on both the front end and the back end. Might not make sense yet, but we will see it as it keeps going on here. Just a little bit of background history of the project. We are coming up on five years in the cross-plane project. We took it public in December of 2018, so next month, it'll be five years. Pretty excited about that. We donated it to the CNCF in 2020. Then we've been continuing to mature along there. We're in the incubating stage now and we're hoping next year to move to a fully graduated stage. And we'll need your help for that so that we'll talk about that in a bit too. And then we are just now coming off the heels of our latest release, the cross-plane 1.14 release came out just last week. So it is super fresh and we'll be talking about some of the key features that were in that release, which is our biggest release we've ever done. Numbers, stats for the project, the key thing here is that it's continuing to grow, but the one that's, I think, most interesting recently is that just last week, or maybe just with the last week, it's a lot going on in cross-plane, is we crossed 10,000 members of the Slack workspace, so we're super active there, super busy. It's a good place to get in touch with other people in the community. All right, let's talk about what cross-plane does and start seeing some tangible examples of it. So cross-plane, at its foundational layer there, is a way to manage resources that are in the cloud, on-premises, et cetera. So in cross-plane, you can represent entities or objects in the real world as resources within the control plane. So let's take, for example, AWS. There's over 900 different types of resources there. In cross-plane, there will be over 900 different resources that represent every service and everything that you can do within AWS, same for GCP, Azure, et cetera. So you know all the different things in AWS and other cloud providers like networking, clusters, caches, databases, all that sort of stuff. It is represented in cross-plane as an object that you can create and manipulate, et cetera. And cross-plane goes out into the real world and makes it happen for you. So what does a managed resource look like? Well, let's take, for example, an Amazon S3 bucket. So on the left side of the screen here, we see a way to declaratively configure an Amazon bucket. So you see there, that's all yaml there, you can specify the configuration for that bucket. And then in the real world, out in AWS, there will be, you know, cross-plane will make it so so that there is a S3 bucket out there in the real world as well. Just like any good Kubernetes object, all the cross-plane resources also follow a consistent resource model. So you'll see, you know, in addition to spec fields for, you know, declaring what you want in your bucket, it'll also have status fields that shows you the latest, you know, the latest fields and values from the real world. And then also events that tell a story of what's happening with that object as it's going through its life cycle. So the way this actually works is probably like you would expect. You know, there's a whole bunch of custom resource definitions, CRDs, that represent all those objects and, you know, services and everything out in the cloud and on-premises and all that stuff. So if we work our way from the left side of the diagram over to the right, we'll see that we start with a buckets custom resource and then, you know, as you as a user can use kubectl, get ops, whatever you want to apply that to your Kubernetes cluster, the API server accepts that. And then there's a set of controllers in cross-plane, and for instance here, an S3 controller that's sitting there in a reconciliation loop. It's waiting for events from the Kubernetes API server. The API server says, hey, an S3 bucket has been requested, then the S3 controller goes and tries to reconcile that with the real world by talking to AWS over its API. So you ask for a bucket out there on Amazon, it'll happen. Let's not get too bogged down in the details on this one here, but this is basically the tech stack of cross-plane. So at the top, there's a whole, you know, hundreds of custom controllers that each deal with reconciling one type of resource, and then there's a common cross-plane runtime layer that provides, you know, useful functionality that kind of works for managing cloud infrastructure and resources like cross-plane is intended to do. And then underneath that, there is all sorts of Kubernetes common functionality. So we make use of the controller runtime to build our controllers and reconciliation loops within cross-plane, and then all the Kubernetes API machinery, the resource model, the runtime, all that stuff is very heavily used as well. All right, so we've been talking about these granular, fine-grained services and resources, but just those by itself of being able to create a bucket or create a database or whatever, by that itself does not really make a cloud native control plane or a platform. So let's see how cross-plane then lets you take these fine-grained resources and make a true platform out of them. All right, so this is some of the special sauce in cross-plane. This is what kind of differentiates it from other infrastructure-focused projects, I think. And so what cross-plane lets you do here is that it lets you assemble together a bunch of these granular, fine-grained resources, even from multiple clouds, doesn't matter where they're coming from, but you can assemble them together and then expose those as a higher level of abstraction, a simplified abstraction to your developers, your app teams. So to make that tangible, you can say, take together like a GKE cluster, node pool, network, subnet, all that sort of stuff that it takes to deploy a full working Kubernetes production cluster in GCP, and then you can compose them all together into a single abstraction, a single simplified resource that you then offer as a cluster resource to your developers. So your developers will see a cluster, but under the covers, it's all that more complicated, complex machinery. So the point of that is to not expose that environmental complexity to your developers. You make a simplified abstraction, you give that to them underneath the covers. You have that complexity, but then you can also specify all your organizational policy and configuration, essentially golden paths. You can codify your golden paths into something simple underneath there, sorry, into a simplified abstraction up top. And then as we talked about before, you normally don't have to write any code to do this at all. You can do it in a declarative fashion. All right, so finally, let's look at a picture of this, because we've been looking at a lot of text, and I think a picture is gonna help a lot here. So this is the resource model in crossplane, and let's work our way left to right. So we've got claims on the left. The developer is there, she's eating her popsicle, and she wants a simplified experience to be able to just use a simplified abstraction to get the infrastructure that she needs. So on the left side of the line here, that's what the developer is interacting with, and on the right side of the line here, this is all the platform engineer complexity that they codify and put together into a simplified abstraction. So we've got compositions, that's where you're composing together all of these managed resources. You can have multiple ones of those, and one of them will be selected at runtime. And then this composite resource definition, that's what defines the shape of the abstraction and what configuration knobs and inputs and values that your developer is allowed to touch or allowed to specify. That's the shape of the API and the abstraction that you're giving to them. So let's make that tangible, where you want to be able to have your developer's self-service get a database on demand when they want one, right? So the abstraction that you're gonna give to them is a Postgres abstraction. And so your developer can come and they can say, okay, I want a small Postgres instance, that's what I want. Now underneath the covers, you as a platform engineer, you've defined what that actually means by means of a composition. So when the developer asks for a Postgres underneath the covers here in this example, at runtime, they're going to get an AWS composition. Now it could be GCP, it could be Azure, DigitalOcean, whatever, fast, slow, cheap, expensive, gold, silver, it doesn't matter. One of those compositions gets selected at runtime. And then for AWS, it's going to be the RDS database, the DB parameter groups, security groups, and all that sort of stuff. All right, so what do these composite resources look like? This is kind of the left side of the slide here where, to your developer, you've got to define a contract of, in my platform, I'm going to offer to you a simplified abstraction and something for NoSQL or Postgres or whatever it's gonna be. But you as a platform engineer gets to define that through the shape of your API, all the different fields and values that they're allowed to set, you do that through a composite resource definition with a standard open API v3 schema that says, this is the fields, they can set, these are the ones that are required, all that sort of stuff. Now then underneath that, there will be a number of run time or compositions that can be selected at runtime, and those are what specifies what resources are going to get composed together so that the developer will end up getting the real infrastructure that they need. And then Nick is gonna talk a lot more about an update to this, which is pretty important in the latest release, but one way that you can specify right now of the developer has these specific configuration values that they've said, for instance, a location field of where they want this resource to be, and then you need some sort of way to take the simplified configuration on the abstraction to your developers, you need some way to take that and then apply it to the smaller, the lower fine grained resources. So we do that through patches and transforms here, where you can say, okay, when the developer specifies location, I want you to go ahead and apply that down to the managed resource on the region field, and then when they say EU, go ahead and map that, transform that into this particular EU region, and when they say US, transform that into this particular US region. So this gives you a sense of how you can compose resources together, and then let the developer influence through limited configuration how the resources come out the other side. So there's a lot of different ways to extend the crossplane, right? It's a framework, so there's multiple different extensions points for it here, and so we're gonna talk about a couple of them real quick. So providers, we kind of talked about that's what teaches crossplane, how to deal with new environments, new infrastructure. So there's a new one for Amazon, right? There's one for Alibaba and et cetera, other types of environments. Things you might not expect either, like there's a GitLab, Git Hub one, there's one for Argo, there's all sorts of things that you control by creating a provider for it and letting crossplane use that to learn new environments. Configurations are how you package up all of your compositions and redistribute them so you can then apply them to different clusters within your environments and get them out to the environments that they need to run in. And so Nick is gonna focus almost entirely, I think, on functions. So just a quick hint at that is that you can do all this stuff without writing code, but what if you wanna take it a little bit further and write some custom logic? And then so we have a new extension point in crossplane that is functions that allows you to write code when you need it. There's a whole bunch of providers, as you mentioned, the ecosystem. I think this is actually out of date because there's some new providers that come up from the community all the time and so this is the start and there's a lot more also. And we're always happy to have more providers in the ecosystem. So if you're interested in making some, just let us know. We'll be happy to work with you on it. And so with this ecosystem of providers, where do you find them? There is a single point where all the providers are being pushed to, they're being aggregated there. And so it's a place to go, discover what's out there, get documentation for it, examples, et cetera and kinda learn how to do everything you can with crossplane. So that's it. The marketplace for crossplane at marketplace.upbound.io. And that's kind of a rallying point for everything that's going on in the crossplane ecosystem. All right, so that was the intro session. So we've kinda talked about everything the crossplane can do from a very high level. And so now we're moving down into the deeper dive session here. And we're gonna talk about some of the new stuff in 1.14, which is, as I mentioned, it was literally our biggest release we've ever done. So a lot of cool stuff to talk about there. All right, so ordered deletion. That's something that people have asked for a lot. Once you get into production usage and enterprise usage, heavy usage across plane, you see that you need something to deal with being able to delete things in a consistent ordered fashion. So let's talk about why that happens. So Kubernetes is eventually consistent. And that is super, super useful and super cool when you're creating resources because you can throw 10, 100, whatever. You can throw all these resources at crossplane. It will try to reconcile all of them. There could be dependencies between them. You don't really have to think about that very much because with the beauty of active reconciliation and eventual consistency, if it doesn't work the first time, it'll try again. So you will eventually get all the resources created, the ones with the dependencies, everything's there. It's all good. It's not complex. You got loose coupling, everything works well. That cannot be said about deletions, unfortunately. When you need to delete an object that may be depended upon by another object, you've got to be cognizant of that. You have to be aware of that. If you delete that one object, the other one may not be able to clean itself up. So you've got to have some means of making sure that everything gets deleted in an orderly sequence or a fashion there. So one instance or one example of this is a Helm release or a Helm chart and a EKS cluster. If you delete the EKS cluster, well, you can't do much with the Helm chart anymore. It's kind of, you don't really know what state it's in. You could assume it got cleaned up, but you don't really know. So there's lots of examples of that where something, an object being depended upon by something else means you need to be aware of that. So what does that mean? How has Crospin attempted to solve this problem? So a new feature in 1.14 is for order deletion and we're calling it the usage API. So you could essentially capture or model relationships, like dependency relationships between resources in Crospin. So for instance, one resource A can be depended upon by resource B and you can model that and express that fact. And then we have implemented an admission webhook in Crospin so that if you're trying to go and delete that resource that's depended upon by somebody else, the admission webhook will detect that. It'll kick in, it'll report that back to the API server, and it'll be rejected. It'll say, no, you cannot delete this because it's in use by somebody else right now. So it really enforces the ability to clean everything up cleanly. And this is what it looks like. So this is a bit more of a fully specified approach to this because a lot of times people are gonna practically be using this within a composition. So say you've got a composition for a whole bunch of networking stuff and you've got VPCs and subnets and stuff. You can express these usage relationships as kind of a shortcut, but I wanted to show you the full example of if you're starting from scratch, you can say, hey, here is a usage. So we're declaring an instance of the usage type. And under the spec here, we've got a usage of a cluster and it's by a helm release. So we're kind of modeling that relationship of the helm releases depending on the cluster. And then that gives the admission webhook everything it needs to know to make sure that if you're trying to delete that cluster and the helm release is still around, it'll stop you from doing that. And one cool side effect you get here is that you can also do complete deletion protection for resources also. So you can admit, oh sorry, omit the by-field and you can just say, hey, there's a usage of an RDS database, this is my production database. It's, I'm not gonna tell you who it's in use by, that doesn't matter because it's in use, do not delete it. And that admission webhook will prevent any sort of accidental deletion or anything of this resource because it is obviously very important and you're protecting it that way. All right, I think that's everything for me and I'm gonna go ahead and turn it over to Nick for composition functions. Thanks, Jared. I did just realize that if we have time, we're supposed to do a demo of composition functions at the end of this and I'm holding a microphone so it might be challenging, but we'll see what we can do. All right, so Jared mentioned before one of the sort of really nice features of crossplane is what we call composition, which is the ability to, for you as usually a platform team member to think how do I wanna frame concepts for my users, for the developers that I'm supporting? Maybe I have my own opinion of what a bucket should look like, what fields it should expose, what configuration knobs it should have. So I'll design an API that represents a bucket and then I'll teach crossplane what should crossplane do when someone calls that API. Someone says, hey, I want a bucket. Like what in reality should I do? Should I go create an S3 bucket or a Google Cloud storage bucket, et cetera, et cetera. And the way that people have, the way that we've allowed people to configure this in the past has been using an API type called composition. Composition works pretty well for simple and static cases. It's kind of just a list of YAML manifests effectively with, as Jared showed you before, a bit of copying around to take data from the input API call and sort of patch it over to the output API call. But it is missing a lot of things, especially to start to get to more complex tasks like let's say deploying an Amazon EKS cluster, which is actually made up of like tens of resources that have a lot of relationships between them, et cetera. And so what composition doesn't have today, it doesn't have conditionals, doesn't have iteration, doesn't have the ability to speak to external systems as a very simple templating system. And that was somewhat intentional. We didn't really wanna grow a new DSL for configuring crossplane when we first came up with composition. And at the same time, we know from, a lot of us have backgrounds in platform engineering, different platform engineers have different preferences. Some people are gonna wanna use home templates, some people are gonna wanna use Q-lang, some people might wanna write it in Python. Like it's very hard to, we didn't think we were gonna invent a better language. So we thought, why don't we try and meet people where they're at and let people use the tools that they already know and like to configure composition. If you saw this session last year, we were just about to ship this in alpha. So welcome back if you were here last year. And now, as Jared said, it hit beta last week. So the general idea here is with composition functions, instead of specifying a template, a list of resources to go create in the configuration object, you tell crossplane, go call these functions please and you supply those functions. You either write them yourself, which is hopefully pretty straightforward or you can find them from the existing marketplace of functions. And then that function is kind of a pipeline. So the input to that pipeline is the observed state of the world. So crossplane takes on basically saying, okay, a developer out there said, I would like a bucket. And I know that this is a new bucket, so there's no existing resources that it's made up of. So what I'm gonna do is take the schema that the platform engineer defined, pass that to this pipeline of functions and say, hey functions, what should I do? Tell me what the desired state is based on this observed state. So it's kind of similar if you've written a Kubernetes controller before it's doing a similar thing, but it takes away tons of the boilerplate and complexity and crossplane does pretty much all of the hard part for you. And you really do just have to say, given this input, produce these outputs. So you install a function in a similar way to installing a provider or a configuration. Crossplane has a package manager that allows you to sort of declaratively just say, hey, make this function available. In reality, functions feel like building a serverless function. You literally just edit the kind of function.py or function.go, whatever language you're working in, add a little bit of logic and package it up and ship it. But behind the scenes, crossplane does turn that into a long running deployment pod, effectively. And those speak GRPC. So crossplane, whenever someone creates an XR, which is what we call a composite resource, when someone makes one of those API abstractions saying, hey, give me a bucket or give me a cluster or whatever platform team is defined, crossplane's gonna go and call these functions over GRPC to say, hey, what should I do? So the long-term vision, keep in mind we just hit beta with this last week. The long-term vision is that there will be SDKs for any language that people want to use to write these functions. Right now, we just have Go, we surveyed the community and the top three languages in order were Go, Python, and then TypeScript. So we have the Go function SDK, it works pretty well. There's a template for creating functions in Go. This weekend, I started the Python one, so coming real soon. And one of my coworkers tells me that they prototyped a TypeScript one, but he won't show it to me yet, so we'll see how that goes. Another thing that's really handy is we've done a ton of improvements this release with the crossplane CLI. Up until 1.14, the crossplane CLI kind of mostly just built packages and pushed them, which was useful, but we thought that there was more we could do. As it applies to functions, two of the really interesting commands that the CLI now has is the ability to template a function. So you can run this crossplane beta X package in it, my function, and it'll set up your function for you and get you ready to go, just drop in some logic. But then another thing that I think people will find really, really compelling, what we've seen people finding really, really compelling is people coming from other infrastructure tools, especially sort of more CLI-driven infrastructure tools, have basically said they want dry run functionality. Crossplanes are long running control play and you send it your configuration and it keeps applying it. But people wanted to say, hey, I'd like to, if a developer makes this API call, I want to see what crossplane's going to do. One of the really cool things about taking all of the logic the crossplane actually uses to figure out what it should do, to figure out what the desired state is for a given observed state, and putting that into a bunch of functions that it kind of just containers, is that we can now have a CLI tool. You give the CLI tools some desired state, pulls down all of those containers, the exact same ones, the exact same logic conversions that your production control plane will run, and sends the observed state through it, and prints you out the desired state, which kind of gives you like a dry run experience there. So we talk a lot about functions being something you use to use general purpose programming languages to provide logic, and this is sort of a personal and subjective thing, you know, I would really like to use Go or Python or languages like that to provide my configuration. I find that eventually you get to complex enough configuration tasks that you kind of just want to reach for a general purpose programming language that has existing tooling and test frameworks and all that kind of thing. But, you know, a lot of people would prefer to use their language of choice, their configuration language of choice, Q, Go templates, et cetera, et cetera. So you don't have to write your own function. One of the neat things about functions is that they are kind of allowing people to add new ways to configure cross-plane. So we already have functions available that use Go templates to offer a very sort of helm-like experience, I think that's on this slide, where you can basically either in line provide simple templates, or you can basically provide cross-plane a directory of templates and say use this. So if you're familiar with helm, this'll feel very, very similar. Someone from the community, actually two people from the community, there are currently two different Q functions that have appeared slightly before cross-plane was released. So if you prefer Q, similar kind of pattern, you can provide your configuration in that. We actually have a function as well that implements traditional cross-plane built-in patch-and-transform style composition as a function, which is useful because you can then use that sort of tool that I showed you before to render out your compositions and do a bit of a dry run, even if you do like or find, you know, appropriate the contemporary style of composition. Oh, no, all right, now it's time for the function. Microphone holder. I'll interpretively dance instead of talking. All right, let me quit Slack, just in case there's a secret source in there. All right, so what we're gonna do here is just make a function and go really quick. It's gonna be mostly sort of copying and pasting, but just to give you an idea of what the experience is like. So I believe we want, yeah, around this command, and I already made a backup of this just in case because the Wi-Fi was kind of slow earlier, but it looks like that worked. So what's this done is just implemented a template or grabbed a template, which I've called function demo. And you can see this is what the template will scaffold out. There's a bunch of stuff in there, but the only thing that's really important for the purposes of this exercise is fn.go, function.go, everything else you can pretty much leave. You could delete the test file, add some logic to fn.go, and then package it up and run it. The reason that everything else is there that there's a Docker file and a bunch of other stuff is that we do want these to group with you. If you do decide that you have custom build and CI demands from your function, you could, I don't know, build it using something other than Docker or switch out the test framework that's being used. You can do that if you want, but we don't want you to have to think about that. So if I look at fn.go at the moment, this run function is really what's important. This one does very little at the moment. It takes a run function request, which is the observed state that cross-plane sends it, and then it's effectively just gonna do a hello world. It's gonna say I was run with input, blah, blah, blah, blah. So, let's, oops, I need to CD example. So this command is that sort of dry run functionality that I was talking about. In this example, there's very little in the input, but you can see here this XR is the input resource that the user would have created. And then cross-plane is saying, okay, given this input, I'm gonna go and create this bucket resource here. I'm concerned because that's the state we're supposed to get to rather than where this demo we're supposed to start. Let's see here. So, I bet in this terminal over here, I am go running the version of this thing that I built previously. So by default, the render command is actually gonna pull down the logic that you use in production and run that. But if you are developing a function, you can run the function locally and you can tell using a annotation on the function, you can basically tell it to run in development mode and it's gonna talk to the one that you're running locally to just help you develop a function. So now, if we run render, it'll tell me I'm in the wrong directory, now if we run render, there you go, it's just gonna print out this hello world thing that says I was run with this input. So let me go over here and I'll stop that from running. And then, I just totally wrote some new function logic using curl. This is the thing that you already saw where this function now imports a bucket type from our AWS provider and is going to create a bucket. In this case, we are just, it's just a fixed output but you could imagine this whereas as USEs for the region, you could copy that from the XR input. Just kind of give you an idea of the input or how you would develop a function here. So if we now run that again and then do our beta render, it will fail again. Let's see, what am I doing here? That looks good. There we go, that's promising. So as I say, thanks, Jared. As I say, we have the SDK and tooling for Go, only released a week ago, so it's early but we've had a ton of people from the community writing these functions already and it seems to be working pretty well. I started prototyping the Python one. It's been about seven years since I was a full-time Python developer but I'm really liking the experience of writing these in Python and that's I think something that's gonna be really useful here if you have a platform team that aren't expert Go developers which is often kind of mandatory in the cloud-native ecosystem. They can now deploy cross-plane and still have the power of like a general-purpose programming language but using a language that they might be more familiar with. That's the end of everything, right? Oh, there's one more slide. I apologize. All right, so to wrap it up here, we don't want to talk about how like cross-plane is a community project, right? It's part of the CNCF and we are nothing without our community. So there's a lot of different ways to get involved. So you can see, most of them you start at crossplane.io or cross-plane organization on GitHub. You'll find most all of them there but lots of ways to connect with us and get involved. And then as I mentioned, we are working towards getting fully graduated with the CNCF and so in the cross-plane repo there's an adopters.md file. If you are already using cross-plane and have success story to share there, like a bunch of other people that have already added themselves to it, we definitely welcome you to add yourself to it as well. So I think that there, we can go ahead and switch over to, we have three minutes for questions if anybody has some. Yes, that was a quick hand. So a couple of years ago when I was doing due diligence around infrastructure as code, cross-plane, Palome, Terraform, you guys were still in a primitive stage at that point and the provider list was kind of small. But I even then appreciated the controller-based invocation instead of API. And it was just more cloud-native centric, right? But many people made a decision to kind of go with a different option for infrastructure as code, not to name the product. How do we adjust tactically from that perspective? Because that code base has grown as well. But now someone like myself who's definitely sees a lot of value in cross-plane and want to include that into the ecosystem. Because now I'm looking at infrastructure as code with say Terraform upstream, maybe cross-plane in the middle and then continue to march down with Argo. So can you talk a little bit about just like how people are addressing the strengths of cross-plane and how to introduce that into the ecosystem? Yeah, really good question. So I think, I'm gonna go behind this, I don't get yelled at. So one of the things I think you could say there is that, say for instance you are using other IAC tools, cross-plane has with this concept of providers is super, super extensible. So for instance for Terraform, there is a provider for Terraform. So you can take your existing HCL and just show that right to cross-plane and say cross-plane start dealing with this. So that's one sort of, I don't think you really want to scale like a huge, huge amount of HCL that way. That's one way you can start taking your existing investments and porting them over to cross-plane and having it do useful stuff for you right away. But I think another concept that we've seen a few people be pretty successful with is that with the concept of cross-plane compositions and abstractions, if you're going to expose the idea of say a database to your users for that infrastructure for them, you can give them that interface to work with. And then so for underneath the covers, it could still be doing Terraform stuff. Then over time, without your developer being affected, you can change that to a native cross-plane implementation. So you're keeping a consistent interface on top but changing it under the covers. So that's another way to do it. And then the third thing is that we want to do more investments and import like tools that import existing resources into cross-plane. There's a couple of things for that. We can make it smoother. So you can take existing stuff and get them into cross-plane in a more automated fashion too. So those are three ways to go about it, I think. Is it a clock say? Oh yeah, you're at the mic, you're in line. Go ahead. Yeah, I used, about a year ago, I started using cross-plane or I at least baited it and it was fantastic. However, this was great in a green field environment where I'm starting from scratch for creating resources and everything you just demoed. The issue that we seem to have was, and maybe you just addressed some of this, we have an existing environment with thousands of AWS resources and so on and we started running into conflicts. We found that imports would happen, yes, of existing resources, let's say imported database. However, if there was drift between what my cross-plane was and what actually existed in AWS, then cross-plane would start changing things, would start overriding settings and so on and so forth. Are there plans to or have there been changes to support that sort of drift a little bit more gracefully? I think yes. So if I, just to make sure I understand, obviously a cross-plane is supposed to correct drift, that is something that it does, but if you are importing a resource and you don't import it exactly as it currently was in the cloud, then it will correct the drift that it perceives in some way that you don't want to do. By deleting my database or something, yeah. So I think that's kind of what Jared just touched on and this is what we think of as like the import where you could imagine, no concrete plans at the moment, but you could imagine a cross-plane CLI import this AR in AWS or whatever and it sort of generates you a version of that. I definitely think that's the path that we will go down. I forget Jared, is that on our roadmap at the moment? I'm not sure what it is. Yeah, I think it's at a couple of reasons. Okay, yeah, it's a little while out, but it's definitely on the roadmap. Thank you. All right, I guess we'll go hang out outside if anyone wants to chat with us afterwards. Thank you so much everybody, really appreciate it.