# Openflow Gdrive Cleanup

> Clean up the Google Drive CDC connector demo. Stops flow, drops schema, resets gate state.

- Skill: `snowflake-labs/openflow-gdrive-cleanup` (Agent Skill)
- Install (CLI): `npx skillmds@latest add snowflake-labs/openflow-gdrive-cleanup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/snowflake-labs/openflow-gdrive-cleanup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: snowflake-labs (https://skillmd.com/u/snowflake-labs)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/snowflake-labs/openflow-gdrive-cleanup

---


# OpenFlow Google Drive — Cleanup

Tear down the connector deployment and reset for a fresh demo run.

## When to Load

Parent SKILL.md routes here on: "cleanup", "clean", "reset", "tear down", "remove"

## Forbidden Actions

- **NEVER drop the RUNTIMES schema** — it contains OpenFlow runtime definitions and is shared infrastructure
- **NEVER drop the NETWORKS schema** -- it contains network rules tracked in `.sfutils/manifest.toml`
- **NEVER drop the POLICIES schema** -- it contains auth policies tracked in `.sfutils/manifest.toml`
- **NEVER drop the database itself** — only drop the demo-specific destination schema
- **NEVER delete `.sfutils/`** — manifest is preserved across runs

## Correct Cleanup Order

The cleanup MUST follow this dependency order:

1. Stop flow (processors)
2. Disable controllers
3. **Delete parameter contexts** (BEFORE deleting PG — contexts are orphaned if PG deleted first)
4. Delete process group
5. Detach EAI from runtime (if attached)
6. Drop destination schema (only the demo schema, NEVER infrastructure schemas)
7. Remove PAT / service user (if full cleanup requested)
8. Remove nipyapi profile
9. Reset gate state + manifest

## Workflow

### Step 1: Resolve Config

```bash
eval $(python3 -c "
import tomllib, os
m = tomllib.load(open('.sfutils/manifest.toml', 'rb'))
s = m.get('snowflake', {})
o = m.get('openflow', {})
rt = o.get('runtime', {})
wf = o.get('workflows', {})
print(f'CONNECTION={s.get(\"connection\", \"\")}')
print(f'DATABASE={o.get(\"database\", \"\")}')
print(f'SCHEMA={o.get(\"schema\", \"\")}')
print(f'ROLE={o.get(\"role\", \"\")}')
print(f'PROFILE={rt.get(\"nipyapi_profile\", \"\")}')
print(f'EAI={o.get(\"eai\", \"\")}')
print(f'RUNTIME_FQN={rt.get(\"name\", \"\")}')
# Get PG_ID from first workflow if available
for k, v in wf.items():
    if isinstance(v, dict) and v.get('pg_id'):
        print(f'PG_ID={v[\"pg_id\"]}')
        break
")
```

### Step 2: Find and Stop the Flow

```bash
nipyapi --profile $PROFILE ci list_flows
```

Find the connector PG and get its ID. Stop the flow:

```bash
nipyapi --profile $PROFILE canvas schedule_process_group "<PG_ID>" False
```

### Step 3: Disable Controllers

```bash
nipyapi --profile $PROFILE canvas schedule_all_controllers "<PG_ID>" False
```

### Step 4: Delete Parameter Contexts

**IMPORTANT:** This MUST happen BEFORE deleting the process group. If the PG is deleted first, parameter contexts become orphaned and will conflict on the next deployment.

**Delete in reverse-dependency order:** The Ingestion context references the Destination context. Delete Ingestion first, then Destination, then any others.

Run via `uv run` to access the nipyapi Python dependency:

```bash
uv run --project <SKILL_DIR> python -c "
import nipyapi
nipyapi.profiles.switch('$PROFILE')

contexts = nipyapi.nifi.FlowApi().get_parameter_contexts()
# Sort: delete Ingestion before Destination (reverse dependency order)
ORDER = ['Ingestion', 'Destination', 'Connection']
matching = [ctx for ctx in contexts.parameter_contexts if 'Google Drive' in ctx.component.name]
matching.sort(key=lambda c: next((i for i, k in enumerate(ORDER) if k in c.component.name), 99), reverse=False)

for ctx in matching:
    print(f'Deleting parameter context: {ctx.component.name}')
    nipyapi.parameters.delete_parameter_context(ctx.id)
    print(f'  Deleted')
"
```

Where `<SKILL_DIR>` is the absolute path to `skills/openflow-gdrive-demo/` (contains pyproject.toml with nipyapi dependency).

### Step 5: Delete Process Group

```bash
nipyapi --profile $PROFILE canvas delete_process_group "<PG_ID>" True
```

The `True` flag forces deletion (purges queued flowfiles).

### Step 6: Detach EAI from Runtime

If an EAI was attached to the runtime for this connector, ask the user to detach it via Snowsight:

> Please detach EAI `{EAI_NAME}` from your runtime:
> 1. Go to Snowsight > Ingestion > OpenFlow > Deployments > your runtime
> 2. Edit the runtime and remove `{EAI_NAME}` from External Access Integrations
> 3. Save

**STOP**: Wait for user to confirm.

### Step 7: Drop Destination Schema

**⚠️ SAFETY CHECK:** Only drop the demo-specific schema. NEVER drop infrastructure schemas.

**Protected schemas (NEVER drop):** `RUNTIMES`, `NETWORKS`, `POLICIES`, `INFORMATION_SCHEMA`, `PUBLIC`

```bash
snow sql -q "DROP SCHEMA IF EXISTS $DATABASE.$SCHEMA CASCADE" -c $CONNECTION --role ACCOUNTADMIN
```

Removes all tables, stages, Cortex Search service, dynamic tables, and procedures in the demo schema.

### Step 8: Remove PAT and Service User (if full cleanup)

If user requested full cleanup (including PAT/service-user):

```bash
<PAT_SKILL_DIR>/pat remove --user $SA_USER --db $SFUTILS_DB --drop-user --yes
snow sql -q "DROP ROLE IF EXISTS $SA_ROLE" -c $CONNECTION --role ACCOUNTADMIN
```

Then remove the nipyapi profile:

```python
import yaml
profiles_path = '~/.nipyapi/profiles.yml'
# Read, delete the profile key, write back
```

### Step 9: Reset Gate State and Manifest

```bash
python3 .cortex/skills/openflow-gdrive-demo/scripts/gate.py \
  --step deploy --action reset --cascade --manifest .sfutils/manifest.toml
```

Remove `[openflow]`, `[openflow.*]`, and `[pat.*]` (if REMOVED) sections from manifest, leaving only `[snowflake]` and `[prereqs]`.

### Step 10: Verify Cleanup

1. Confirm no connector flow remains:
   ```bash
   nipyapi --profile $PROFILE ci list_flows
   ```

2. Confirm no orphaned parameter contexts:
   ```python
   contexts = nipyapi.nifi.FlowApi().get_parameter_contexts()
   assert len(contexts.parameter_contexts) == 0
   ```

3. Confirm schema is gone:
   ```bash
   snow sql -q "SHOW SCHEMAS IN DATABASE $DATABASE" -c $CONNECTION
   ```

4. Confirm EAI detached (user confirmed in Step 6).

5. Confirm service user removed (if full cleanup):
   ```bash
   snow sql -q "SHOW USERS LIKE '%$SA_USER%'" -c $CONNECTION --role ACCOUNTADMIN
   ```

## Stopping Points

- ✋ Before Step 7: confirm which schema to drop (safety check)
- ✋ Before Step 8: confirm full cleanup if PAT/user removal requested
- ✋ After Step 10: present cleanup verification

## Output

```
Demo cleaned up!
  Flow:             Deleted
  Parameter Ctxs:   Deleted
  EAI:              Detached from runtime (integration retained)
  Schema:           Dropped (CASCADE)
  PAT/User:         [Removed | Retained]
  Gate:             All steps reset
  Manifest:         Reset to base state
  Ready for fresh demo deployment
```

