the main manager component of serve.zone
Go to file
2024-05-28 18:45:34 +02:00
.gitea/workflows fix(core): update 2024-04-20 12:21:41 +02:00
.vscode fix(core): update 2024-04-20 12:21:41 +02:00
html fix(core): update 2024-04-20 12:21:41 +02:00
scripts fix(core): update 2024-04-20 12:21:41 +02:00
test fix(core): update 2024-04-20 12:21:41 +02:00
ts fix(switch to unified package for cloudly + api + cli): update 2024-05-28 18:45:34 +02:00
ts_apiclient fix(switch to unified package for cloudly + api + cli): update 2024-05-28 18:45:34 +02:00
ts_cliclient fix(core): update 2024-04-20 12:21:41 +02:00
ts_web fix(switch to unified package for cloudly + api + cli): update 2024-05-28 18:45:34 +02:00
.dockerignore fix(core): update 2024-04-20 12:21:41 +02:00
.gitignore fix(core): update 2024-04-20 12:21:41 +02:00
cli.child.ts fix(core): update 2024-04-20 12:21:41 +02:00
cli.js fix(core): update 2024-04-20 12:21:41 +02:00
cli.ts.js fix(core): update 2024-04-20 12:21:41 +02:00
Dockerfile fix(core): update 2024-04-20 12:21:41 +02:00
Dockerfile_cloudron_##version## fix(core): update 2024-04-20 12:21:41 +02:00
npmextra.json fix(switch to unified package for cloudly + api + cli): update 2024-05-28 18:45:34 +02:00
package.json 1.0.216 2024-05-28 18:45:34 +02:00
pnpm-lock.yaml fix(switch to unified package for cloudly + api + cli): update 2024-05-28 18:45:34 +02:00
qenv.yml fix(core): update 2024-04-20 12:21:41 +02:00
readme.hints.md fix(core): update 2024-04-20 12:21:41 +02:00
readme.md fix(switch to unified package for cloudly + api + cli): update 2024-05-28 18:45:34 +02:00
tsconfig.json fix(core): update 2024-04-20 12:21:41 +02:00

@serve.zone/cloudly

A cloud manager utilizing Docker Swarmkit, designed for operations on Cloudron, and supports various cloud platforms like DigitalOcean, Hetzner Cloud, and Cloudflare.

Install

To install @serve.zone/cloudly, run the following command in your terminal:

npm install @serve.zone/cloudly --save

This will install the package and add it to your project's package.json dependencies.

Usage

@serve.zone/cloudly is designed to help you manage and configure cloud environments. This package provides a comprehensive TypeScript and ESM-based interface for interacting with various cloud services, including Docker Swarmkit cluster management, and integration with cloud providers such as DigitalOcean, Hetzner Cloud, and Cloudflare.

Getting Started

Before diving into the specifics, ensure your environment is properly set up. This includes having Node.js installed (preferably the latest LTS version), and if you are working in a TypeScript project, ensure TypeScript is configured.

Initializing Cloudly

First, import Cloudly class from the package and initialize it as shown below:

import { Cloudly } from '@serve.zone/cloudly';

const myCloudlyInstance = new Cloudly();

The Cloudly class is the entry point to using the library features. It prepares the environment for configuring the cloud services.

Configuration

Configuration plays a pivotal role in how @serve.zone/cloudly operates. The library expects certain configurations to be provided, which can include credentials for cloud services, database connections, etc.

For example, to configure a connection to MongoDB, specify your MongoDB details as shown:

const myCloudlyConfig = {
    mongoDescriptor: {
        mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
        mongoDbName: 'myDatabase',
        mongoDbUser: 'myUser',
        mongoDbPass: 'myPassword',
    },
    // Additional configuration values...
};

const myCloudlyInstance = new Cloudly(myCloudlyConfig);

Managing Docker Swarmkit Cluster

Cloudly allows managing Docker Swarmkit clusters through an abstracted interface, simplifying operations such as deployment and scaling. Below are examples to demonstrate these capabilities.

Example: Start a Cloudly Instance and Add a Cluster

import { Cloudly, ClusterManager } from '@serve.zone/cloudly';

async function main() {
    const myCloudlyConfig = {
        mongoDescriptor: {
            mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
            mongoDbName: 'myDatabase',
            mongoDbUser: 'myUser',
            mongoDbPass: 'myPassword',
        },
        cfToken: 'your_cloudflare_api_token',
        environment: 'development',
        letsEncryptEmail: 'lets_encrypt_email@example.com',
        publicUrl: 'example.com',
        publicPort: 8443,
        hetznerToken: 'your_hetzner_api_token'
    };

    const myCloudlyInstance = new Cloudly(myCloudlyConfig);
    await myCloudlyInstance.start();

    const clusterManager = myCloudlyInstance.clusterManager;
    const newCluster = await clusterManager.storeCluster({
        id: 'example_cluster_id',
        data: {
            name: 'example_cluster',
            jumpCode: 'random_jump_code',
            jumpCodeUsedAt: null,
            secretKey: 'example_secret_key',
            acmeInfo: null,
            cloudlyUrl: 'https://example.com:8443',
            servers: [],
            sshKeys: [],
        },
    });

    console.log('Cluster added:', newCluster);
}
main();

Example: Manage Cloudflare DNS Records

import { Cloudly, CloudflareConnector } from '@serve.zone/cloudly';

async function manageDNSRecords() {
    const myCloudlyConfig = {
        mongoDescriptor: {
            mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
            mongoDbName: 'myDatabase',
            mongoDbUser: 'myUser',
            mongoDbPass: 'myPassword',
        },
        cfToken: 'your_cloudflare_api_token',
        environment: 'development',
        letsEncryptEmail: 'lets_encrypt_email@example.com',
        publicUrl: 'example.com',
        publicPort: 8443,
        hetznerToken: 'your_hetzner_api_token'
    };

    const myCloudlyInstance = new Cloudly(myCloudlyConfig);
    await myCloudlyInstance.start();

    const dnsInfo = {
        zoneName: 'example.com',
        recordName: 'sub.example.com',
        recordType: 'A',
        recordContent: '127.0.0.1',
    };

    const cfConnector = myCloudlyInstance.cloudflareConnector.cloudflare;
    const newRecord = await cfConnector.createDNSRecord(
        dnsInfo.zoneName,
        dnsInfo.recordName,
        dnsInfo.recordType,
        dnsInfo.recordContent
    );

    console.log('DNS Record created:', newRecord);
}
manageDNSRecords();

Example: Integrate with DigitalOcean

import { Cloudly, DigitalOceanConnector } from '@serve.zone/cloudly';

async function manageDroplet() {
    const myCloudlyConfig = {
        mongoDescriptor: {
            mongoDbUrl: 'mongodb+srv://<username>:<password>@<cluster>.mongodb.net/myFirstDatabase',
            mongoDbName: 'myDatabase',
            mongoDbUser: 'myUser',
            mongoDbPass: 'myPassword',
        },
        cfToken: 'your_cloudflare_api_token',
        environment: 'development',
        letsEncryptEmail: 'lets_encrypt_email@example.com',
        publicUrl: 'example.com',
        publicPort: 8443,
        hetznerToken: 'your_hetzner_api_token'
    };

    const myCloudlyInstance = new Cloudly(myCloudlyConfig);
    await myCloudlyInstance.start();

    const doConnector = myCloudlyInstance.digitaloceanConnector;
    const dropletInfo = {
        name: 'example-droplet',
        region: 'nyc3',
        size: 's-1vcpu-1gb',
        image: 'ubuntu-20-04-x64',
    };

    const newDroplet = await doConnector.createDroplet(
        dropletInfo.name,
        dropletInfo.region,
        dropletInfo.size,
        dropletInfo.image
    );

    console.log('Droplet created:', newDroplet);
}
manageDroplet();

Using Cloudly Web Interface

If your project includes a web interface to manage various sections like DNS, deployments, clusters, etc., you can use the provided elements and state management. Below is an example of setting up a dashboard using the components defined:

import { commitinfo } from '../00_commitinfo_data.js';
import * as plugins from '../plugins.js';

import * as appstate from '../appstate.js';

import {
  DeesElement,
  css,
  cssManager,
  customElement,
  html,
  state
} from '@design.estate/dees-element';
import { CloudlyViewBackups } from './cloudly-view-backups.js';
import { CloudlyViewClusters } from './cloudly-view-clusters.js';
import { CloudlyViewDbs } from './cloudly-view-dbs.js';
import { CloudlyViewDeployments } from './cloudly-view-deployments.js';
import { CloudlyViewDns } from './cloudly-view-dns.js';
import { CloudlyViewImages } from './cloudly-view-images.js';
import { CloudlyViewLogs } from './cloudly-view-logs.js';
import { CloudlyViewMails } from './cloudly-view-mails.js';
import { CloudlyViewOverview } from './cloudly-view-overview.js';
import { CloudlyViewS3 } from './cloudly-view-s3.js';
import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js';
import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js';
import { CloudlyViewServices } from './cloudly-view-services.js';

declare global {
  interface HTMLElementTagNameMap {
    'cvault-dashboard': CloudlyDashboard;
  }
}

@customElement('cloudly-dashboard')
export class CloudlyDashboard extends DeesElement {
  @state() private jwt: string;
  @state() private data: appstate.IDataState = {
    secretGroups: [],
    secretBundles: [],
    clusters: [],
  };

  constructor() {
    super();
    const subcription = appstate.dataState
      .select((stateArg) => stateArg)
      .subscribe((dataArg) => {
        this.data = dataArg;
      });
    this.rxSubscriptions.push(subcription);
  }

  public static styles = [
    cssManager.defaultStyles,
    css`
      .maincontainer {
        position: relative;
        width: 100vw;
        height: 100vh;
      }

      h1 {
        font-weight: 400;
        font-size: 24px;
        font-family: 'Cal Sans';
      }
    `,
  ];
  public render() {
    return html`
      <div class="maincontainer">
        <dees-simple-login name="cloudly v${commitinfo.version}">
          <dees-simple-appdash name="cloudly v${commitinfo.version}"
            .viewTabs=${[
              {
                name: 'Overview',
                element: CloudlyViewOverview,
              },
              {
                name: 'SecretGroups',
                element: CloudlyViewSecretGroups,
              },
              {
                name: 'SecretBundles',
                element: CloudlyViewSecretBundles,
              },
              {
                name: 'Clusters',
                element: CloudlyViewClusters,
              },
              {
                name: 'Images',
                element: CloudlyViewImages,
              },
              {
                name: 'Services',
                element: CloudlyViewServices,
              },
              {
                name: 'Deployments',
                element: CloudlyViewDeployments,
              },
              {
                name: 'DNS',
                element: CloudlyViewDns,
              },
              {
                name: 'Mails',
                element: CloudlyViewMails,
              },
              {
                name: 'Logs',
                element: CloudlyViewLogs,
              },
              {
                name: 's3',
                element: CloudlyViewS3,
              },
              {
                name: 'DBs',
                element: CloudlyViewDbs,
              },
              {
                name: 'Backups',
                element: CloudlyViewBackups,
              },
            ] as plugins.deesCatalog.IView[]}
          ></dees-simple-appdash>
        </dees-simple-login>
      </div>
    `;
  }
  public async firstUpdated() {
    const simpleLogin = this.shadowRoot.querySelector('dees-simple-login');
    simpleLogin.addEventListener('login', (e: CustomEvent) => {
      console.log(e.detail);
      this.login(e.detail.data.username, e.detail.data.password);
    });
    this.addEventListener('contextmenu', (eventArg) => {
      plugins.deesCatalog.DeesContextmenu.openContextMenuWithOptions(eventArg, [
        {
          name: 'About',
          iconName: 'mugHot',
          action: async () => {
            await plugins.deesCatalog.DeesModal.createAndShow({
              heading: 'About',
              content: html`configvault ${commitinfo.version}`,
              menuOptions: [
                {
                  name: 'close',
                  iconName: null,
                  action: async (modalArg) => {
                    await modalArg.destroy();
                  },
                },
              ],
            });
          },
        },
      ]);
    });

    // lets deal with initial state
    const domtools = await this.domtoolsPromise;
    const loginState = appstate.loginStatePart.getState();
    console.log(loginState);
    if (loginState.jwt) {
      this.jwt = loginState.jwt;
      await simpleLogin.switchToSlottedContent();
      await appstate.dataState.dispatchAction(appstate.getDataAction, null);
    }
  }

  private async login(username: string, password: string) {
    console.log(`attempting to login...`);
    const simpleLogin = this.shadowRoot.querySelector('dees-simple-login');
    const form = simpleLogin.shadowRoot.querySelector('dees-form');
    form.setStatus('pending', 'Logging in...');
    const state = await appstate.loginStatePart.dispatchAction(appstate.loginAction, {
      username,
      password,
    });
    if (state.jwt) {
      console.log('got jwt');
      this.jwt = state.jwt;
      form.setStatus('success', 'Logged in!');
      await simpleLogin.switchToSlottedContent();
      await appstate.dataState.dispatchAction(appstate.getDataAction, null);
    } else {
      form.setStatus('error', 'Login failed!');
      await domtools.convenience.smartdelay.delayFor(2000);
      form.reset();
    }
  }

  private async logout() {}
}

This script sets up a cloud management dashboard for interacting with various cloud services seamlessly. It covers creating clusters, managing DNS records, handling cloud-provider-specific resources, and much more.

With the examples provided above, you should now have a good understanding of how to use @serve.zone/cloudly to manage your cloud infrastructure programmatically. For deeper insights and additional features, refer to the documentation relevant to specific modules and methods used in your application.

This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the license file within this repository.

Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

Trademarks

This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.

Company Information

Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany

For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.

By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.