npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sap/hdi-dynamic-deploy

v2.9.0

Published

HDI dynamic content deployment

Downloads

4,552

Readme

@sap/hdi-dynamic-deploy

@sap/hdi-dynamic-deploy is a Node.js-based http server for dynamic deployment to SAP HANA DI (HDI) containers, HDI Dynamic Deployer for short. The HDI Dynamic Deployer can be used in XS Advanced (XSA) and in SAP Cloud Platform (SAP CP)/Cloud Foundry (CF) to deploy database content to dynamically created containers (e.g. created via the Instance Manager).

The dynamic deployer is built upon @sap/hdi-deploy which should be used directly if a static deployment at deploytime is sufficient.

README.md

Installation:

Dynamic deployment:

Integration into a Database Module

Usually, @sap/hdi-dynamic-deploy gets installed via a package.json-based dependency inside your application's db module:

db/package.json:

{
  "name": "deploy",
  "dependencies": {
    "@sap/hdi-dynamic-deploy": "2.9.0"
  },
  "scripts": {
    "start": "node node_modules/@sap/hdi-dynamic-deploy/"
  }
}

Configuration of the dynamic deployer

The dynamic deployer needs to be configured via the following environment variables:

  • PORT: port the HTTP server listens to
  • hdi_dynamic_deploy_user: username for HTTP basic authentication
  • hdi_dynamic_deploy_password: password for HTTP basic authentication
  • ENFORCE_AUDITING: force usage of audit logging. If audit logging cannot be enabled, the server will throw an error and stop.
  • ENFORCE_V2: force usage of the V2 audit logging API. If audit logging V2 cannot be enabled, the server will throw an error and stop.
  • STRUCTUREDLOGGING: allows dynamic deployer logs to be in structured format when set to true.
  • AUDIT_LOG_TENANT: specifies the tenant to use for audit logging. Likely this will be the subaccount-id where your app is deployed. If this is not specified you may be unable to view the logs.

Note: Any client that knows the hdi_dynamic_deploy_user and the corresponding password will indirectly be able to read the database artifacts contained in the dynamic deploy server.

If an auditlog service is bound to the dynamic deployer, invalid authentication attempts will be logger accordingly.

The PORT variable is automatically set by XSA. ENFORCE_AUDITING, ENFORCE_V2, username and password have to be given e.g. via the mta.yaml file (see example below). When using the XSA deploy-service, a strong generated password will be used. In other use cases, sufficient password strength has to be ensured!

modules:
  - name: db
    type: com.sap.xs.hdi-dynamic
    path: db
    properties:
      hdi_dynamic_deploy_user: ${generated-user}
      hdi_dynamic_deploy_password: ${generated-password}
    provides:
    - name: db_deployment
      properties:
         url: ${default-url}
         user: ${generated-user}
         password: ${generated-password}

Triggering a dynamic deployment by a HTTP POST request

The dynamic deployer is a http server started for a specific db module. When the module is pushed to XSA or CF, the dynamic deployer starts listening for requests and eventually starts the (non-dynamic) deployer to deploy the content of the db module to a given container.

To trigger the deployment one has to send a HTTP POST request with basic authentication and content type application/json to the dynamic deployer. The api offers three urls for deployment, http(s)://<hostname>:<port>/v1/deploy, http(s)://<hostname>:<port>/v1/deploy/to/instance and http(s)://<hostname>:<port>/v1/deploy/to/instance/async.

Synchronous deployment

Deployment via http(s)://<hostname>:<port>/v1/deploy (VCAP_SERVICES style)

The first way to trigger a deployment is to send a HTTP POST request to the url http(s)://<hostname>:<port>/v1/deploy. The body simply consists of a JSON object containing replacements for several of the HDI deployer's environment variables. Supported are replacements for:

  • HDI_DEPLOY_OPTIONS
  • DEPLOY_ID
  • TARGET_CONTAINER
  • SERVICE_REPLACEMENTS
  • VCAP_SERVICES

In addition to providing VCAP_SERVICES for replacing the corresponding environment variable it is also possible to provide ADDITIONAL_VCAP_SERVICES. The deployer is then called with service bindings created from the VCAP_SERVICES of the dynamic deployer by adding the service definitions given by ADDITIONAL_VCAP_SERVICES. The ADDITIONAL_VCAP_SERVICES object has the same structure as the original VCAP_SERVICES, i.e. it contains lists of service bindings. If the request contains ADDITIONAL_VCAP_SERVICES, the server scans through all of its services and either adds the list of bindings to the VCAP_SERVICES environment variable or merges the two lists in case bindings for the given service already exist. Existing bindings with the same name are replaced with the bindings from ADDITIONAL_VCAP_SERVICES.

Example:

{
    "TARGET_CONTAINER": "hdi_container_service_name",
    "ADDITIONAL_VCAP_SERVICES": {
        "hana" : [ {
            "name" : "hdi_container_service_name",
            "label" : "hana",
            "tags" : [ "hana", "database", "relational" ],
            "plan" : "hdi-shared",
            "credentials" : {
                "schema" : "DB_EXAMPLE",
                "hdi_password" : "hdi_password",
                "password" : "password",
                "driver" : "com.sap.db.jdbc.Driver",
                "port" : "30015",
                "host" : "srv1234567.host.name",
                "db_hosts" : [ {
                 "port" : 30015,
                 "host" : "srv7654321.host.name"
                } ],
                "hdi_user" : "hdi_user",
                "user" : "user",
                "url" : "jdbc:sap://srv1234567.host.name:30015/?currentschema=DB_EXAMPLE"
            }
        } ]
    }
}

Deployment via http(s)://<hostname>:<port>/v1/deploy/to/instance (Instance Manager style)

Since version 1.2.0 of the dynamic deployer there is a second way to trigger a deployment by sending a HTTP POST request to the url http(s)://<hostname>:<port>/v1/deploy/to/instance. The request body is simply a managed service instance as retrieved from the Instance Manager with a HTTP GET.

Since version 2.3.2 of the dynamic deployer the request body can be a managed service instance as retrieved from the Instance Manager or Service Manager with a HTTP GET.

Example: Instance Manager

{
  "tenant_id": "1",
  "id": "da7ff475-fd3f-4a86-a3e7-cd3e41e3653d",
  "binding_id": "3bb96cab-0bec-4088-9991-244b750e53b3",
  "instance_id": "d9cc0aef-16f7-40d2-8e10-1816b9214f2e",
  "managed_service_id": "79d9e11a-95c2-4771-ae2d-8ba703bd8fda",
  "managed_plan_id": "bebaad3e-352b-4928-bc6b-8783d754ac3b",
  "managed_instance_id": "0a4d365a-eec5-4083-85ae-677f77bb6f5d",
  "managed_binding_id": "a5cba4c8-95a3-42c8-982d-e075d0a6b941",
  "status": "CREATION_SUCCEEDED",
  "updated_on": 1494322225942,
  "credentials": {
    "host": "srv1234567.host.name",
    "port": "30015",
    "driver": "com.sap.db.jdbc.Driver",
    "url": "jdbc:sap://srv1234567.host.name:30015/?currentschema=55D392C7232649E8A2F08993645B28B5",
    "schema": "55D392C7232649E8A2F08993645B28B5",
    "hdi_user": "SBSS_78283957013891283645150604040575244555286482237534978212872169092",
    "hdi_password": "password",
    "user": "SBSS_92380540949443696814788249184554628165227387555319796659663474608",
    "password": "password"
  }
}

Example: Service Manager

{
  "id": "da7ff475-fd3f-4a86-a3e7-cd3e41e3653d",
  "ready": true,
  "service_instance_id": "790e19ae-b9f7-4d80-8e4d-d368d96f79bd",
  "last_operation": {
        "id": "e9061cfe-b70a-405b-a402-084b3ec74711",
        "ready": true,
        "type": "create",
        "state": "succeeded",
        "resource_id": "bf24e49c-fd62-4ad4-83fc-6c09132f8cf7",
        "resource_type": "/v1/service_bindings",
        "platform_id": "service-manager",
        "correlation_id": "ec849486-34b3-40ac-71e6-baf91c91cd0b",
        "reschedule": false,
        "reschedule_timestamp": "0001-01-01T00:00:00Z",
        "deletion_scheduled": "0001-01-01T00:00:00Z",
        "created_at": "2021-11-02T09:22:47.667677Z",
        "updated_at": "2021-11-02T09:22:49.288825Z"
    },
  "name": "91ce8c49-a1c8-4557-8b25-0e2c4034a4cf",
  "credentials": {
    "host": "srv1234567.host.name",
    "port": "30015",
    "driver": "com.sap.db.jdbc.Driver",
    "url": "jdbc:sap://srv1234567.host.name:30015/?currentschema=55D392C7232649E8A2F08993645B28B5",
    "schema": "55D392C7232649E8A2F08993645B28B5",
    "hdi_user": "SBSS_78283957013891283645150604040575244555286482237534978212872169092",
    "hdi_password": "password",
    "user": "SBSS_92380540949443696814788249184554628165227387555319796659663474608",
    "password": "password"
  }
}

The response from the dynamic deployer

If there was no problem with the basic authentication and the request reaches the dynamic deployer, it usually responds with status code 200 and a json body containing the result of the deployment. The response body has the following form:

{
  messages: [<list of result messages from the di server>],
  exitCode: <exit code of the call to the deployer app>
}

IMPORTANT: A status code of 200 does not mean that the deployment was successful. It just means that the dynamic deployer was able to call the (non-dynamic) deployer. If the deployer finished with no errors the exitCode attribute of the response is 0, otherwise it is 1. More detailed information about the deployment can be retrieved from the messages attribute of the response.

Asynchronous deployment

Since version 1.7.0 of the dynamic deployer there is a third way to trigger a deployment by sending a HTTP POST request to the url http(s)://<hostname>:<port>/v1/deploy/to/instance/async. The request body is simply a managed service instance as retrieved from the Instance Manager with a HTTP GET, i.e. the same as for http(s)://<hostname>:<port>/v1/deploy/to/instance. But instead of waiting until the deployment is done and then returning the results, a GUID is returned.

Since version 2.3.2 of the dynamic deployer the request body can be a managed service instance as retrieved from the Instance Manager or Service Manager with a HTTP GET.

This GUID can be used to query the status of the deployment by sending a GET request to http(s)://<hostname>:<port>/v1/status/:guid - if the deployment is still running, the response just contains a status property. If the deployment is finished, the usual response is returned - in conjunction with the status property.

Since version 2.5.0 of the dynamic deployer there is a forth way to trigger a deployment by sending a HTTP POST request to the url http(s)://<hostname>:<port>/v1/deploy/async. The request body is same as for http(s)://<hostname>:<port>/v1/deploy/. But instead of waiting until the deployment is done and then returning the results, a GUID is returned.

How to use it in a multi-target application

A multi-target application (MTA) for multi-tenancy scenarios with the instance manager typically includes multiple db modules:

  • N static db modules (type: com.sap.xs.hdi), e.g. for configuration or shared data. A static module depends on @sap/hdi-deploy; it does not depend on @sap/hdi-dynamic-deploy.
  • M dynamic db modules (type: com.sap.xs.hdi-dynamic) where the business data for a certain type of tenant is contained. A dynamic module depends on @sap/hdi-dynamic-deploy, which internally depends on @sap/hdi-deploy for deployment to the correct tenant.

Example:

modules:
  - name: db-static-1
    type: com.sap.xs.hdi
    path: db-static-1
    
  - name: db-static-2
    type: com.sap.xs.hdi
    path: db-static-2
    
  - name: db-dynamic-1
    type: com.sap.xs.hdi-dynamic
    path: db-dynamic-1
    
  - name: db-dynamic-2
    type: com.sap.xs.hdi-dynamic
    path: db-dynamic-2
    
  - name: db-dynamic-3
    type: com.sap.xs.hdi-dynamic
    path: db-dynamic-3

Accessing the underlying HTTP server

By requiring the dynamic deploy package, you can access the internal HTTP server. This way, you can decide when to start/stop the server.

The exported object offers two methods:

    /**
     * Start the HTTP server on this.port.
     *
     * @param {any} cb Callback function (error, result).
     * @returns {undefined}
     */
    function start(cb){
      <..>
    };

    /**
     * Stop the HTTP server.
     *
     * @param {any} cb Callback function (error, result).
     * @returns {undefined}
     */
    function stop(cb){
      <..>
    };

Furthermore, the object has the property port. This has to be set to the port that you want the server to listen on.

Example:

'use strict';

const {server} = require('@sap/hdi-dynamic-deploy/index');

server.port = process.env.PORT;
server.start(function(){
  console.log(`@sap/hdi-dynamic-deploy HTTP server up and running, listening on port ${  server.port}`);
});

Accessing the router functions

By requiring the dynamic deploy package, you can access the functions used for the API endpoints and can use them in your own router. Both functions expect two parameters:

  • A HTTP request object
  • A HTTP response object

Example:

'use strict';

const {deploy_to_instance, deploy} = require('@sap/hdi-dynamic-deploy/index');

/** 
 * Now the functions can be added to a router.
 * 
 * deploy_to_instance is the function used for the /v1/deploy/to/instance route
 * deploy is the function used for the /v1/deploy route
 * 
 */