the main manager component of serve.zone
Go to file
Philipp Kunz acc642adf9
Some checks failed
Docker (tags) / security (push) Failing after 16s
Docker (tags) / test (push) Has been skipped
Docker (tags) / release (push) Has been skipped
Docker (tags) / metadata (push) Has been skipped
1.1.6
2024-06-20 19:20:17 +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(structure): improve structure, prepare better CI integration 2024-06-05 14:13:03 +02:00
ts fix(core): update 2024-06-20 19:20:16 +02:00
ts_apiclient fix(structure): improve structure, prepare better CI integration 2024-06-05 14:13:03 +02:00
ts_cliclient fix(core): update 2024-04-20 12:21:41 +02:00
ts_web fix(core): update 2024-06-20 19:20:16 +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(core): update 2024-06-20 19:20:16 +02:00
package.json 1.1.6 2024-06-20 19:20:17 +02:00
pnpm-lock.yaml fix(core): update 2024-06-20 19:00:58 +02:00
qenv.yml fix(core): update 2024-04-20 12:21:41 +02:00
readme.hints.md fix(core): update 2024-06-20 19:20:16 +02:00
readme.md fix(core): update 2024-06-20 19:20:16 +02:00
tsconfig.json fix(core): update 2024-04-20 12:21:41 +02:00

@serve.zone/cloudly

A comprehensive multi-cloud manager leveraging Docker Swarmkit to orchestrate containerized applications across various cloud services and integrate robust configuration and API management capabilities.

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 the 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',
    },
    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);

Managing Docker Swarmkit Clusters

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: Initializing a Cloudly Instance and Adding 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();

Additional Use Cases

Managing Cloudflare DNS Records

You can manage Cloudflare DNS records using the CloudflareConnector provided by Cloudly.

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();

Integrating with DigitalOcean

Integrate with DigitalOcean to manage droplets and other resources.

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:

Web Dashboard Example

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 {
    'cloudly-dashboard': CloudlyDashboard;
  }
}

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

  constructor() {
    super();
    document.title = `cloudly v${commitinfo.version}`;
    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,
              },
              {
                name: 'Fleet',
                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`cloudly ${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.getAllDataAction, null);
    }
  }

  private async login(username: string, password: string) {
    const domtools = await this.domtoolsPromise;
    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.getAllDataAction, null);
    } else {
      form.setStatus('error', 'Login failed!');
      await domtools.convenience.smartdelay.delayFor(2000);
      form.reset();
    }
  }

  private async logout() {}
}

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.