Oatfin Under The Hood - Part III
Thanks again for subscribing to Cloud Musings! Last I checked, it was 47 subscribers strong on LinkedIn. If you haven't subscribed, subscribe to get automatic updates when I publish new editions! I would love introductions to investors and enterprise partners who are excited about the cloud and developer tools space.
The goal in this edition is to continue to de-mystify what Oatfin does under the hood with code. In part 1, I talked about the steps that happen when a user clicks the deploy now button. In part 2, I talked about managing cloud credentials among developers. In this edition, I’ll talk about the cloning of an environment feature.
With cloud native, one of the major challenges is observability and being able to debug production issues quickly. But you can’t really debug your app while it’s being used by users in real time.
It’s nice to have a temporary environment that is as close to production as possible, but spinning up and tearing down a cloud infrastructure quickly is a major pain for developers.
One of the cool features we shipped is the ability to clone an infrastructure or environment one-to-one to make it easy to reproduce and troubleshoot production issues.
In solving this problem, it would have been nice to have a COPY or CLONE operation in REST. Something I think is fundamental to almost every API.
For now I’m doing:
POST /resource?source=id
If the “source” parameter is present as a query parameter, then it’s a clone operation, otherwise it’s a create operation. The operation is not idempotent meaning it will create a new copy each time the API is called.
Here is what this looks like. For the frontend, I’m using React, Typescript with a tool called umijs and antdesign from Ant financial:
The create request:
import { request } from 'umi'
export async function createApp(params) {
return request('/v1/apps', {
method: 'POST',
data: params,
headers: {
Authorization: 'Bearer ACCESS_TOKEN,
},
})
};
The clone request:
import { request } from 'umi'
export async function cloneApp(params, id) {
return request(`/v1/apps?source=${id}`, {
method: 'POST',
data: params,
headers: {
Authorization: 'Bearer ACCESS_TOKEN,
},
})
};
Calling these functions inside the React component:
export const AppComponent: FC<Props> = (props) => {
...
const handleCreate = async (values) => {
const res = await createApp(values);
...
};
const handleClone = async (values) => {
const res = await cloneApp(values);
...
};
return (
<>
<CreateModal
...
onSubmit={handleCreate}
/>
<CloneModal
...
onSubmit={handleClone}
/>
</>
);
};
The Python & Flask code skeleton:
@api.route('/apps', methods=['POST']
@jwt_required()
def create_clone_app():
req_data = flask.request.get_json()
clone_source = flask.request.args.get('source')
if not clone_source:
app = AppsService().create(...)
else:
app = AppsService().clone(...)
return flask.jsonify(
app=app.json(),
message='success',
), 200)
Thanks for reading!
Jay