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

SNOW-1621763 update example for na + spcs upgrade #12

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
194 changes: 189 additions & 5 deletions spcs-three-tier/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ Execute the shell script named `setup.sh` in the root folder:

The setup script runs the following scripts:

- Snowpark Container Services setup (`spcs_setup.sql`)
- Provider side setup (`provider_setup.sql`)
- Consumer side setup (`consumer_setup.sql`)
- Image repository setup by executing `make all` command
Expand Down Expand Up @@ -104,25 +103,210 @@ To clean up the Native App test install, you can execute `cleanup.sh`, which wil
Your Native App is now ready on the Provider Side. You can make the Native App available
for installation in other Snowflake Accounts by creating a version and release directive, then setting
the default patch and Sharing the App in the Snowsight UI.

See the [documentation](https://other-docs.snowflake.com/en/native-apps/provider-publishing-app-package) for more information.

1. Navigate to the "Apps" tab and select "Packages" at the top.
Add the version and set the release directive in the provider account
```sql
ALTER APPLICATION PACKAGE spcs_app_pkg ADD VERSION v1 using @spcs_app_pkg.napp.app_stage;
ALTER APPLICATION PACKAGE spcs_app_pkg SET DEFAULT RELEASE DIRECTIVE VERSION=v1 PATCH=0;
```

2. Now click on your App Package (`NA_SPCS_PYTHON_PKG`).
Publish the app:

1. Navigate to the "Apps" tab and select "Packages" at the top.
spcs_app_pkg
2. Now click on your App Package (`spcs_app_pkg`).

3. From here you can click on "Set release default" and choose the latest patch (the largest number) for version `v1`.

4. Next, click "Share app package". This will take you to the Provider Studio.

5. Give the listing a title, choose "Only Specified Consumers", and click "Next".

6. For "What's in the listing?", select the App Package (`NA_SPCS_PYTHON_PKG`). Add a brief description.
6. For "What's in the listing?", select the App Package (`spcs_app_pkg`). Add a brief description.

7. Lastly, add the Consumer account identifier to the "Add consumer accounts".

8. Click "Publish".

### Install Native App in Consumer Account


### Upgrade a Native App
Upgrades can be performed in two ways:

* Automated Upgrades: Triggered automatically when the provider updates the release directive on the application
package. All installed instances specified by the directive are upgraded automatically.

* Manual Upgrades: Initiated by the consumer, who manually executes the ALTER APPLICATION command to perform the upgrade.

From the last step, we had an app called `spcs_app_instance` in the consumer account.

In this tutorial, we'll demonstrate the upgrade process within the Native App Framework.

#### Add a Patch to Version v1 and Upgrade

##### change endpoints
Update the endpoints in the frontend.yaml file.
Before:
```yaml
endpoints:
- name: app
port: 8000
public: true
```
After
```yaml
endpoints:
- name: app1
port: 8003
public: true
- name: app2
port: 8004
public: true
```

To upload the file into the stage @spcs_app_pkg.napp.app_stage, we can use snowsql:

```bash
snow sql -q 'put file:///DIRECTOR_TO_EXAMPLE/native-apps-examples/spcs-three-tier/app/* @spcs_app_pkg.napp.app_stage auto_compress=false overwrite=true'
```

add a patch and set default release directive in the provider account
```sql
alter application package spcs_app_pkg add patch for version v1 using @spcs_app_pkg.napp.app_stage;
alter application package spcs_app_pkg set default release directive version=v1 patch=1;
```

#### Upgrade process
The app should automatically update to version v1.1 after several minutes or hours once the default release directive is set.

For manual upgrades (immediate and synchronous), run the following in the consumer account:

```sql
alter application spcs_app_instance upgrade
```

#### Check Application Status
To check the status of the application, including the current version and patch:
```sql
desc application app
```
This will display the application's current version, patch, upgrade state, and more.

To verify that the updated services are deployed:
```sql
SHOW ENDPOINTS IN SERVICE spcs_app_instance.app_public.frontend;
```
**Expected output:**

| Name | Port | Port Range | Protocol | Is_Public | Ingress_URL |
|------|------|------------|----------|-----------|--------------|
| app1 | 8003 | | HTTP | true | [app1-url] |
| app2 | 8004 | | HTTP | true | [app1-url] |


##### upgrades to version v2 and fails

change endpoints in the spec file `frontend.yaml`
```yaml
endpoints:
- name: app1
port: 8003
public: true
- name: app2
port: 8004
public: true
- name: app3
port: 8005
public: true
```
replace the PROCEDURE `CREATE OR REPLACE PROCEDURE versioned_schema.init()` into
```sql
CREATE OR REPLACE PROCEDURE versioned_schema.init()
RETURNS STRING
LANGUAGE SQL
EXECUTE AS OWNER
AS
$$
DECLARE
can_create_compute_pool BOOLEAN;
BEGIN
SELECT SYSTEM$HOLD_PRIVILEGE_ON_ACCOUNT('create compute pool') INTO :can_create_compute_pool;
IF (:can_create_compute_pool) THEN
ALTER SERVICE IF EXISTS app_public.frontend FROM SPECIFICATION_FILE='frontend.yaml';
ALTER SERVICE IF EXISTS app_public.backend FROM SPECIFICATION_FILE='backend.yaml';

-- ALTER SERVICE is async process. To minimize the downtime we need to wait until the services are ready.
SELECT system$wait_for_services(180, 'app_public.backend', 'app_public.frontend');

-- Trigger an error
SELECT * FROM non_exists_table;

END IF;
RETURN 'init complete';
END $$;

```

###### Add Version v2 and Attempt the Upgrade

In the provider account
```sql
alter application package spcs_app_pkg add version v2 using @spcs_app_pkg.napp.app_stage;
alter application package spcs_app_pkg set default release directive version=v2 patch=0;
```
In the consumer account
```sql
alter application spcs_app_instance upgrade;
```
Check the application’s upgrade status in the consumer account:
```sql
desc application app
```
The table below shows part of the output. Please note that the `upgrade_target_version` is `v2` and
`upgrade_target_patch` is `0`. The `update_state` is `FAILED`, and it also gives the
`upgrade_failure_reason`. In this case, the app remains on the previous version (v1.1).

| Property | Value |
|-----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| name | SPCS_APP_INSTANCE |
| version | V1 |
| patch | 1 |
| upgrade_state | FAILED |
| upgrade_target_version | 2 |
| upgrade_target_patch | 0 |
| upgrade_attempt | 3 |
| upgrade_failure_type | VERSION_SETUP |
| upgrade_failure_reason | "[ErrorCode 2003] Uncaught exception of type 'STATEMENT_ERROR' on line 171 at position 0 : Uncaught exception of type 'STATEMENT_ERROR' on line 12 at position 8 : SQL compilation error: Object 'NON_EXISTS_TABLE' does not exist or not authorized." |

##### Version Initializer for SPCS Service Upgrade

The failed SQL query `SELECT * FROM non_exists_table` occurs **after** the `ALTER SERVICE` statement in v2.0, but the
`ALTER SERVICE` command still runs successfully. This raises concerns about the service version: although the services might appear to be running version `v2.0`, they are actually running version `v1.1`.

The key is the `ALTER SERVICE` command is inside the `version_initializer` of the `lifecycle_callbacks`. If the upgrade to version `v2.0` fails, the system will invoke the `version_initializer` for the current version (`v1.1`), effectively reverting the services to the correct version.

**Important Tips for the `version_initializer` Callback Procedure**:
- The callback procedure should reside in a **versioned schema**.
- Code/SQL responsible for creating and altering SPCS services must be included **within the callback procedure** to ensure proper rollback in the event of upgrade failure.
- If the `ALTER SERVICE` command is not placed inside `version_initializer`, the services might remain in version `v2.0`, even after an upgrade failure.

---

##### Handling Upgrade Failures

Upgrade failures can happen due to issues on the provider's side, such as errors in the setup script. In such cases, upgrades might fail for all consumers. To handle this, you have a few options:

* Rollback to a previous version: In the scenario described above, you can revert the release directive to version `v1.1` by running the following command:

```sql
ALTER APPLICATION PACKAGE spcs_app_pkg SET DEFAULT RELEASE DIRECTIVE VERSION=v1 PATCH=1;
```

* Create a new version: Correct the errors and release a new version. After passing the necessary security review, you can set this new version as the default release directive. However, be aware that the security review process can take some time.


### Debugging
There are some Stored Procedures to allow the Consumer to see the status
and logs for the containers and services. These procedures are granted to the `app_admin`
Expand Down
12 changes: 6 additions & 6 deletions spcs-three-tier/app/manifest.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
manifest_version: 1
version:
name: V1
name: v1
label: "First Version"

configuration:
grant_callback: v1.create_services
grant_callback: versioned_schema.create_services

artifacts:
setup_script: setup.sql
Expand All @@ -20,7 +20,7 @@ artifacts:
- /spcs_app/napp/img_repo/eap_router

lifecycle_callbacks:
version_initializer: v1.init
version_initializer: versioned_schema.init

privileges:
- BIND SERVICE ENDPOINT:
Expand All @@ -39,13 +39,13 @@ references:
- SELECT
object_type: VIEW
multi_valued: false
register_callback: v1.register_single_callback
register_callback: versioned_schema.register_single_callback

- WIKIPEDIA_EAI:
label: "Wikipedia Access Integration"
description: "EAI for Egress from NA+SPCS"
privileges: [USAGE]
object_type: EXTERNAL_ACCESS_INTEGRATION
register_callback: v1.register_single_callback
configuration_callback: v1.get_configuration
register_callback: versioned_schema.register_single_callback
configuration_callback: versioned_schema.get_configuration
required_at_setup: true
Loading
Loading