Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bringup #1

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 96 additions & 52 deletions examples/chem-sync-local-flask/README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
# Benchling App Example: Chemical Sync for Local Development

An example Benchling App written in Python which allows users to search for chemicals
via [PubChem](https://pubchem.ncbi.nlm.nih.gov/) and create them in Benchling.
An example Benchling App written in Python which allows users to search for
chemicals via [PubChem](https://pubchem.ncbi.nlm.nih.gov/) and create them in
Benchling.

![image info](./docs/demo-full.gif)
_The App features branching flows and will also validate user inputs._

**Appendices**:

* [Architecture Diagram](#architecture-diagram)

## Technical Prerequisites

This app is optimized as a minimal local development experience using [Docker](https://www.docker.com/) for reproducibility.
This app is optimized as a minimal local development experience using
[Docker](https://www.docker.com/) for reproducibility.

> ⚠️ **Development Only**: This example is not meant to be copied into
> production as-is. There are additional deployment, scale, and security
> concerns that should be addressed before deploying an app based on this
> example to production.

> ⚠️ **Development Only**: This example is not meant to be copied into production as-is. There are additional deployment, scale, and security concerns that should be addressed before deploying an app based on this example to production.
It relies on a few other tools that will be installed for you within Docker
containers:

It relies on a few other tools that will be installed for you within Docker containers:
* [Localtunnel](https://localtunnel.me/) - expose a public webhook URL and forward the results locally. ⚠️ *Not for production or real data!*
* [Flask](https://flask.palletsprojects.com/) - A simple Python web application framework
* [Localtunnel](https://localtunnel.me/) - expose a public webhook URL and
forward the results locally. ⚠️ _Not for production or real data!_
* [Flask](https://flask.palletsprojects.com/) - A simple Python web application
framework

## Getting Started

TODO: Create the app and set the envars first

Create an empty placeholder file for Docker secrets. *nix example:

```bash
@@ -39,12 +51,17 @@ Start Docker:
docker compose up --build -d
```

Tip: You can omit the `-d` option if you want to run in the foreground. Otherwise, use `docker compose logs -f` to tail logs.
Tip: You can omit the `-d` option if you want to run in the foreground.
Otherwise, use `docker compose logs -f` to tail logs.

> ℹ️ **Windows Note 1:** "Use ContainerD for pulling and storing images" may need to be enabled in `Docker > Settings > Features in development > Beta Features`

> ℹ️ **Windows Note 2**: If running into an error like "ERROR: request returned Bad Gateway for API route and version", [this solution](https://github.com/docker/for-mac/issues/6956#issuecomment-1876444658) may fix the problem.
> ℹ️ **Windows Note 1:** "Use ContainerD for pulling and storing images" may
> need to be enabled in `Docker > Settings > Features in development > Beta
> Features`

> ℹ️ **Windows Note 2**: If running into an error like "ERROR: request returned
> Bad Gateway for API route and version", [this
> solution](https://github.com/docker/for-mac/issues/6956#issuecomment-1876444658)
> may fix the problem.

You can verify that Flask is up and running:

@@ -54,38 +71,47 @@ curl localhost:8000/health

If Flask is running, you should see `OK` printed.

Be sure to note the URL created for you by `localtunnel`. The log line should look something like this:
Be sure to note the URL created for you by `localtunnel`. The log line should
look something like this:

```
```bash
app-workshop-local-tunnel-1 | your url is: https://brave-wombats-poke.loca.lt
```

On *nix systems, you can easily obtain _just_ the URL via:

```
docker compose logs local-tunnel | grep -o https://.* | tail -n 1
```bash
docker compose logs local-tunnel | grep -o "https://.*"
```

Example Output:

```
```bash
https://brave-wombats-poke.loca.lt
```

> 💡 Don't forget to append `/1/webhooks`, making the full URL given to Benchling `https://brave-wombats-poke.loca.lt/1/webhooks`
> 💡 Don't forget to append `/1/webhooks`, making the full URL given to
> Benchling `https://brave-wombats-poke.loca.lt/1/webhooks`

## Setting Up Your App in Benchling

### Benchling Prerequisites

1. Access to a Benchling tenant, like `https://my-tenant.benchling.com`
2. Ensure you've been granted access to the [Benchling Developer Platform Capability](https://help.benchling.com/hc/en-us/articles/9714802977805-Access-the-Benchling-Developer-Platform).
3. [Optional] If you'd like to render the App's UI in a Run, you'll need a [Benchling Connect](https://www.benchling.com/connect) license.
4. [Molecule entities](https://help.benchling.com/hc/en-us/articles/9684254682893-Molecule-entity-overview) will need to be enabled on your tenant.
5. [Global Apps](https://docs.benchling.com/docs/global-apps-faq) will need to be enabled on your tenant.
2. Ensure you've been granted access to the [Benchling Developer Platform
Capability](https://help.benchling.com/hc/en-us/articles/9714802977805-Access-the-Benchling-Developer-Platform).
3. [Optional] If you'd like to render the App's UI in a Run, you'll need a
[Benchling Connect](https://www.benchling.com/connect) license.
4. [Molecule
entities](https://help.benchling.com/hc/en-us/articles/9684254682893-Molecule-entity-overview)
will need to be enabled on your tenant.
5. [Global Apps](https://docs.benchling.com/docs/global-apps-faq) will need to
be enabled on your tenant.

### Upload the App Manifest

Click the user icon in the bottom left corner to bring up the main menu. Select "Feature Settings" > "Developer Console"
Click the user icon in the bottom left corner to bring up the main menu. Select
"Feature Settings" > "Developer Console"

Next, click the "Create app" button and choose "From manifest."

@@ -101,10 +127,10 @@ a new public webhook URL.
Update the Benchling App's Webhook URL in the UI with the new server and
append the path our Flask route expects (see `local_app/app.py`).

For example, if our `localtunnel` generated URL is `https://hot-ideas-doubt.loca.lt`,
the webhook URL in Benchling should be:
For example, if our `localtunnel` generated URL is
`https://hot-ideas-doubt.loca.lt`, the webhook URL in Benchling should be:

```
```string
https://hot-ideas-doubt.loca.lt/1/webhooks
```

@@ -117,31 +143,35 @@ Generate a client secret in Benchling and be sure to copy the secret.
![image info](./docs/generate-secret.gif)

Since the client secret is sensitive, it's handled a bit differently. It's
registered as a `secret` in our `docker-compose.yaml` file, which will be looking
for a file `./client_secret`.
registered as a `secret` in our `docker-compose.yaml` file, which will be
looking for a file `./client_secret`.

We can create this file and paste in the secret plaintext value if we have the secret in our clipboard.
On *nix:
We can create this file and paste in the secret plaintext value if we have the
secret in our clipboard. On *nix:

```bash
touch .client_secret
pbpaste > .client_secret
```

> ⚠️ **Security Note:** Be sure to avoid committing `.client_secret` to a source code repository.
> ⚠️ **Security Note:** Be sure to avoid committing `.client_secret` to a source
> code repository.

You'll then need to restart _just_ the `benchling-app` Docker service to pick up the changes:
You'll then need to restart _just_ the `benchling-app` Docker service to pick up
the changes:

```bash
docker-compose up -d
```

If you restart both containers, be sure to update your App in Benchling with the new webhook URL from localtunnel.
If you restart both containers, be sure to update your App in Benchling with the
new webhook URL from localtunnel.

### Setting Client ID

Our App needs a Client ID to pair with the Client Secret for authentication to Benchling. In this case, we've created our
App to accept `CLIENT_ID` as an environment variable.
Our App needs a Client ID to pair with the Client Secret for authentication to
Benchling. In this case, we've created our App to accept `CLIENT_ID` as an
environment variable.

One easy way to set an environment variables for Docker is to add a `.env` file.

@@ -155,24 +185,28 @@ Windows example:
echo.> .env
```

Open it in an editor of your choice and set the values with the plaintext client ID
for your App. For example:
Open it in an editor of your choice and set the values with the plaintext client
ID for your App. For example:

```
```bash
CLIENT_ID=Ts7jtwPohM
```

### Setting App Definition ID

The App definition ID is available from the Developer Console by selecting the App to view.
The App definition ID is available from the Developer Console by selecting the
App to view.

![image info](./docs/global-app-definition-id.png)

> ℹ️ **Note:** If you do NOT see this ID, please ensure [Global Apps](https://docs.benchling.com/docs/global-apps-faq) are enabled for your tenant.
> ℹ️ **Note:** If you do NOT see this ID, please ensure [Global
> Apps](https://docs.benchling.com/docs/global-apps-faq) are enabled for your
> tenant.

Add it to your `.env` file with a variable name `APP_DEFINITION_ID`. The contents of your `.env` file should now look something like:
Add it to your `.env` file with a variable name `APP_DEFINITION_ID`. The
contents of your `.env` file should now look something like:

```
```bash
CLIENT_ID=Ts7jtwPohM
APP_DEFINITION_ID=appdef_Trow4zbR3o
```
@@ -187,17 +221,23 @@ docker-compose up -d

### Security Note: Storing App Secrets in Production

> ⚠️ **Security Note:** In production, store the secret with a secure solution such as a secrets store (AWS Secrets Manager, as an example) or, if storing programmatically, encrypted using app-layer encryption. Avoid placing it in plaintext anywhere in code or configuration.
> ⚠️ **Security Note:** In production, store the secret with a secure solution
> such as a secrets store (AWS Secrets Manager, as an example) or, if storing
> programmatically, encrypted using app-layer encryption. Avoid placing it in
> plaintext anywhere in code or configuration.

### Create App Registry Dependencies

If you examine the `configuration` section of `manifest.yaml`, you'll see our App
expects a few configuration items:
If you examine the `configuration` section of `manifest.yaml`, you'll see our
App expects a few configuration items:

1. A folder
2. A molecule entity schema with two decimal fields

We declare two `features` in the `manifest.yaml` so that our App can render
its UI as a `CANVAS` (e.g. within the Notebook) or on an `ASSAY_RUN`. If you'd like to use a Run, we'll also need:
We declare two `features` in the `manifest.yaml` so that our App can render its
UI as a `CANVAS` (e.g. within the Notebook) or on an `ASSAY_RUN`. If you'd like
to use a Run, we'll also need:

1. An Lab Automation run schema

#### Folder
@@ -218,8 +258,9 @@ The created molecule schema should look something like this:

![image info](./docs/schema-example.png)

_Note: The names can be different, and the schema is allowed to have additional fields.
As long as it's for a `Molecule` entity, and has at least two `Decimal` fields._
_Note: The names can be different, and the schema is allowed to have additional
fields. As long as it's for a `Molecule` entity, and has at least two `Decimal`
fields._

#### [Optional] Lab Automation Run Schema

@@ -229,13 +270,16 @@ If using a Run, create a new lab automation run schema in the registry.

### Updating the App's Configuration

App Configuration gives us a stable code contract for referencing data mapped in a Benchling tenant.
The values of the data in Benchling can then be changed without updating App code.
App Configuration gives us a stable code contract for referencing data mapped in
a Benchling tenant. The values of the data in Benchling can then be changed
without updating App code.

Let's update our configuration to:

1. Specify a folder for syncing sequences
2. Link a molecule schema and fields for the synced chemicals
3. [Optional] If using a Run, select an assay run schema to associate with our Benchling App
3. [Optional] If using a Run, select an assay run schema to associate with our
Benchling App

![image info](./docs/update-app-config.gif)

@@ -269,4 +313,4 @@ Let's grant some access by adding the Benchling App to an organization.

### Architecture Diagram

![image info](./docs/architecture-diagram.png)
![image info](./docs/architecture-diagram.png)
2 changes: 0 additions & 2 deletions examples/chem-sync-local-flask/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3.8"

services:
benchling-app:
build: .
5 changes: 5 additions & 0 deletions examples/chem-sync-local-flask/local_app/app.py
Original file line number Diff line number Diff line change
@@ -44,3 +44,8 @@ def _enqueue_work() -> None:
args=(request.json,),
)
thread.start()


if __name__ == "__main__":
app = create_app()
app.run(host="0.0.0.0", port=8000)
2 changes: 1 addition & 1 deletion examples/chem-sync-local-flask/manifest.yaml
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ manifestVersion: 1

info:
name: Sample Sync App
version: 0.1.0
version: 0.1.2
features:
- name: Sync Step
id: sync_step