diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f66114fce88..3ab595b6619 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,24 @@ on: pull_request: jobs: + lint: + strategy: + matrix: + package: ['linode-manager', '@linode/api-v4', '@linode/validation'] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: "18.14" + - uses: actions/cache@v3 + with: + path: | + **/node_modules + key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + - run: yarn --frozen-lockfile + - run: yarn workspace ${{ matrix.package }} run lint + build-validation: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e55968c0cdc..fda1fed0802 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -25,8 +25,11 @@ jobs: - name: Install Dependencies run: yarn --frozen-lockfile - - name: Run build - run: yarn build + - name: Build @linode/validation + run: yarn build:validation + + - name: Build @linode/api-v4 + run: yarn build:sdk - name: Run Base Branch Coverage run: yarn coverage:summary @@ -65,8 +68,11 @@ jobs: - name: Install Dependencies run: yarn --frozen-lockfile - - name: Run Build - run: yarn build + - name: Build @linode/validation + run: yarn build:validation + + - name: Build @linode/api-v4 + run: yarn build:sdk - name: Run Current Branch Coverage run: yarn coverage:summary diff --git a/.github/workflows/coverage_badge.yml b/.github/workflows/coverage_badge.yml index b4cf419261c..dee947804c6 100644 --- a/.github/workflows/coverage_badge.yml +++ b/.github/workflows/coverage_badge.yml @@ -27,8 +27,11 @@ jobs: - name: Install Dependencies run: yarn --frozen-lockfile - - name: Run Build - run: yarn build + - name: Build @linode/validation + run: yarn build:validation + + - name: Build @linode/api-v4 + run: yarn build:sdk - name: Run Base Branch Coverage run: yarn coverage:summary diff --git a/packages/api-v4/CHANGELOG.md b/packages/api-v4/CHANGELOG.md index 89cf1b68b8c..65c16932d3b 100644 --- a/packages/api-v4/CHANGELOG.md +++ b/packages/api-v4/CHANGELOG.md @@ -1,3 +1,14 @@ +## [2024-01-08] - v0.107.0 + + +### Added: + +- Optional `headers` to `getProfile` function ([#9987](https://github.com/linode/manager/pull/9987)) + +### Tech Stories: + +- Add Lint GitHub Action ([#9973](https://github.com/linode/manager/pull/9973)) + ## [2023-12-11] - v0.106.0 diff --git a/packages/api-v4/package.json b/packages/api-v4/package.json index da52fac15de..b47b260030f 100644 --- a/packages/api-v4/package.json +++ b/packages/api-v4/package.json @@ -1,6 +1,6 @@ { "name": "@linode/api-v4", - "version": "0.106.0", + "version": "0.107.0", "homepage": "https://github.com/linode/manager/tree/develop/packages/api-v4", "bugs": { "url": "https://github.com/linode/manager/issues" @@ -67,7 +67,7 @@ "lint-staged": "^13.2.2", "prettier": "~2.2.1", "tsup": "^7.2.0", - "vitest": "^0.34.6" + "vitest": "^1.0.1" }, "lint-staged": { "*.{ts,tsx,js}": [ diff --git a/packages/api-v4/src/account/types.ts b/packages/api-v4/src/account/types.ts index 2e98373bb62..a08f586db08 100644 --- a/packages/api-v4/src/account/types.ts +++ b/packages/api-v4/src/account/types.ts @@ -68,6 +68,7 @@ export type AccountCapability = | 'Machine Images' | 'Managed Databases' | 'NodeBalancers' + | 'Object Storage Access Key Regions' | 'Object Storage' | 'Vlans' | 'VPCs'; diff --git a/packages/api-v4/src/firewalls/types.ts b/packages/api-v4/src/firewalls/types.ts index 5d5148b6f3b..19f86dc1480 100644 --- a/packages/api-v4/src/firewalls/types.ts +++ b/packages/api-v4/src/firewalls/types.ts @@ -14,6 +14,12 @@ export interface Firewall { rules: FirewallRules; created_dt: string; updated_dt: string; + entities: { + id: number; + type: FirewallDeviceEntityType; + label: string; + url: string; + }[]; } export interface FirewallRules { diff --git a/packages/api-v4/src/object-storage/types.ts b/packages/api-v4/src/object-storage/types.ts index 7648dc514ed..a13ee820bfc 100644 --- a/packages/api-v4/src/object-storage/types.ts +++ b/packages/api-v4/src/object-storage/types.ts @@ -25,7 +25,8 @@ export interface UpdateObjectStorageKeyRequest { export interface ObjectStorageBucketRequestPayload { label: string; - cluster: string; + region?: string; // @TODO OBJ Multicluster - This field will become required, and the 'cluster' field will be deprecated once the feature is fully rolled out in production as part of the process of cleaning up the 'objMultiCluster' feature flag. + cluster?: string; acl?: 'private' | 'public-read' | 'authenticated-read' | 'public-read-write'; cors_enabled?: boolean; } @@ -36,6 +37,7 @@ export interface ObjectStorageDeleteBucketRequestPayload { } export interface ObjectStorageBucket { + region?: string; // @TODO OBJ Multicluster - This field will become required, and the 'cluster' field will be deprecated once the feature is fully rolled out in production as part of the process of cleaning up the 'objMultiCluster' feature flag. label: string; created: string; cluster: string; diff --git a/packages/api-v4/src/profile/profile.ts b/packages/api-v4/src/profile/profile.ts index 2a179722d5c..1779d465d66 100644 --- a/packages/api-v4/src/profile/profile.ts +++ b/packages/api-v4/src/profile/profile.ts @@ -10,6 +10,7 @@ import Request, { setData, setMethod, setParams, + setHeaders, setURL, setXFilter, } from '../request'; @@ -24,6 +25,7 @@ import { SendPhoneVerificationCodePayload, VerifyVerificationCodePayload, } from './types'; +import type { RequestOptions } from '../types'; /** * getProfile @@ -31,8 +33,13 @@ import { * Return the current (logged in) user's profile. * */ -export const getProfile = () => - Request(setURL(`${API_ROOT}/profile`), setMethod('GET')); +export const getProfile = ({ headers }: RequestOptions = {}) => { + return Request( + setURL(`${API_ROOT}/profile`), + setMethod('GET'), + setHeaders(headers) + ); +}; /** * updateProfile diff --git a/packages/manager/.eslintrc.js b/packages/manager/.eslintrc.cjs similarity index 99% rename from packages/manager/.eslintrc.js rename to packages/manager/.eslintrc.cjs index 1aefa4734d9..3c64f9b2c0e 100644 --- a/packages/manager/.eslintrc.js +++ b/packages/manager/.eslintrc.cjs @@ -20,6 +20,7 @@ module.exports = { ignorePatterns: [ 'node_modules', 'build', + 'storybook-static', '.storybook', 'e2e', 'public', diff --git a/packages/manager/.storybook/main.ts b/packages/manager/.storybook/main.ts index 8372cb5378a..a4a9b625d6f 100644 --- a/packages/manager/.storybook/main.ts +++ b/packages/manager/.storybook/main.ts @@ -13,6 +13,7 @@ const config: StorybookConfig = { '@storybook/addon-measure', '@storybook/addon-actions', 'storybook-dark-mode', + '@storybook/addon-storysource', ], staticDirs: ['../public'], framework: { diff --git a/packages/manager/.storybook/preview.tsx b/packages/manager/.storybook/preview.tsx index 5e83954a674..43df4076fb8 100644 --- a/packages/manager/.storybook/preview.tsx +++ b/packages/manager/.storybook/preview.tsx @@ -89,7 +89,6 @@ const preview: Preview = { - ), }, diff --git a/packages/manager/CHANGELOG.md b/packages/manager/CHANGELOG.md index d207b1bf4ab..17dd41dba32 100644 --- a/packages/manager/CHANGELOG.md +++ b/packages/manager/CHANGELOG.md @@ -4,6 +4,62 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [2024-01-08] - v1.109.0 + + +### Changed: + +- Improve layout of User Permissions page ([#10005](https://github.com/linode/manager/pull/10005)) +- Update toast notifications for UserPermissions ([#10011](https://github.com/linode/manager/pull/10011)) +- VLAN availability text on Linode Create ([#9989](https://github.com/linode/manager/pull/9989)) +- Default access to `None` for all scopes when creating Personal Access Tokens ([#9992](https://github.com/linode/manager/pull/9992)) +- Filter already assigned services from firewall dropdowns ([#9993](https://github.com/linode/manager/pull/9993)) + +### Fixed: + +- User Permissions toggle and radio button accessibility ([#10009](https://github.com/linode/manager/pull/10009)) + +### Tech Stories: + +- Currency and DateTimeDisplay v7 storybook migrations ([#10007](https://github.com/linode/manager/pull/10007)) +- ColorPalette and CircleProgress v7 storybook migration ([#10015](https://github.com/linode/manager/pull/10015)) +- DebouncedSearchTextfield and EditableText v7 storybook migrations ([#10017](https://github.com/linode/manager/pull/10017)) +- Placeholder and EntityDetails v7 storybook migrations ([#10019](https://github.com/linode/manager/pull/10019)) +- PaginationControls V7 story migration ([#9959](https://github.com/linode/manager/pull/9959)) +- TagsInput & TagsPanel Storybook v7 Stories ([#9963](https://github.com/linode/manager/pull/9963)) +- Add Lint Github Action ([#9973](https://github.com/linode/manager/pull/9973)) +- Complete @mui/styles to tss-react migration and remove @mui/styles ([#9978](https://github.com/linode/manager/pull/9978)) +- ErrorState and FileUploader v7 storybook migrations ([#9981](https://github.com/linode/manager/pull/9981)) +- Speed up code coverage Github Actions jobs by skipping Cloud Manager build ([#9988](https://github.com/linode/manager/pull/9988)) +- Radio and TextField v7 storybook migrations ([#9994](https://github.com/linode/manager/pull/9994)) +- Graphs stories v7 migration ([#9999](https://github.com/linode/manager/pull/9999)) +- Add ability to pass headers to useProfile query ([#9987](https://github.com/linode/manager/pull/9987)) + +### Tests: + +- Add Cypress test for Firewalls empty state landing page ([#10000](https://github.com/linode/manager/pull/10000)) +- Add integration test for Domains empty landing page ([#10004](https://github.com/linode/manager/pull/10004)) +- Add Cypress integration tests for User Permissions page ([#10009](https://github.com/linode/manager/pull/10009)) +- Fix `CreditCard.test.tsx` failing unit test triggered by new year ([#10023](https://github.com/linode/manager/pull/10023)) +- Add integration test for AGLB Load Balancer delete flows. ([#9955](https://github.com/linode/manager/pull/9955)) +- Add Cypress test for Volumes empty state landing page ([#9995](https://github.com/linode/manager/pull/9995)) +- Tests to power on/off and reboot Linodes ([#9980](https://github.com/linode/manager/pull/9980)) + +### Upcoming Features: + +- Add child access user permissions for parent accounts ([#10005](https://github.com/linode/manager/pull/10005)) +- Update top menu for parent, child, and proxy accounts ([#10014](https://github.com/linode/manager/pull/10014)) +- Add AGLB Service Target Section to Full Create Flow ([#9965](https://github.com/linode/manager/pull/9965)) +- Change AGLB Rule Session Stickiness unit from milliseconds to seconds ([#9969](https://github.com/linode/manager/pull/9969)) +- Improve AGLB selects and other UX ([#9975](https://github.com/linode/manager/pull/9975)) +- Ability to choose a single Compute Region ID (e.g., us-east) in Create Object Storage Bucket drawer ([#9976](https://github.com/linode/manager/pull/9976)) +- Add mocks and update queries for new Parent/Child endpoints ([#9977](https://github.com/linode/manager/pull/9977)) +- Replace NodeBalancer detail charts with Recharts ([#9983](https://github.com/linode/manager/pull/9983)) +- Revised copy for Private IP add-on in Linode Create flow ([#9990](https://github.com/linode/manager/pull/9990)) +- Add `child_account` oauth scope to Personal Access Token drawers ([#9992](https://github.com/linode/manager/pull/9992)) +- Add AGLB Routes section of full create page ([#9997](https://github.com/linode/manager/pull/9997)) + + ## [2023-12-11] - v1.108.0 ### Added: diff --git a/packages/manager/cypress/e2e/core/account/user-permissions.spec.ts b/packages/manager/cypress/e2e/core/account/user-permissions.spec.ts new file mode 100644 index 00000000000..f0f45768b7b --- /dev/null +++ b/packages/manager/cypress/e2e/core/account/user-permissions.spec.ts @@ -0,0 +1,475 @@ +import type { Grant, Grants } from '@linode/api-v4'; +import { accountUserFactory } from '@src/factories/accountUsers'; +import { grantsFactory } from '@src/factories/grants'; +import { userPermissionsGrants } from 'support/constants/user-permissions'; +import { + mockGetUser, + mockGetUserGrants, + mockGetUsers, + mockUpdateUser, + mockUpdateUserGrants, +} from 'support/intercepts/account'; +import { ui } from 'support/ui'; +import { shuffleArray } from 'support/util/arrays'; +import { randomLabel } from 'support/util/random'; + +// Message shown when user has unrestricted account acess. +const unrestrictedAccessMessage = + 'This user has unrestricted access to the account.'; + +// Toggle button labels for Global Permissions section. +const globalPermissionsLabels = [ + 'Can add Linodes to this account ($)', + 'Can add Longview clients to this account', + 'Can add Domains using the DNS Manager', + 'Can create frozen Images under this account ($)', + 'Can add Firewalls to this account', + 'Can add VPCs to this account', + 'Can add NodeBalancers to this account ($)', + 'Can modify this account’s Longview subscription ($)', + 'Can create StackScripts under this account', + 'Can add Block Storage Volumes to this account ($)', + 'Can add Databases to this account ($)', +]; + +// Specific permission entity types. +const specificPermissionsTypes = [ + 'Linodes', + 'Firewalls', + 'StackScripts', + 'Images', + 'Volumes', + 'NodeBalancers', + 'Domains', + 'Longview Clients', + 'Databases', + 'VPCs', +]; + +/** + * Returns a copy of a Grants object with its entity-specific permissions set to a new value. + * + * @param grants - Grants that should be copied with new permissions applied. + * @param newPermissions - New permissions to apply to Grants. + * + * @returns Clone of `grants` with new permissions applied. + */ +const updateGrantMockPermissions = ( + grants: Grants, + newPermissions: 'read_only' | 'read_write' | null +) => { + return { + ...grants, + database: grants.database.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + domain: grants.domain.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + firewall: grants.firewall.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + image: grants.image.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + linode: grants.linode.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + longview: grants.longview.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + nodebalancer: grants.nodebalancer.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + stackscript: grants.stackscript.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + volume: grants.volume.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + vpc: grants.vpc.map((grant: Grant) => ({ + ...grant, + permissions: newPermissions, + })), + }; +}; + +/** + * Returns an array of entity labels belonging to the given Grants object. + * + * @returns Array of entity labels. + */ +const entityLabelsFromGrants = (grants: Grants) => { + return [ + ...grants.database, + ...grants.domain, + ...grants.firewall, + ...grants.image, + ...grants.linode, + ...grants.longview, + ...grants.nodebalancer, + ...grants.stackscript, + ...grants.volume, + ...grants.vpc, + ].map((grant: Grant) => grant.label); +}; + +/** + * Assert whether all global permissions are enabled or disabled. + * + * @param enabled - When `true`, assert that all permissions are enabled. Otherwise, assert they are disabled. + */ +const assertAllGlobalPermissions = (enabled: boolean) => { + globalPermissionsLabels.forEach((permissionLabel: string) => { + const checkedQuery = enabled ? 'be.checked' : 'not.be.checked'; + cy.findByLabelText(permissionLabel).should(checkedQuery); + }); +}; + +/** + * Selects "None", "Read Only", or "Read-Write" billing access. + * + * @param billingAccess - Billing access to select. + */ +const selectBillingAccess = ( + billingAccess: 'None' | 'Read Only' | 'Read-Write' +) => { + cy.get(`[data-qa-select-card-heading="${billingAccess}"]`) + .closest('[data-qa-selection-card]') + .should('be.visible') + .click(); +}; + +/** + * Asserts whether "None", "Read Only", or "Read-Write" billing access is selected. + * + * @param billingAccess - Selected billing access to assert. + */ +const assertBillingAccessSelected = ( + billingAccess: 'None' | 'Read Only' | 'Read-Write' +) => { + cy.get(`[data-qa-select-card-heading="${billingAccess}"]`) + .closest('[data-qa-selection-card]') + .should('be.visible') + .should('have.attr', 'data-qa-selection-card-checked', 'true'); +}; + +describe('User permission management', () => { + /* + * - Confirms that full account access can be toggled for account users using mock API data. + * - Confirms that users can navigate to User Permissions pages via Users & Grants page. + * - Confirms that User Permissions page updates to reflect enabled full account access. + * - Confirms that User Permissions page updates to reflect disabled full account access. + */ + it('can toggle full account access', () => { + const mockUser = accountUserFactory.build({ + username: randomLabel(), + restricted: false, + }); + + const mockUserUpdated = { + ...mockUser, + restricted: true, + }; + + const mockUserGrantsUpdated = grantsFactory.build(); + const mockUserGrants = { + ...mockUserGrantsUpdated, + global: undefined, + }; + + mockGetUsers([mockUser]).as('getUsers'); + mockGetUser(mockUser).as('getUser'); + mockGetUserGrants(mockUser.username, mockUserGrants).as('getUserGrants'); + + // Navigate to Users & Grants page, find mock user, click its "User Permissions" button. + cy.visitWithLogin('/account/users'); + cy.wait('@getUsers'); + cy.findByText(mockUser.username) + .should('be.visible') + .closest('tr') + .within(() => { + ui.button + .findByTitle('User Permissions') + .should('be.visible') + .should('be.enabled') + .click(); + }); + + // Confirm that Cloud navigates to the user's permissions page and that user has + // unrestricted account access. + cy.url().should( + 'endWith', + `/account/users/${mockUser.username}/permissions` + ); + cy.findByText(unrestrictedAccessMessage).should('be.visible'); + + // Restrict account access, confirm page updates to reflect change. + mockUpdateUser(mockUser.username, mockUserUpdated); + mockGetUserGrants(mockUser.username, mockUserGrantsUpdated); + cy.findByLabelText('Toggle Full Account Access') + .should('be.visible') + .click(); + + ui.toast.assertMessage('User permissions successfully saved.'); + + // Smoke tests to confirm that "Global Permissions" and "Specific Permissions" + // sections are visible. + cy.findByText(unrestrictedAccessMessage).should('not.exist'); + cy.get('[data-qa-global-section]') + .should('be.visible') + .within(() => { + cy.contains( + 'Configure the specific rights and privileges this user has within the account.' + ).should('be.visible'); + cy.findByText('Billing Access').should('be.visible'); + globalPermissionsLabels.forEach((permissionLabel: string) => { + cy.findByText(permissionLabel).should('be.visible'); + }); + }); + + cy.get('[data-qa-entity-section]') + .should('be.visible') + .within(() => { + cy.findByText('Specific Permissions').should('be.visible'); + specificPermissionsTypes.forEach((permissionLabel: string) => { + cy.findByText(permissionLabel).should('be.visible'); + }); + }); + + // Re-enable unrestricted account access, confirm page updates to reflect change. + mockUpdateUser(mockUser.username, mockUser); + mockGetUserGrants(mockUser.username, mockUserGrants); + cy.findByLabelText('Toggle Full Account Access') + .should('be.visible') + .click(); + + cy.findByText(unrestrictedAccessMessage).should('be.visible'); + cy.findByText('Global Permissions').should('not.exist'); + cy.findByText('Billing Access').should('not.exist'); + cy.findByText('Specific Permissions').should('not.exist'); + }); + + /* + * - Confirms that global and specific user permissions can be updated using mock API data. + * - Confirms that toast notification is shown when updating global and specific permissions. + */ + it('can update global and specific permissions', () => { + const mockUser = accountUserFactory.build({ + username: randomLabel(), + restricted: true, + }); + + const mockUserGrants = { ...userPermissionsGrants }; + const grantEntities = entityLabelsFromGrants(mockUserGrants); + + // Mock grants after global permissions changes have been applied. + const mockUserGrantsUpdatedGlobal: Grants = { + ...mockUserGrants, + global: { + account_access: 'read_only', + cancel_account: true, + child_account_access: true, + add_domains: true, + add_firewalls: true, + add_images: true, + add_linodes: true, + add_longview: true, + add_nodebalancers: true, + add_stackscripts: true, + add_volumes: true, + add_vpcs: true, + longview_subscription: true, + }, + }; + + // Mock grants after entity-specific permissions changes have been applied. + const mockUserGrantsUpdatedSpecific = { + ...mockUserGrantsUpdatedGlobal, + ...updateGrantMockPermissions(mockUserGrantsUpdatedGlobal, 'read_write'), + }; + + mockGetUser(mockUser).as('getUser'); + mockGetUserGrants(mockUser.username, mockUserGrants).as('getUserGrants'); + cy.visitWithLogin(`/account/users/${mockUser.username}/permissions`); + cy.wait(['@getUser', '@getUserGrants']); + + mockUpdateUserGrants(mockUser.username, mockUserGrantsUpdatedGlobal).as( + 'updateUserGrants' + ); + cy.get('[data-qa-global-section]') + .should('be.visible') + .within(() => { + // Confirm that all global permissions are disabled, and then enable some. + assertAllGlobalPermissions(false); + assertBillingAccessSelected('None'); + + // Enable all global permissions and "Read-Only" billing access. + globalPermissionsLabels.forEach((permissionLabel: string) => { + cy.findByText(permissionLabel).should('be.visible').click(); + }); + selectBillingAccess('Read Only'); + + ui.button + .findByTitle('Save') + .should('be.visible') + .should('be.enabled') + .click(); + + cy.wait('@updateUserGrants'); + }); + + // Confirm that toast notification appears when updating global permissions. + ui.toast.assertMessage('General user permissions successfully saved.'); + + // Update entity-specific user permissions. + mockUpdateUserGrants(mockUser.username, mockUserGrantsUpdatedSpecific).as( + 'updateUserGrants' + ); + cy.get('[data-qa-entity-section]') + .should('be.visible') + .within(() => { + grantEntities.forEach((entityLabel: string) => { + cy.findByText(entityLabel) + .should('be.visible') + .closest('tr') + .within(() => { + // Confirm that "None" radio button is selected. + cy.get('[data-qa-permission="None"]') + .should('have.attr', 'data-qa-radio', 'true') + .should('be.visible'); + + // Click "Read-Write" radio button, confirm selection changes. + cy.get('[data-qa-permission="Read-Write"]') + .should('have.attr', 'data-qa-radio', 'false') + .should('be.visible') + .click(); + + cy.get('[data-qa-permission="Read-Write"]').should( + 'have.attr', + 'data-qa-radio', + 'true' + ); + }); + }); + + // Save changes and confirm that toast notification appears. + ui.button + .findByTitle('Save') + .should('be.visible') + .should('be.enabled') + .click(); + + cy.wait('@updateUserGrants'); + }); + + ui.toast.assertMessage( + 'Entity-specific user permissions successfully saved.' + ); + }); + + /* + * - Confirms that users can discard changes to their global permissions using "Reset" button. + * - Confirms that users can discard changes to their entity-specific permissions using "Reset" button. + */ + it('can reset user permissions changes', () => { + const mockUser = accountUserFactory.build({ + username: randomLabel(), + restricted: true, + }); + + const mockUserGrants = { ...userPermissionsGrants }; + const grantEntities = entityLabelsFromGrants(mockUserGrants); + + mockGetUser(mockUser); + mockGetUserGrants(mockUser.username, mockUserGrants); + cy.visitWithLogin(`/account/users/${mockUser.username}/permissions`); + + // Test reset in Global Permissions section. + cy.get('[data-qa-global-section]') + .should('be.visible') + .within(() => { + // Confirm that all global permissions are disabled and that the user + // does not have billing access. + assertAllGlobalPermissions(false); + assertBillingAccessSelected('None'); + + // Enable random permissions and billing read-write access. + shuffleArray(globalPermissionsLabels) + .slice(0, 5) + .forEach((permissionLabel: string) => { + cy.findByText(permissionLabel).should('be.visible').click(); + }); + + selectBillingAccess('Read-Write'); + + // Click "Reset" button and confirm that global permissions revert to + // their initial state. + ui.button + .findByTitle('Reset') + .should('be.visible') + .should('be.enabled') + .click(); + + assertAllGlobalPermissions(false); + assertBillingAccessSelected('None'); + }); + + // Test reset in Specific Permissions section. + cy.get('[data-qa-entity-section]') + .should('be.visible') + .within(() => { + grantEntities.forEach((entityLabel: string) => { + cy.findByText(entityLabel) + .should('be.visible') + .closest('tr') + .within(() => { + // Confirm that "None" radio button is selected. + cy.get('[data-qa-permission="None"]') + .should('have.attr', 'data-qa-radio', 'true') + .should('be.visible'); + + // Click "Read Only" radio button, confirm selection changes. + cy.get('[data-qa-permission="Read Only"]') + .should('have.attr', 'data-qa-radio', 'false') + .should('be.visible') + .click(); + + cy.get('[data-qa-permission="Read Only"]').should( + 'have.attr', + 'data-qa-radio', + 'true' + ); + }); + }); + + // Reset changes and confirm that permissions revert to initial state. + ui.button + .findByTitle('Reset') + .should('be.visible') + .should('be.enabled') + .click(); + + grantEntities.forEach((entityLabel: string) => { + cy.findByText(entityLabel) + .should('be.visible') + .closest('tr') + .within(() => { + // Confirm that "None" radio button is selected. + cy.get('[data-qa-permission="None"]') + .should('have.attr', 'data-qa-radio', 'true') + .should('be.visible'); + }); + }); + }); + }); +}); diff --git a/packages/manager/cypress/e2e/core/domains/domains-empty-landing-page.spec.ts b/packages/manager/cypress/e2e/core/domains/domains-empty-landing-page.spec.ts new file mode 100644 index 00000000000..6b99ded32a4 --- /dev/null +++ b/packages/manager/cypress/e2e/core/domains/domains-empty-landing-page.spec.ts @@ -0,0 +1,74 @@ +import { ui } from 'support/ui'; +import { mockGetDomains } from 'support/intercepts/domains'; + +describe('Domains empty landing page', () => { + /** + * - Confirms Domains landing page empty state is shown when no Domains are present: + * - Confirms that "Getting Started Guides" and "Video Playlist" are listed on landing page. + * - Confirms that clicking on "Import A Zone" opens "Import a Zone" drawer. + * - Confirms that clicking "Create Domain" navigates user to domain create page. + */ + it('shows the empty state when there are no domains', () => { + mockGetDomains([]).as('getDomains'); + + cy.visitWithLogin('/domains'); + cy.wait(['@getDomains']); + + // confirms helper text + cy.findByText('Easy domain management').should('be.visible'); + cy.findByText( + 'A comprehensive, reliable, and fast DNS service that provides easy domain management for no additional cost.' + ).should('be.visible'); + + // checks that guides are visible + cy.findByText('Getting Started Guides').should('be.visible'); + cy.findByText('Overview of DNS Manager').should('be.visible'); + cy.findByText('Getting Started with DNS Manager').should('be.visible'); + cy.findByText('Create a Domain Zone').should('be.visible'); + cy.findByText('View additional DNS Manager guides').should('be.visible'); + + // checks that videos are visible + cy.findByText('Video Playlist').should('be.visible'); + cy.findByText( + 'Linode DNS Manager | Total Control Over Your DNS Records' + ).should('be.visible'); + cy.findByText( + 'Using Domains with Your Server | Common DNS Configurations' + ).should('be.visible'); + cy.findByText('Connect a Domain to a Linode Server').should('be.visible'); + cy.findByText('View our YouTube channel').should('be.visible'); + + // confirms Import a Zone drawer + ui.button + .findByTitle('Import a Zone') + .should('be.visible') + .should('be.enabled') + .click(); + ui.drawer + .findByTitle('Import a Zone') + .should('be.visible') + .within(() => { + ui.buttonGroup + .findButtonByTitle('Import') + .should('be.visible') + .should('be.disabled'); + + cy.findByText('Remote Nameserver').should('be.visible'); + ui.buttonGroup + .findButtonByTitle('Cancel') + .should('be.visible') + .should('be.enabled') + .click(); + }); + cy.findByText('Remote Nameserver').should('not.be.visible'); + + // confirms clicking on 'Create Domain' button + ui.button + .findByTitle('Create Domain') + .should('be.visible') + .should('be.enabled') + .click(); + + cy.url().should('endWith', '/domains/create'); + }); +}); diff --git a/packages/manager/cypress/e2e/core/firewalls/landing-page-empty-state.spec.ts b/packages/manager/cypress/e2e/core/firewalls/landing-page-empty-state.spec.ts new file mode 100644 index 00000000000..b95dd0b6452 --- /dev/null +++ b/packages/manager/cypress/e2e/core/firewalls/landing-page-empty-state.spec.ts @@ -0,0 +1,32 @@ +import { ui } from 'support/ui'; +import { mockGetFirewalls } from 'support/intercepts/firewalls'; + +describe('confirms Firewalls landing page empty state is shown when no Firewalls exist', () => { + /* + * - Confirms that Getting Started Guides is listed on landing page. + * - Confirms that Video Playlist is listed on landing page. + * - Confirms that clicking on Create Firewall button navigates user to firewall create page. + */ + it('shows the empty state when no Firewalls exist', () => { + mockGetFirewalls([]).as('getFirewalls'); + + cy.visitWithLogin('/firewalls'); + cy.wait(['@getFirewalls']); + + cy.findByText('Secure cloud-based firewall').should('be.visible'); + cy.findByText( + 'Control network traffic to and from Linode Compute Instances with a simple management interface' + ).should('be.visible'); + cy.findByText('Getting Started Guides').should('be.visible'); + cy.findByText('Video Playlist').should('be.visible'); + + // Create Firewall button exists and clicking it navigates user to create firewall page. + ui.button + .findByTitle('Create Firewall') + .should('be.visible') + .should('be.enabled') + .click(); + + cy.url().should('endWith', '/firewalls/create'); + }); +}); diff --git a/packages/manager/cypress/e2e/core/linodes/switch-linode-state.spec.ts b/packages/manager/cypress/e2e/core/linodes/switch-linode-state.spec.ts new file mode 100644 index 00000000000..1b0a7317ebb --- /dev/null +++ b/packages/manager/cypress/e2e/core/linodes/switch-linode-state.spec.ts @@ -0,0 +1,187 @@ +import { createLinode } from 'support/api/linodes'; +import { containsVisible, fbtVisible, fbltVisible } from 'support/helpers'; +import { apiMatcher } from 'support/util/intercepts'; +import { ui } from 'support/ui'; +import { cleanUp } from 'support/util/cleanup'; +import { authenticate } from 'support/api/authentication'; + +authenticate(); +describe('switch linode state', () => { + beforeEach(() => { + cleanUp(['linodes']); + }); + + it('powers off a linode from landing page', () => { + createLinode().then((linode) => { + cy.visitWithLogin('/linodes'); + cy.get(`[data-qa-linode="${linode.label}"]`) + .should('be.visible') + .within(() => { + containsVisible('Running'); + }); + + ui.actionMenu + .findByTitle(`Action menu for Linode ${linode.label}`) + .should('be.visible') + .click(); + + ui.actionMenuItem.findByTitle('Power Off').should('be.visible').click(); + + ui.dialog + .findByTitle(`Power Off Linode ${linode.label}?`) + .should('be.visible') + .within(() => { + ui.button + .findByTitle('Power Off Linode') + .should('be.visible') + .should('be.enabled') + .click(); + }); + + cy.get(`[data-qa-linode="${linode.label}"]`) + .should('be.visible') + .within(() => { + containsVisible('Shutting Down'); + cy.contains('Offline', { timeout: 300000 }).should('be.visible'); + }); + }); + }); + + it('powers off a linode from details page', () => { + createLinode().then((linode) => { + cy.visitWithLogin(`/linodes/${linode.id}`); + containsVisible('RUNNING'); + fbtVisible(linode.label); + + cy.findByText('Power Off').should('be.visible').click(); + ui.dialog + .findByTitle(`Power Off Linode ${linode.label}?`) + .should('be.visible') + .within(() => { + ui.button + .findByTitle('Power Off Linode') + .should('be.visible') + .should('be.enabled') + .click(); + }); + containsVisible('SHUTTING DOWN'); + cy.contains('OFFLINE', { timeout: 300000 }).should('be.visible'); + }); + }); + + it('powers on a linode from landing page', () => { + createLinode({ booted: false }).then((linode) => { + cy.visitWithLogin('/linodes'); + cy.get(`[data-qa-linode="${linode.label}"]`) + .should('be.visible') + .within(() => { + containsVisible('Offline'); + }); + + ui.actionMenu + .findByTitle(`Action menu for Linode ${linode.label}`) + .should('be.visible') + .click(); + + ui.actionMenuItem.findByTitle('Power On').should('be.visible').click(); + + ui.dialog + .findByTitle(`Power On Linode ${linode.label}?`) + .should('be.visible') + .within(() => { + ui.button + .findByTitle('Power On Linode') + .should('be.visible') + .should('be.enabled') + .click(); + }); + + cy.get(`[data-qa-linode="${linode.label}"]`) + .should('be.visible') + .within(() => { + containsVisible('Booting'); + cy.contains('Running', { timeout: 300000 }).should('be.visible'); + }); + }); + }); + + it('powers on a linode from details page', () => { + createLinode({ booted: false }).then((linode) => { + cy.visitWithLogin(`/linodes/${linode.id}`); + containsVisible('OFFLINE'); + fbtVisible(linode.label); + + cy.findByText('Power On').should('be.visible').click(); + ui.dialog + .findByTitle(`Power On Linode ${linode.label}?`) + .should('be.visible') + .within(() => { + ui.button + .findByTitle('Power On Linode') + .should('be.visible') + .should('be.enabled') + .click(); + }); + containsVisible('BOOTING'); + cy.contains('RUNNING', { timeout: 300000 }).should('be.visible'); + }); + }); + + it('reboots a linode from landing page', () => { + createLinode().then((linode) => { + cy.visitWithLogin('/linodes'); + cy.get(`[data-qa-linode="${linode.label}"]`) + .should('be.visible') + .within(() => { + containsVisible('Running'); + }); + + ui.actionMenu + .findByTitle(`Action menu for Linode ${linode.label}`) + .should('be.visible') + .click(); + + ui.actionMenuItem.findByTitle('Reboot').should('be.visible').click(); + + ui.dialog + .findByTitle(`Reboot Linode ${linode.label}?`) + .should('be.visible') + .within(() => { + ui.button + .findByTitle('Reboot Linode') + .should('be.visible') + .should('be.enabled') + .click(); + }); + + cy.get(`[data-qa-linode="${linode.label}"]`) + .should('be.visible') + .within(() => { + containsVisible('Rebooting'); + cy.contains('Running', { timeout: 300000 }).should('be.visible'); + }); + }); + }); + + it('reboots a linode from details page', () => { + createLinode().then((linode) => { + cy.visitWithLogin(`/linodes/${linode.id}`); + containsVisible('RUNNING'); + fbtVisible(linode.label); + + cy.findByText('Reboot').should('be.visible').click(); + ui.dialog + .findByTitle(`Reboot Linode ${linode.label}?`) + .should('be.visible') + .within(() => { + ui.button + .findByTitle('Reboot Linode') + .should('be.visible') + .should('be.enabled') + .click(); + }); + containsVisible('REBOOTING'); + cy.contains('RUNNING', { timeout: 300000 }).should('be.visible'); + }); + }); +}); diff --git a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-configurations.spec.ts b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-configurations.spec.ts index 588c9c27e17..961e0599991 100644 --- a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-configurations.spec.ts +++ b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-configurations.spec.ts @@ -112,7 +112,9 @@ describe('Akamai Global Load Balancer configurations page', () => { ui.drawer.findByTitle('Add Route').within(() => { cy.findByLabelText('Route').click(); - ui.autocompletePopper.findByTitle(routes[0].label).click(); + ui.autocompletePopper + .findByTitle(routes[0].label, { exact: false }) + .click(); ui.buttonGroup .findButtonByTitle('Add Route') @@ -180,7 +182,9 @@ describe('Akamai Global Load Balancer configurations page', () => { ui.drawer.findByTitle('Add Route').within(() => { cy.findByLabelText('Route').click(); - ui.autocompletePopper.findByTitle(routes[0].label).click(); + ui.autocompletePopper + .findByTitle(routes[0].label, { exact: false }) + .click(); ui.buttonGroup .findButtonByTitle('Add Route') @@ -248,7 +252,9 @@ describe('Akamai Global Load Balancer configurations page', () => { ui.drawer.findByTitle('Add Route').within(() => { cy.findByLabelText('Route').click(); - ui.autocompletePopper.findByTitle(routes[0].label).click(); + ui.autocompletePopper + .findByTitle(routes[0].label, { exact: false }) + .click(); ui.buttonGroup .findButtonByTitle('Add Route') @@ -333,7 +339,9 @@ describe('Akamai Global Load Balancer configurations page', () => { ui.drawer.findByTitle('Add Route').within(() => { cy.findByLabelText('Route').click(); - ui.autocompletePopper.findByTitle(routes[0].label).click(); + ui.autocompletePopper + .findByTitle(routes[0].label, { exact: false }) + .click(); ui.buttonGroup .findButtonByTitle('Add Route') diff --git a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts index b7be9ae8955..f5d15fe1045 100644 --- a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts +++ b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-landing-page.spec.ts @@ -13,6 +13,8 @@ import { randomLabel } from 'support/util/random'; import { mockGetLoadBalancer, mockGetLoadBalancers, + mockDeleteLoadBalancerError, + mockDeleteLoadBalancer, } from 'support/intercepts/load-balancers'; import type { Loadbalancer } from '@linode/api-v4'; import { chooseRegion } from 'support/util/regions'; @@ -127,3 +129,153 @@ describe('Akamai Global Load Balancer landing page', () => { }); }); }); + +describe('Delete', () => { + /* + * - Confirms that Deleting a load balancer from the AGLB landing page. + * - Confirms AGLB landing page reverts to its empty state when all of the load balancers have been deleted. + */ + it('Delete a Load Balancer from landing page.', () => { + const chosenRegion = chooseRegion(); + const loadBalancerConfiguration = configurationFactory.build(); + const loadbalancerMocks = [ + loadbalancerFactory.build({ + id: 1, + label: randomLabel(), + configurations: [ + { + id: loadBalancerConfiguration.id, + label: loadBalancerConfiguration.label, + }, + ], + regions: ['us-east', chosenRegion.id], + }), + ]; + + // TODO Delete feature flag mocks when AGLB feature flag goes away. + mockAppendFeatureFlags({ + aglb: makeFeatureFlagData(true), + }).as('getFeatureFlags'); + mockGetFeatureFlagClientstream().as('getClientStream'); + mockGetLoadBalancers(loadbalancerMocks).as('getLoadBalancers'); + mockGetLoadBalancer(loadbalancerMocks[0]); + + const loadbalancer = loadbalancerMocks[0]; + + cy.visitWithLogin('/loadbalancers'); + cy.wait(['@getFeatureFlags', '@getClientStream', '@getLoadBalancers']); + + ui.actionMenu + .findByTitle(`Action menu for Load Balancer ${loadbalancer.label}`) + .should('be.visible') + .click(); + + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); + + // Mock the API call for deleting the load balancer. + mockDeleteLoadBalancer(loadbalancer.id).as('deleteLoadBalancer'); + + mockGetLoadBalancers([]).as('getLoadBalancers'); + + // Handle the delete confirmation dialog. + ui.dialog + .findByTitle(`Delete ${loadbalancer.label}?`) + .should('be.visible') + .within(() => { + cy.findByLabelText('Load Balancer Label') + .should('be.visible') + .click() + .type(loadbalancer.label); + + ui.buttonGroup + .findButtonByTitle('Delete') + .should('be.visible') + .should('be.enabled') + .click(); + }); + + cy.wait(['@deleteLoadBalancer', '@getLoadBalancers']); + + // Confirm that user is navigated to the empty loadbalancer empty state landing page. + + cy.get('[data-qa-header]') + .should('be.visible') + .should('have.text', 'Global Load Balancers'); + + cy.findByText( + 'Scalable Layer 4 and Layer 7 load balancer to route and manage enterprise traffic between clients and your distributed applications and networks globally.' + ).should('be.visible'); + cy.findByText('Getting Started Guides').should('be.visible'); + + // Create button exists and navigates user to create page. + ui.button + .findByTitle('Create Global Load Balancer') + .should('be.visible') + .should('be.enabled'); + + cy.findByText(loadbalancer.label).should('not.exist'); + }); + + it('Shows API errors when deleting a load balancer', () => { + const chosenRegion = chooseRegion(); + const loadBalancerConfiguration = configurationFactory.build(); + const loadbalancerMocks = [ + loadbalancerFactory.build({ + id: 1, + label: randomLabel(), + configurations: [ + { + id: loadBalancerConfiguration.id, + label: loadBalancerConfiguration.label, + }, + ], + regions: ['us-east', chosenRegion.id], + }), + ]; + + // TODO Delete feature flag mocks when AGLB feature flag goes away. + mockAppendFeatureFlags({ + aglb: makeFeatureFlagData(true), + }).as('getFeatureFlags'); + mockGetFeatureFlagClientstream().as('getClientStream'); + mockGetLoadBalancers(loadbalancerMocks).as('getLoadBalancers'); + mockGetLoadBalancer(loadbalancerMocks[0]); + + const loadbalancer = loadbalancerMocks[0]; + + cy.visitWithLogin('/loadbalancers'); + cy.wait(['@getFeatureFlags', '@getClientStream', '@getLoadBalancers']); + + ui.actionMenu + .findByTitle(`Action menu for Load Balancer ${loadbalancer.label}`) + .should('be.visible') + .click(); + + ui.actionMenuItem.findByTitle('Delete').should('be.visible').click(); + // Mock the API call for deleting the load balancer. + mockDeleteLoadBalancerError(loadbalancer.id, 'Control Plane Error').as( + 'deleteLoadBalancer' + ); + + mockGetLoadBalancers([]).as('getLoadBalancers'); + + // Handle the delete confirmation dialog. + ui.dialog + .findByTitle(`Delete ${loadbalancer.label}?`) + .should('be.visible') + .within(() => { + cy.findByLabelText('Load Balancer Label') + .should('be.visible') + .click() + .type(loadbalancer.label); + + ui.buttonGroup.findButtonByTitle('Delete').click(); + + cy.wait(['@deleteLoadBalancer']); + + cy.findByText('Control Plane Error').should('be.visible'); + + ui.buttonGroup.findButtonByTitle('Cancel').click(); + }); + }); +}); diff --git a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts index 890c89f7066..37465adf226 100644 --- a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts +++ b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-routes.spec.ts @@ -229,7 +229,7 @@ describe('Akamai Global Load Balancer routes page', () => { cy.wait('@getServiceTargets'); ui.autocompletePopper - .findByTitle(serviceTargets[0].label) + .findByTitle(serviceTargets[0].label, { exact: false }) .should('be.visible') .click(); @@ -250,7 +250,7 @@ describe('Akamai Global Load Balancer routes page', () => { cy.wait('@getServiceTargets'); ui.autocompletePopper - .findByTitle(serviceTargets[1].label) + .findByTitle(serviceTargets[1].label, { exact: false }) .should('be.visible') .click(); @@ -327,7 +327,7 @@ describe('Akamai Global Load Balancer routes page', () => { cy.wait('@getServiceTargets'); ui.autocompletePopper - .findByTitle(serviceTargets[0].label) + .findByTitle(serviceTargets[0].label, { exact: false }) .should('be.visible') .click(); @@ -348,7 +348,7 @@ describe('Akamai Global Load Balancer routes page', () => { cy.wait('@getServiceTargets'); ui.autocompletePopper - .findByTitle(serviceTargets[1].label) + .findByTitle(serviceTargets[1].label, { exact: false }) .should('be.visible') .click(); @@ -408,7 +408,7 @@ describe('Akamai Global Load Balancer routes page', () => { cy.wait('@getServiceTargets'); ui.autocompletePopper - .findByTitle(serviceTargets[0].label) + .findByTitle(serviceTargets[0].label, { exact: false }) .should('be.visible') .click(); @@ -479,7 +479,7 @@ describe('Akamai Global Load Balancer routes page', () => { cy.wait('@getServiceTargets'); ui.autocompletePopper - .findByTitle(serviceTargets[0].label) + .findByTitle(serviceTargets[0].label, { exact: false }) .should('be.visible') .click(); diff --git a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-summary.spec.ts b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-summary.spec.ts index 8a59b03a063..f7709968e77 100644 --- a/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-summary.spec.ts +++ b/packages/manager/cypress/e2e/core/loadBalancers/load-balancer-summary.spec.ts @@ -2,12 +2,19 @@ * @file Integration tests for Akamai Global Load Balancer summary page. */ -import { loadbalancerFactory } from '@src/factories/aglb'; +import { loadbalancerFactory, configurationFactory } from '@src/factories/aglb'; import { mockAppendFeatureFlags, mockGetFeatureFlagClientstream, } from 'support/intercepts/feature-flags'; -import { mockGetLoadBalancer } from 'support/intercepts/load-balancers'; + +import { + mockGetLoadBalancer, + mockGetLoadBalancers, + mockDeleteLoadBalancer, +} from 'support/intercepts/load-balancers'; +import { randomLabel } from 'support/util/random'; +import { ui } from 'support/ui'; import { makeFeatureFlagData } from 'support/util/feature-flags'; describe('Akamai Global Load Balancer details page', () => { @@ -41,3 +48,93 @@ describe('Akamai Global Load Balancer details page', () => { cy.findByText(mockLoadBalancer.hostname).should('be.visible'); }); }); + +describe('Delete', () => { + /* + * Deleting a load balancer from the AGLB load balancer details page "Settings" tab (route: /loadbalancers/:id/settings) + * Confirms User is redirected to AGLB landing page upon deleting from Load Balancer details page "Settings" tab, and load balancer is not listed on the landing page. + */ + + // Test case for deleting a load balancer from the Settings tab. + it('Deletes a loadbalancer from Settings tab', () => { + const mockLoadBalancer = loadbalancerFactory.build(); + // Setup additional mock load balancer data. + const loadBalancerConfiguration = configurationFactory.build(); + const loadbalancerMocks = [ + loadbalancerFactory.build({ + id: 1, + label: randomLabel(), + configurations: [ + { + id: loadBalancerConfiguration.id, + label: loadBalancerConfiguration.label, + }, + ], + regions: ['us-east'], + }), + ]; + const loadbalancerMock = loadbalancerMocks[0]; + + mockGetLoadBalancers(loadbalancerMocks).as('getLoadBalancers'); + + mockAppendFeatureFlags({ + aglb: makeFeatureFlagData(true), + }).as('getFeatureFlags'); + + mockGetFeatureFlagClientstream().as('getClientStream'); + mockGetLoadBalancer(mockLoadBalancer).as('getLoadBalancer'); + + // Visit the specific load balancer's page with login. + cy.visitWithLogin(`/loadbalancers/${mockLoadBalancer.id}`); + + // Wait for all the mock API calls to complete. + cy.wait(['@getFeatureFlags', '@getClientStream', '@getLoadBalancer']); + + // Navigate to the 'Settings' tab. + cy.findByText('Settings').should('be.visible').click(); + + cy.findByText(mockLoadBalancer.label).should('be.visible'); + + cy.findByText('Delete Load Balancer').should('be.visible'); + + // Mock the API call for deleting the load balancer. + mockDeleteLoadBalancer(mockLoadBalancer.id).as('deleteLoadBalancer'); + + ui.button.findByTitle('Delete').should('be.visible').click(); + + // Handle the delete confirmation dialog. + ui.dialog + .findByTitle(`Delete ${mockLoadBalancer.label}?`) + .should('be.visible') + .within(() => { + cy.findByTestId('textfield-input') + .should('be.visible') + .click() + .type(mockLoadBalancer.label); + + ui.buttonGroup + .findButtonByTitle('Delete') + .should('be.visible') + .should('be.enabled') + .click(); + }); + + // Wait for the delete operation and subsequent data retrieval to complete. + cy.wait(['@deleteLoadBalancer', '@getLoadBalancers']); + + // Confirm user is navigated to the load balancers landing page list. + cy.findByText(loadbalancerMock.label) + .should('be.visible') + .closest('tr') + .within(() => { + ui.actionMenu + .findByTitle( + `Action menu for Load Balancer ${loadbalancerMock.label}` + ) + .should('be.visible'); + }); + + // Verify that the deleted load balancer no longer exists in the list. + cy.findByText(mockLoadBalancer.label).should('not.exist'); + }); +}); diff --git a/packages/manager/cypress/e2e/core/objectStorage/object-storage.e2e.spec.ts b/packages/manager/cypress/e2e/core/objectStorage/object-storage.e2e.spec.ts index 99e656b06f2..88d2b0c1e16 100644 --- a/packages/manager/cypress/e2e/core/objectStorage/object-storage.e2e.spec.ts +++ b/packages/manager/cypress/e2e/core/objectStorage/object-storage.e2e.spec.ts @@ -15,6 +15,11 @@ import { import { ui } from 'support/ui'; import { randomLabel } from 'support/util/random'; import { cleanUp } from 'support/util/cleanup'; +import { + mockAppendFeatureFlags, + mockGetFeatureFlagClientstream, +} from 'support/intercepts/feature-flags'; +import { makeFeatureFlagData } from 'support/util/feature-flags'; // Message shown on-screen when user navigates to an empty bucket. const emptyBucketMessage = 'This bucket is empty.'; @@ -116,8 +121,13 @@ describe('object storage end-to-end tests', () => { interceptCreateBucket().as('createBucket'); interceptDeleteBucket(bucketLabel, bucketCluster).as('deleteBucket'); + mockAppendFeatureFlags({ + objMultiCluster: makeFeatureFlagData(false), + }).as('getFeatureFlags'); + mockGetFeatureFlagClientstream().as('getClientStream'); + cy.visitWithLogin('/object-storage'); - cy.wait('@getBuckets'); + cy.wait(['@getFeatureFlags', '@getBuckets']); ui.button.findByTitle('Create Bucket').should('be.visible').click(); diff --git a/packages/manager/cypress/e2e/core/volumes/landing-page-empty-state.spec.ts b/packages/manager/cypress/e2e/core/volumes/landing-page-empty-state.spec.ts new file mode 100644 index 00000000000..1d254586082 --- /dev/null +++ b/packages/manager/cypress/e2e/core/volumes/landing-page-empty-state.spec.ts @@ -0,0 +1,29 @@ +import { ui } from 'support/ui'; +import { mockGetVolumes } from 'support/intercepts/volumes'; + +describe('confirms Volumes landing page empty state is shown when no Volumes exist', () => { + /* + * - Confirms that Getting Started Guides is listed on landing page. + * - Confirms that Video Playlist is listed on landing page. + * - Confirms that clicking on Create Volume button navigates user to volume create page. + */ + it('shows the empty state when no Volumes exist', () => { + mockGetVolumes([]).as('getVolumes'); + + cy.visitWithLogin('/volumes'); + cy.wait(['@getVolumes']); + + cy.findByText('NVMe block storage service').should('be.visible'); + cy.findByText('Getting Started Guides').should('be.visible'); + cy.findByText('Video Playlist').should('be.visible'); + + // Create Volume button exists and clicking it navigates user to create volume page. + ui.button + .findByTitle('Create Volume') + .should('be.visible') + .should('be.enabled') + .click(); + + cy.url().should('endWith', '/volumes/create'); + }); +}); diff --git a/packages/manager/cypress/support/constants/user-permissions.ts b/packages/manager/cypress/support/constants/user-permissions.ts new file mode 100644 index 00000000000..d6ca785951d --- /dev/null +++ b/packages/manager/cypress/support/constants/user-permissions.ts @@ -0,0 +1,58 @@ +import { randomLabel } from 'support/util/random'; +import { grantFactory, grantsFactory } from 'src/factories/grants'; +import type { Grants } from '@linode/api-v4'; + +/** + * User permission grants with all permissions restricted. + */ +export const userPermissionsGrants: Grants = grantsFactory.build({ + global: { + account_access: null, + cancel_account: false, + child_account_access: false, + add_domains: false, + add_firewalls: false, + add_images: false, + add_linodes: false, + add_longview: false, + add_nodebalancers: false, + add_stackscripts: false, + add_volumes: false, + add_vpcs: false, + longview_subscription: false, + }, + database: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + domain: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + firewall: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + image: grantFactory.buildList(1, { label: randomLabel(), permissions: null }), + linode: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + longview: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + nodebalancer: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + stackscript: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + volume: grantFactory.buildList(1, { + label: randomLabel(), + permissions: null, + }), + vpc: grantFactory.buildList(1, { label: randomLabel(), permissions: null }), +}); diff --git a/packages/manager/cypress/support/intercepts/account.ts b/packages/manager/cypress/support/intercepts/account.ts index 552a7bcd9f4..d88ebb44732 100644 --- a/packages/manager/cypress/support/intercepts/account.ts +++ b/packages/manager/cypress/support/intercepts/account.ts @@ -18,6 +18,7 @@ import type { Payment, PaymentMethod, User, + Grants, } from '@linode/api-v4'; /** @@ -48,6 +49,21 @@ export const mockUpdateAccount = ( ); }; +/** + * Intercepts GET request to fetch account users and mocks response. + * + * @param users - User objects with which to mock response. + * + * @returns Cypress chainable. + */ +export const mockGetUsers = (users: User[]): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher('account/users*'), + paginateResponse(users) + ); +}; + /** * Intercepts GET request to fetch account user information. * @@ -59,6 +75,77 @@ export const interceptGetUser = (username: string): Cypress.Chainable => { return cy.intercept('GET', apiMatcher(`account/users/${username}`)); }; +/** + * Intercepts GET request to fetch account user information and mocks response. + * + * @param username - Username of user whose info is being fetched. + * + * @returns Cypress chainable. + */ +export const mockGetUser = (user: User): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher(`account/users/${user.username}`), + makeResponse(user) + ); +}; + +/** + * Intercepts PUT request to update account user information and mocks response. + * + * @param username - Username of user to update. + * @param updatedUser - Updated user account info with which to mock response. + * + * @returns Cypress chainable. + */ +export const mockUpdateUser = ( + username: string, + updatedUser: User +): Cypress.Chainable => { + return cy.intercept( + 'PUT', + apiMatcher(`account/users/${username}`), + makeResponse(updatedUser) + ); +}; + +/** + * Intercepts GET request to fetch account user grants and mocks response. + * + * @param username - Username of user for which to fetch grants. + * + * @returns Cypress chainable. + */ +export const mockGetUserGrants = ( + username: string, + grants: Grants +): Cypress.Chainable => { + return cy.intercept( + 'GET', + apiMatcher(`account/users/${username}/grants`), + makeResponse(grants) + ); +}; + +/** + * Intercepts PUT request to update account user grants and mocks response. + * + * @param username - Username of user for which to update grants. + * @param grants - Updated grants with which to mock response. + * + * @returns Cypress chainable. + */ +export const mockUpdateUserGrants = ( + username: string, + grants: Grants +): Cypress.Chainable => { + return cy.intercept( + 'PUT', + apiMatcher(`account/users/${username}/grants`), + makeResponse(grants) + ); +}; + /** * Intercepts POST request to generate entity transfer token. * diff --git a/packages/manager/cypress/support/intercepts/load-balancers.ts b/packages/manager/cypress/support/intercepts/load-balancers.ts index ff7ed60fbe2..3d6bac9a2b1 100644 --- a/packages/manager/cypress/support/intercepts/load-balancers.ts +++ b/packages/manager/cypress/support/intercepts/load-balancers.ts @@ -42,6 +42,37 @@ export const mockGetLoadBalancers = (loadBalancers: Loadbalancer[]) => { ); }; +/** + * Intercepts DELETE requests to delete an AGLB load balancer. + * + * @param loadBalancerId - ID of load balancer for which to delete. + * + * @returns Cypress chainable. + */ +export const mockDeleteLoadBalancer = (loadBalancerId: number) => { + return cy.intercept('DELETE', apiMatcher(`/aglb/${loadBalancerId}`), {}); +}; + +/** + * Intercepts DELETE requests to delete an AGLB load balancer and mocks HTTP 500 error response. + * + * @param loadBalancerId - ID of load balancer for which to delete. + * @param message - Optional error message with which to respond. + * + * @returns Cypress chainable. + */ +export const mockDeleteLoadBalancerError = ( + loadBalancerId: number, + message?: string +) => { + const defaultMessage = 'An error occurred while deleting Load Balancer.'; + return cy.intercept( + 'DELETE', + apiMatcher(`/aglb/${loadBalancerId}`), + makeErrorResponse(message ?? defaultMessage, 500) + ); +}; + /** * Intercepts GET requests to retrieve AGLB load balancer configurations and mocks response. * diff --git a/packages/manager/cypress/support/plugins/configure-api.ts b/packages/manager/cypress/support/plugins/configure-api.ts index e8548892857..16d9c13c915 100644 --- a/packages/manager/cypress/support/plugins/configure-api.ts +++ b/packages/manager/cypress/support/plugins/configure-api.ts @@ -1,6 +1,7 @@ -import { CypressPlugin } from './plugin'; +import { Profile, getProfile } from '@linode/api-v4'; + import { configureLinodeApi, defaultApiRoot } from '../util/api'; -import { getProfile, Profile } from '@linode/api-v4'; +import { CypressPlugin } from './plugin'; /** * Configures API requests to use configure access token and API root. diff --git a/packages/manager/cypress/support/plugins/discard-passed-test-recordings.ts b/packages/manager/cypress/support/plugins/discard-passed-test-recordings.ts index 4eb2d3aeb14..eca3bca5c2b 100644 --- a/packages/manager/cypress/support/plugins/discard-passed-test-recordings.ts +++ b/packages/manager/cypress/support/plugins/discard-passed-test-recordings.ts @@ -1,7 +1,7 @@ -import { CypressPlugin } from './plugin'; +// @ts-expect-error for some reason, @node/types is v12 and it probably doesn't have this. +import fs from 'fs/promises'; -// Dependencies used in hooks have to use `require()` syntax. -const fs = require('fs/promises'); // eslint-disable-line +import { CypressPlugin } from './plugin'; /** * Delete recordings for any specs that passed without requiring any diff --git a/packages/manager/cypress/support/plugins/load-env-config.ts b/packages/manager/cypress/support/plugins/load-env-config.ts index c7ad9cbee88..3d29a1f2ebb 100644 --- a/packages/manager/cypress/support/plugins/load-env-config.ts +++ b/packages/manager/cypress/support/plugins/load-env-config.ts @@ -1,5 +1,6 @@ import * as dotenv from 'dotenv'; import { resolve } from 'path'; +import { fileURLToPath } from 'url'; import { CypressPlugin } from './plugin'; @@ -14,7 +15,14 @@ export const loadEnvironmentConfig: CypressPlugin = ( _on, config ): Cypress.PluginConfigOptions => { - const dotenvPath = resolve(__dirname, '..', '..', '..', '.env'); + const dotenvPath = resolve( + fileURLToPath(import.meta.url), + '..', + '..', + '..', + '..', + '.env' + ); const conf = dotenv.config({ path: dotenvPath, }); diff --git a/packages/manager/cypress/support/plugins/vite-preprocessor.ts b/packages/manager/cypress/support/plugins/vite-preprocessor.ts index af95f959637..1a0115f81ec 100644 --- a/packages/manager/cypress/support/plugins/vite-preprocessor.ts +++ b/packages/manager/cypress/support/plugins/vite-preprocessor.ts @@ -1,12 +1,20 @@ -import { CypressPlugin } from './plugin'; +import vitePreprocessor from 'cypress-vite'; +import { resolve } from 'path'; +import { fileURLToPath } from 'url'; -// Dependencies used in hooks have to use `require()` syntax. -const path = require('path'); // eslint-disable-line -const vitePreprocessor = require('cypress-vite'); // eslint-disable-line +import { CypressPlugin } from './plugin'; export const vitePreprocess: CypressPlugin = (on, _config): void => { on( 'file:preprocessor', - vitePreprocessor(path.resolve(__dirname, '..', '..', 'vite.config.ts')) + vitePreprocessor( + resolve( + fileURLToPath(import.meta.url), + '..', + '..', + '..', + 'vite.config.ts' + ) + ) ); }; diff --git a/packages/manager/cypress/support/ui/autocomplete.ts b/packages/manager/cypress/support/ui/autocomplete.ts index f96bb9cc7e3..94e391232b1 100644 --- a/packages/manager/cypress/support/ui/autocomplete.ts +++ b/packages/manager/cypress/support/ui/autocomplete.ts @@ -1,5 +1,7 @@ import { getRegionById, getRegionByLabel } from 'support/util/regions'; +import type { SelectorMatcherOptions } from '@testing-library/cypress'; + export const autocomplete = { /** * Finds a autocomplete popper that has the given title. @@ -19,12 +21,15 @@ export const autocompletePopper = { /** * Finds a autocomplete popper that has the given title. */ - findByTitle: (title: string): Cypress.Chainable => { + findByTitle: ( + title: string, + options?: SelectorMatcherOptions + ): Cypress.Chainable => { return cy .document() .its('body') .find('[data-qa-autocomplete-popper]') - .findByText(title); + .findByText(title, options); }, }; diff --git a/packages/manager/cypress/support/util/arrays.ts b/packages/manager/cypress/support/util/arrays.ts index 86a1899ba70..74ce77cdf9f 100644 --- a/packages/manager/cypress/support/util/arrays.ts +++ b/packages/manager/cypress/support/util/arrays.ts @@ -18,3 +18,17 @@ export const buildArray = ( .fill(null) .map((_item: null, i: number) => builder(i)); }; + +/** + * Returns a copy of an array with its items sorted randomly. + * + * @param unsortedArray - Array to shuffle. + * + * @returns Copy of `unsortedArray` with its items sorted randomly. + */ +export const shuffleArray = (unsortedArray: T[]): T[] => { + return unsortedArray + .map((value: T) => ({ value, sort: Math.random() })) + .sort((a, b) => a.sort - b.sort) + .map(({ value }) => value); +}; diff --git a/packages/manager/cypress/tsconfig.json b/packages/manager/cypress/tsconfig.json index cd349ce3c3b..e84f29358ae 100644 --- a/packages/manager/cypress/tsconfig.json +++ b/packages/manager/cypress/tsconfig.json @@ -7,6 +7,7 @@ "noImplicitAny": false, "target": "es6", "moduleResolution": "node", + "module": "esnext", "lib": ["es6", "dom"], "baseUrl": "..", "jsx": "react", diff --git a/packages/manager/package.json b/packages/manager/package.json index 92694758152..92c0eb300db 100644 --- a/packages/manager/package.json +++ b/packages/manager/package.json @@ -2,8 +2,9 @@ "name": "linode-manager", "author": "Linode", "description": "The Linode Manager website", - "version": "1.108.0", + "version": "1.109.0", "private": true, + "type": "module", "bugs": { "url": "https://github.com/Linode/manager/issues" }, @@ -19,7 +20,6 @@ "@linode/validation": "*", "@mui/icons-material": "^5.14.7", "@mui/material": "^5.14.7", - "@mui/styles": "^5.14.7", "@paypal/react-paypal-js": "^7.8.3", "@reach/tabs": "^0.10.5", "@sentry/react": "^7.57.0", @@ -111,16 +111,17 @@ }, "devDependencies": { "@linode/eslint-plugin-cloud-manager": "^0.0.3", - "@storybook/addon-actions": "~7.5.2", - "@storybook/addon-controls": "~7.5.2", - "@storybook/addon-docs": "~7.5.2", - "@storybook/addon-measure": "~7.5.2", - "@storybook/addon-viewport": "~7.5.2", - "@storybook/addons": "~7.5.2", - "@storybook/client-api": "~7.5.2", - "@storybook/react": "~7.5.2", - "@storybook/react-vite": "^7.5.2", - "@storybook/theming": "~7.5.2", + "@storybook/addon-actions": "~7.6.4", + "@storybook/addon-controls": "~7.6.4", + "@storybook/addon-docs": "~7.6.4", + "@storybook/addon-measure": "~7.6.4", + "@storybook/addon-storysource": "^7.6.4", + "@storybook/addon-viewport": "~7.6.4", + "@storybook/addons": "~7.6.4", + "@storybook/client-api": "~7.6.4", + "@storybook/react": "~7.6.4", + "@storybook/react-vite": "^7.6.4", + "@storybook/theming": "~7.6.4", "@swc/core": "^1.3.1", "@testing-library/cypress": "^10.0.0", "@testing-library/jest-dom": "~5.11.3", @@ -163,9 +164,9 @@ "@types/zxcvbn": "^4.4.0", "@typescript-eslint/eslint-plugin": "^4.1.1", "@typescript-eslint/parser": "^4.1.1", - "@vitejs/plugin-react-swc": "^3.4.0", - "@vitest/coverage-v8": "^0.34.6", - "@vitest/ui": "^0.34.6", + "@vitejs/plugin-react-swc": "^3.5.0", + "@vitest/coverage-v8": "^1.0.4", + "@vitest/ui": "^1.0.4", "chai-string": "^1.5.0", "chalk": "^5.2.0", "css-mediaquery": "^0.1.2", @@ -173,7 +174,7 @@ "cypress-axe": "^1.0.0", "cypress-file-upload": "^5.0.7", "cypress-real-events": "^1.11.0", - "cypress-vite": "^1.4.2", + "cypress-vite": "^1.5.0", "dotenv": "^16.0.3", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.14.0", @@ -202,11 +203,11 @@ "redux-mock-store": "^1.5.3", "reselect-tools": "^0.0.7", "serve": "^14.0.1", - "storybook": "~7.5.2", - "storybook-dark-mode": "^3.0.1", - "vite": "^4.5.0", + "storybook": "~7.6.4", + "storybook-dark-mode": "^3.0.3", + "vite": "^5.0.7", "vite-plugin-svgr": "^3.2.0", - "vitest": "^0.34.6" + "vitest": "^1.0.4" }, "browserslist": [ ">1%", diff --git a/packages/manager/src/App.test.tsx b/packages/manager/src/App.test.tsx deleted file mode 100644 index d9410cf2872..00000000000 --- a/packages/manager/src/App.test.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { shallow } from 'enzyme'; -import * as React from 'react'; -import { Provider } from 'react-redux'; -import { StaticRouter } from 'react-router-dom'; - -import { App } from './App'; -import { LinodeThemeWrapper } from './LinodeThemeWrapper'; -import { queryClientFactory } from './queries/base'; -import { storeFactory } from './store'; - -const store = storeFactory(queryClientFactory()); - -it('renders without crashing.', () => { - const component = shallow( - - - - - - - - ); - expect(component.find('App')).toHaveLength(1); -}); diff --git a/packages/manager/src/GoTo.tsx b/packages/manager/src/GoTo.tsx index 32af40cb471..c0189b2a0bb 100644 --- a/packages/manager/src/GoTo.tsx +++ b/packages/manager/src/GoTo.tsx @@ -1,6 +1,6 @@ import Dialog from '@mui/material/Dialog'; import { Theme } from '@mui/material/styles'; -import { makeStyles } from '@mui/styles'; +import { makeStyles } from 'tss-react/mui'; import * as React from 'react'; import { useHistory } from 'react-router-dom'; @@ -9,7 +9,7 @@ import EnhancedSelect, { Item } from 'src/components/EnhancedSelect/Select'; import { useAccountManagement } from './hooks/useAccountManagement'; import { useFlags } from './hooks/useFlags'; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles()((theme: Theme) => ({ input: { width: '100%', }, @@ -59,7 +59,7 @@ interface Props { } export const GoTo = React.memo((props: Props) => { - const classes = useStyles(); + const { classes } = useStyles(); const routerHistory = useHistory(); const { _hasAccountAccess, _isManagedAccount } = useAccountManagement(); const flags = useFlags(); diff --git a/packages/manager/src/LinodeThemeWrapper.tsx b/packages/manager/src/LinodeThemeWrapper.tsx index 0164cee437d..74e5d054aec 100644 --- a/packages/manager/src/LinodeThemeWrapper.tsx +++ b/packages/manager/src/LinodeThemeWrapper.tsx @@ -1,15 +1,9 @@ -import { Theme, ThemeProvider } from '@mui/material/styles'; -import { StyledEngineProvider } from '@mui/material/styles'; +import { StyledEngineProvider, ThemeProvider } from '@mui/material/styles'; import * as React from 'react'; import { ThemeName } from './foundations/themes'; import { themes, useColorMode } from './utilities/theme'; -declare module '@mui/styles/defaultTheme' { - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface DefaultTheme extends Theme {} -} - interface Props { children: React.ReactNode; /** Allows theme to be overwritten. Used for Storybook theme switching */ diff --git a/packages/manager/src/__data__/firewalls.ts b/packages/manager/src/__data__/firewalls.ts index a366da01816..aed2bbdb1eb 100644 --- a/packages/manager/src/__data__/firewalls.ts +++ b/packages/manager/src/__data__/firewalls.ts @@ -1,7 +1,16 @@ import { Firewall } from '@linode/api-v4/lib/firewalls'; +import { FirewallDeviceEntityType } from '@linode/api-v4/lib/firewalls'; export const firewall: Firewall = { created_dt: '2019-09-11T19:44:38.526Z', + entities: [ + { + id: 1, + label: 'my-linode', + type: 'linode' as FirewallDeviceEntityType, + url: '/test', + }, + ], id: 1, label: 'my-firewall', rules: { @@ -33,6 +42,14 @@ export const firewall: Firewall = { export const firewall2: Firewall = { created_dt: '2019-12-11T19:44:38.526Z', + entities: [ + { + id: 1, + label: 'my-linode', + type: 'linode' as FirewallDeviceEntityType, + url: '/test', + }, + ], id: 2, label: 'zzz', rules: { diff --git a/packages/manager/src/cachedData/marketplace.json b/packages/manager/src/cachedData/marketplace.json index 887f107e048..05f9e9284d7 100644 --- a/packages/manager/src/cachedData/marketplace.json +++ b/packages/manager/src/cachedData/marketplace.json @@ -1 +1 @@ -{ "data": [ { "id": 1146319, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MongoDB Cluster Null One-Click", "description": "MongoDB Cluster Null One-Click\r\nNull stackscript for 1067004", "ordinal": 0, "logo_url": "assets/mongodbmarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 38, "deployments_active": 0, "is_public": true, "mine": false, "created": "2023-03-23T14:00:01", "updated": "2023-10-18T12:38:31", "rev_note": "", "script": "#!/bin/bash\n\n# Null", "user_defined_fields": [] }, { "id": 1146324, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Galera Cluster Null One-Click", "description": "Galera Cluster Null One-Click\r\nNull Stackscript for 1088136", "ordinal": 0, "logo_url": "assets/galeramarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 144, "deployments_active": 13, "is_public": true, "mine": false, "created": "2023-03-23T14:19:14", "updated": "2023-12-01T14:51:07", "rev_note": "", "script": "#!/bin/bash", "user_defined_fields": [] }, { "id": 1142293, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Redis Sentinel Cluster Null One-Click", "description": "Redis Sentinel Cluster Null One-Click\r\nNull stackscript for 1132204", "ordinal": 0, "logo_url": "assets/redissentinelmarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 171, "deployments_active": 8, "is_public": true, "mine": false, "created": "2023-03-16T14:20:59", "updated": "2023-11-29T17:28:24", "rev_note": "", "script": "#!/bin/bash", "user_defined_fields": [] }, { "id": 1146322, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "PostgreSQL Cluster Null One-Click", "description": "PostgreSQL Cluster Null One-Click\r\nNull Stackscript for 1068726", "ordinal": 0, "logo_url": "assets/postgresqlmarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 195, "deployments_active": 8, "is_public": true, "mine": false, "created": "2023-03-23T14:17:07", "updated": "2023-12-07T01:47:05", "rev_note": "", "script": "#!/bin/bash\n\n# Null", "user_defined_fields": [] }, { "id": 1226546, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "HashiCorp Nomad Cluster Null One-Click", "description": "Nomad Cluster Null One-Click", "ordinal": 0, "logo_url": "assets/nomadocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 378, "deployments_active": 12, "is_public": true, "mine": false, "created": "2023-08-25T19:08:21", "updated": "2023-11-29T10:42:40", "rev_note": "", "script": "#!/bin/bash/", "user_defined_fields": [] }, { "id": 1226547, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "HashiCorp Nomad Cluster Clients Null One-Click", "description": "Nomad Cluster Clients One-Click", "ordinal": 0, "logo_url": "assets/nomadclientsocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 407, "deployments_active": 18, "is_public": true, "mine": false, "created": "2023-08-25T19:08:57", "updated": "2023-11-29T10:45:14", "rev_note": "", "script": "#!/bin/bash", "user_defined_fields": [] }, { "id": 401697, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "WordPress One-Click", "description": "Wordpress One Click App", "ordinal": 1, "logo_url": "assets/WordPress.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 64828, "deployments_active": 4804, "is_public": true, "mine": false, "created": "2019-03-08T21:04:07", "updated": "2023-12-07T16:47:38", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Wordpress Settings\n#\n#\n\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-wordpress\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n webserver_stack: ${web_stack}\n site_title: ${SITE_TITLE}\n wp_admin_user: ${WP_ADMIN_USER}\n wp_db_user: ${WP_DB_USER}\n wp_db_name: ${WP_DB_NAME}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "webserver_stack", "label": "The stack you are looking to deploy Wordpress on", "oneof": "LAMP,LEMP" }, { "name": "site_title", "label": "Website title", "example": "My Blog" }, { "name": "wp_admin_user", "label": "Admin username", "example": "admin" }, { "name": "wp_db_user", "label": "Wordpress database user", "example": "wordpress" }, { "name": "wp_db_name", "label": "Wordpress database name", "example": "wordpress" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 632758, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Nextcloud One-Click", "description": "One Click App - Nextcloud", "ordinal": 2, "logo_url": "assets/nextcloud.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 19078, "deployments_active": 851, "is_public": true, "mine": false, "created": "2020-02-18T16:40:45", "updated": "2023-12-07T16:46:45", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n\n# Install docker\ncurl -fsSL https://get.docker.com | sudo sh\n\n# Adjust permissions\nsudo mkdir -p /mnt/ncdata\nsudo chown -R 33:0 /mnt/ncdata\n\n# Install Nextcloud\nsudo docker run -d \\\n--init \\\n--name nextcloud-aio-mastercontainer \\\n--restart always \\\n-p 80:80 \\\n-p 8080:8080 \\\n-p 8443:8443 \\\n-e NEXTCLOUD_MOUNT=/mnt/ \\\n-e NEXTCLOUD_DATADIR=/mnt/ncdata \\\n--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \\\n--volume /var/run/docker.sock:/var/run/docker.sock:ro \\\nnextcloud/all-in-one:latest\n\n# Some Info\ncat << EOF > /etc/motd\n # # ###### # # ##### #### # #### # # #####\n ## # # # # # # # # # # # # # #\n # # # ##### ## # # # # # # # # #\n # # # # ## # # # # # # # # #\n # ## # # # # # # # # # # # # #\n # # ###### # # # #### ###### #### #### #####\nIf you point a domain to this server ($(hostname -I | cut -f1 -d' ')), you can open the admin interface at https://yourdomain.com:8443\nOtherwise you can open the admin interface at https://$(hostname -I | cut -f1 -d' '):8080\n \nFurther documentation is available here: https://github.com/nextcloud/all-in-one\nEOF\n\n# Install unattended upgrades\nsudo apt-get install unattended-upgrades -y\n\n# firewall\nufw allow 80\nufw allow 443\nufw allow 8080\nufw allow 8443\nufw allow 3478\n\nrm /root/StackScript\nrm /root/ssinclude*\necho \"Installation complete!\"", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is required for creating DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "SOA email address", "default": "" } ] }, { "id": 1017300, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Kali Linux One-Click", "description": "Kali Linux One-Click", "ordinal": 3, "logo_url": "assets/kalilinux.svg", "images": [ "linode/kali" ], "deployments_total": 16888, "deployments_active": 480, "is_public": true, "mine": false, "created": "2022-06-21T14:38:37", "updated": "2023-12-07T14:24:23", "rev_note": "", "script": "#!/bin/bash\n## Kali\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\nfunction headlessoreverything {\n if [ $HEADLESS == \"Yes\" ] && [ $EVERYTHING == \"Yes\" ]; then \n DEBIAN_FRONTEND=noninteractive apt-get install kali-linux-everything -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n elif [ $EVERYTHING == \"Yes\" ] && [ $HEADLESS == \"No\" ]; then\n DEBIAN_FRONTEND=noninteractive apt-get install kali-linux-everything -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n elif [ $HEADLESS == \"Yes\" ] && [ $EVERYTHING == \"No\" ]; then \n DEBIAN_FRONTEND=noninteractive apt-get install kali-linux-headless -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n elif [ $HEADLESS == \"No\" ] && [ $EVERYTHING == \"No\" ]; then \n echo \"No Package Selected\"\n fi\n}\n\nfunction vncsetup {\n if [ $VNC == \"Yes\" ]; then \n ## XFCE & VNC Config\n apt-get install xfce4 xfce4-goodies dbus-x11 tigervnc-standalone-server expect -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n\n readonly VNCSERVER_SET_PASSWORD=$(expect -c \"\nspawn sudo -u $USERNAME vncserver\nexpect \\\"Password:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Verify:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Would you like to enter a view-only password (y/n)?\\\"\nsend \\\"n\\r\\\"\nexpect eof\n\")\necho \"$VNCSERVER_SET_PASSWORD\"\n sleep 2\n killvncprocess=$(ps aux | grep \"/usr/bin/Xtigervnc :1 -localhost=1 -desktop\" | head -n 1 | awk '{ print $2; }')\n kill $killvncprocess\n touch /etc/systemd/system/vncserver@.service\n cat < /etc/systemd/system/vncserver@.service\n[Unit]\nDescription=a wrapper to launch an X server for VNC\nAfter=syslog.target network.target\n[Service]\nType=forking\nUser=$USERNAME\nGroup=$USERNAME\nWorkingDirectory=/home/$USERNAME\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver -depth 24 -geometry 1280x800 -localhost :%i\nExecStop=/usr/bin/vncserver -kill :%i\n[Install]\nWantedBy=multi-user.target\nEOF\n systemctl daemon-reload\n systemctl start vncserver@1.service\n systemctl enable vncserver@1.service\n\n cat < /etc/motd\n###################################\n# VNC SSH Tunnel Instructions #\n###################################\n\n* Ensure you have a VNC Client installed on your local machine\n* Run the command below to start the SSH tunnel for VNC \n\n ssh -L 61000:localhost:5901 -N -l $USERNAME $FQDN\n\n* For more Detailed documentation please visit the offical Documentation below\n\n https://www.linode.com/docs/products/tools/marketplace/guides/kalilinux\n\n### To remove this message, you can edit the /etc/motd file ###\nEOF\n fi\n}\n\nfunction main {\n headlessoreverything\n vncsetup\n stackscript_cleanup\n}\n\nmain", "user_defined_fields": [ { "name": "everything", "label": "Would you like to Install the Kali Everything Package?", "oneof": "Yes,No", "default": "Yes" }, { "name": "headless", "label": "Would you like to Install the Kali Headless Package?", "oneof": "Yes,No", "default": "No" }, { "name": "vnc", "label": "Would you like to setup VNC to access Kali XFCE Desktop", "oneof": "Yes,No", "default": "Yes" }, { "name": "username", "label": "The VNC user to be created for the Linode. The username accepts only lowercase letters, numbers, dashes (-) and underscores (_)" }, { "name": "password", "label": "The password for the limited VNC user" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is required for creating DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address for SOA records (Requires API token)", "default": "" } ] }, { "id": 593835, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Plesk One-Click", "description": "Plesk is the leading secure WordPress and website management platform. This Stackscript installs the latest publicly available Plesk, activates a trial license, installs essential extensions, and sets up and configures the firewall. Please allow the script around 15 minutes to finish.", "ordinal": 4, "logo_url": "assets/plesk.svg", "images": [ "linode/centos7", "linode/ubuntu20.04" ], "deployments_total": 10510, "deployments_active": 484, "is_public": true, "mine": false, "created": "2019-09-26T17:34:17", "updated": "2023-12-07T09:13:45", "rev_note": "updated wording", "script": "#!/bin/bash\n# This block defines the variables the user of the script needs to input\n# when deploying using this script.\n#\n## Enable logging\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction pleskautoinstall {\n echo \"Downloading Plesk Auto-Installer\"\n sh <(curl https://autoinstall.plesk.com/one-click-installer || wget -O - https://autoinstall.plesk.com/one-click-installer)\n echo \"turning on http2\"\n /usr/sbin/plesk bin http2_pref --enable\n}\n\nfunction firewall {\n echo \"Setting Firewall to allow proper ports.\"\n if [ \"${detected_distro[distro]}\" = 'centos' ]; then \n iptables -I INPUT -p tcp --dport 21 -j ACCEPT\n iptables -I INPUT -p tcp --dport 22 -j ACCEPT\n iptables -I INPUT -p tcp --dport 25 -j ACCEPT\n iptables -I INPUT -p tcp --dport 80 -j ACCEPT\n iptables -I INPUT -p tcp --dport 110 -j ACCEPT\n iptables -I INPUT -p tcp --dport 143 -j ACCEPT\n iptables -I INPUT -p tcp --dport 443 -j ACCEPT\n iptables -I INPUT -p tcp --dport 465 -j ACCEPT\n iptables -I INPUT -p tcp --dport 993 -j ACCEPT\n iptables -I INPUT -p tcp --dport 995 -j ACCEPT\n iptables -I INPUT -p tcp --dport 8443 -j ACCEPT\n iptables -I INPUT -p tcp --dport 8447 -j ACCEPT\n iptables -I INPUT -p tcp --dport 8880 -j ACCEPT\n elif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\n ufw allow 21\n ufw allow 22\n ufw allow 25\n ufw allow 80\n ufw allow 110\n ufw allow 143\n ufw allow 443\n ufw allow 465\n ufw allow 993\n ufw allow 995\n ufw allow 8443\n ufw allow 8447\n ufw allow 8880\nelse \necho \"Distro Not supported\"\nfi\n}\n\nfunction main {\n pleskautoinstall\n firewall\n}\n\n# Execute script\nsystem_update\nmain\nstackscript_cleanup", "user_defined_fields": [] }, { "id": 595742, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "cPanel One-Click", "description": "cPanel One-Click", "ordinal": 5, "logo_url": "assets/cpanel.svg", "images": [ "linode/ubuntu20.04", "linode/almalinux8", "linode/rocky8" ], "deployments_total": 28128, "deployments_active": 1005, "is_public": true, "mine": false, "created": "2019-09-30T20:17:52", "updated": "2023-12-07T16:45:38", "rev_note": "", "script": "#!/bin/bash\nset -e\n\n# Commit: fde6587e08ea95321ce010e52a9c1b8d02455a97\n# Commit date: 2023-02-13 17:00:46 -0600\n# Generated: 2023-02-17 11:00:28 -0600\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\necho $(date +%Y%m%d%H%M%S) >> /tmp/cpdebug.log\n\n# Linode's Weblish console will truncate lines unless you do this tput smam. This\n# instructs the terminal to wrap your lines, which is especially important so that\n# the WHM login URL that gets printed at the end can be copied.\ntput smam\n\nsource /etc/os-release\n\nis_os_and_version_id_prefix() {\n [[ $ID == $1 ]] && [[ $VERSION_ID =~ ^$2 ]]\n}\n\nis_almalinux8() {\n is_os_and_version_id_prefix almalinux 8\n}\n\nis_centos7() {\n is_os_and_version_id_prefix centos 7\n}\n\nis_cloudlinux7() {\n is_os_and_version_id_prefix cloudlinux 7\n}\n\nis_cloudlinux8() {\n is_os_and_version_id_prefix cloudlinux 8\n}\n\nis_rocky8() {\n is_os_and_version_id_prefix rocky 8\n}\n\nis_ubuntu20() {\n is_os_and_version_id_prefix ubuntu 20.04\n}\n\nis_supported_os() {\n is_almalinux8 || \\\n is_centos7 || \\\n is_cloudlinux7 || \\\n is_cloudlinux8 || \\\n is_rocky8 || \\\n is_ubuntu20\n}\n\nhas_yum() {\n which yum >/dev/null 2>&1\n}\n\nhas_dnf() {\n which dnf >/dev/null 2>&1\n}\n\nhas_apt() {\n which apt >/dev/null 2>&1\n}\n\nis_networkmanager_enabled() {\n systemctl is-enabled NetworkManager.service > /dev/null 2>&1\n}\n\n# cPanel & WHM is incompatible with NetworkManager\nif is_networkmanager_enabled; then\n systemctl stop NetworkManager.service\n systemctl disable NetworkManager.service\n if has_dnf; then\n dnf -y remove NetworkManager\n elif has_yum; then\n yum -y remove NetworkManager\n fi\nfi\n\nhostnamectl set-hostname server.hostname.tld\n\ncd /home && curl -so installer -L https://securedownloads.cpanel.net/latest\n\nif is_supported_os; then\n if is_ubuntu20; then\n apt-get -o Acquire::ForceIPv4=true update -y\n DEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::options::=\"--force-confdef\" -o DPkg::options::=\"--force-confold\" install grub-pc\n sh installer --skiplicensecheck --skip-cloudlinux\n else\n sh installer --skiplicensecheck\n fi\nelse\n echo \"Your distribution is not supported by this StackScript.\"\n install -d -v -m 711 /var/cpanel\n touch /var/cpanel/cpinit.failed\nfi\n\nrm -f /etc/cpupdate.conf\ncat > /root/.bash_profile <<'END_OF_BASH_PROFILE'\n# .bash_profile\n# Get the aliases and functions\nif [ -f ~/.bashrc ]; then\n . ~/.bashrc\nfi\n# User specific environment and startup programs\nPATH=$PATH:$HOME/bin\nexport PATH\nbash /etc/motd.sh\nif [ -t 0 ]; then\n URL=`whmlogin --nowait 2> /dev/null`\n WHMLOGIN_RETURN=$?\n if [ $WHMLOGIN_RETURN == 1 ]; then\n # whmlogin doesn't support --nowait. Output a URL and hope it's accurate.\n echo \"To log in to WHM as the root user, visit the following address in your web browser:\"\n echo \"\"\n whmlogin\n echo \"\"\n echo \"Thank you for using cPanel & WHM!\"\n else\n if [ $WHMLOGIN_RETURN == 2 ]; then\n # whmlogin indicates that cpinit hasn't updated the IP/hostname yet.\n echo \"To log in to WHM as the root user, run the command 'whmlogin' to get a web address for your browser.\"\n echo \"\"\n echo \"Thank you for using cPanel & WHM!\"\n else\n # whmlogin returned a valid URL to use.\n echo \"To log in to WHM as the root user, visit the following address in your web browser:\"\n echo \"\"\n echo \"$URL\"\n echo \"\"\n echo \"Thank you for using cPanel & WHM!\"\n fi\n fi\nfi\nEND_OF_BASH_PROFILE\n\ncat > /etc/motd.sh <<'END_OF_MOTD'\n#!/bin/bash\nsource /etc/os-release\necho \"\n ____ _ ___ __ ___ _ __ __\n ___| _ \\ __ _ _ __ ___| | ( _ ) \\ \\ / / | | | \\/ |\n / __| |_) / _. | ._ \\ / _ \\ | / _ \\/\\ \\ \\ /\\ / /| |_| | |\\/| |\n| (__| __/ (_| | | | | __/ | | (_> < \\ V V / | _ | | | |\n \\___|_| \\__._|_| |_|\\___|_| \\___/\\/ \\_/\\_/ |_| |_|_| |_|\n\"\necho \"Welcome to cPanel & WHM `/usr/local/cpanel/cpanel -V`\"\necho \"\"\necho \"Running $PRETTY_NAME\"\necho \"\"\necho \"For our full cPanel & WHM documentation: https://go.cpanel.net/docs\"\necho \"\"\necho \"For information on how to quickly set up a website in cPanel & WHM: https://go.cpanel.net/buildasite\"\necho \"\" # This new line makes output from bash_profiles easier to read\nEND_OF_MOTD\ntouch /var/cpanel/cpinit.done", "user_defined_fields": [] }, { "id": 691621, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Cloudron One-Click", "description": "Cloudron One-Click", "ordinal": 6, "logo_url": "assets/cloudron.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 13758, "deployments_active": 628, "is_public": true, "mine": false, "created": "2020-11-30T21:21:45", "updated": "2023-12-07T13:31:57", "rev_note": "", "script": "#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# apt-get updates\n echo 'Acquire::ForceIPv4 \"true\";' > /etc/apt/apt.conf.d/99force-ipv4\n export DEBIAN_FRONTEND=noninteractive\n apt-get update -y\n\nwget https://cloudron.io/cloudron-setup\nchmod +x cloudron-setup\n./cloudron-setup --provider linode-mp\n\necho All finished! Rebooting...\n(sleep 5; reboot) &", "user_defined_fields": [] }, { "id": 692092, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Secure Your Server One-Click", "description": "Secure Your Server One-Click", "ordinal": 7, "logo_url": "assets/secureyourserver.svg", "images": [ "linode/debian10", "linode/ubuntu20.04", "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 4628, "deployments_active": 706, "is_public": true, "mine": false, "created": "2020-12-03T10:01:28", "updated": "2023-12-07T16:01:02", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## User and SSH Security\n#\n#\n#\n#\n\n## Domain\n#\n#\n#\n#\n#\n\n## Block Storage\n#\n#\n\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source Linode Helpers\nsource \nsource \nsource \nsource \n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode. (lower case only)" }, { "name": "password", "label": "The password for the limited sudo user" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode" }, { "name": "disable_root", "label": "Would you like to disable root login over SSH?", "oneof": "Yes,No" }, { "name": "token_password", "label": "Your Linode API token - This is required for creating DNS records", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token and domain)", "default": "" }, { "name": "soa_email_address", "label": "Your email address. This is used for creating DNS records and website VirtualHost configuration.", "default": "" }, { "name": "send_email", "label": "Would you like to be able to send email from this domain? (Requires domain)", "oneof": "Yes,No", "default": "No" }, { "name": "volume", "label": "To use a Block Storage volume, enter its name here.", "default": "" }, { "name": "volume_size", "label": "If creating a new Block Storage volume, enter its size in GB (NOTE: This creates a billable resource at $0.10/month per GB).", "default": "" } ] }, { "id": 925722, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Pritunl One-Click", "description": "Pritunl One-Click", "ordinal": 8, "logo_url": "assets/pritunl.svg", "images": [ "linode/debian10", "linode/ubuntu20.04" ], "deployments_total": 1151, "deployments_active": 82, "is_public": true, "mine": false, "created": "2021-10-26T15:23:37", "updated": "2023-12-06T11:09:03", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 443\nufw allow 80\nfail2ban_install\n\n# Mongo Install\napt-get install -y wget gnupg dirmngr \nwget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \necho \"deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\necho \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\napt-get update -y\napt-get install -y mongodb-org\nsystemctl enable mongod.service\nsystemctl start mongod.service\n\n# Pritunl\napt-key adv --keyserver hkp://keyserver.ubuntu.com --recv E162F504A20CDF15827F718D4B7C549A058F8B6B\napt-key adv --keyserver hkp://keyserver.ubuntu.com --recv 7568D9BB55FF9E5287D586017AE645C0CF8E292A\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \necho \"deb http://repo.pritunl.com/stable/apt buster main\" | tee /etc/apt/sources.list.d/pritunl.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\necho \"deb http://repo.pritunl.com/stable/apt focal main\" | tee /etc/apt/sources.list.d/pritunl.list\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\n\napt update -y\napt install -y pritunl\n\nsystemctl enable pritunl.service\nsystemctl start pritunl.service\n\n# Performance tune\necho \"* hard nofile 64000\" >> /etc/security/limits.conf\necho \"* soft nofile 64000\" >> /etc/security/limits.conf\necho \"root hard nofile 64000\" >> /etc/security/limits.conf\necho \"root soft nofile 64000\" >> /etc/security/limits.conf\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address for the SOA record", "default": "" } ] }, { "id": 741206, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "CyberPanel One-Click", "description": "CyberPanel One-Click", "ordinal": 9, "logo_url": "assets/cyberpanel.svg", "images": [ "linode/ubuntu20.04", "linode/ubuntu22.04" ], "deployments_total": 11109, "deployments_active": 596, "is_public": true, "mine": false, "created": "2021-01-27T02:46:19", "updated": "2023-12-07T16:13:29", "rev_note": "", "script": "#!/bin/bash\n### linode\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n### Install cyberpanel\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/cybersetup.sh )\n\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )\n\n### Clean up ls tmp folder\nsudo rm -rf /tmp/lshttpd/*", "user_defined_fields": [] }, { "id": 401709, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Minecraft: Java Edition One-Click", "description": "Minecraft OCA", "ordinal": 10, "logo_url": "assets/Minecraft.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 20310, "deployments_active": 346, "is_public": true, "mine": false, "created": "2019-03-08T21:13:32", "updated": "2023-12-07T16:42:13", "rev_note": "remove maxplayers hard coded options [oca-707]", "script": "#!/usr/bin/env bash\n# Game config options:\n# https://minecraft.gamepedia.com/Server.properties\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n## Linode/SSH Security Settings - Required\n#\n#\n## Linode/SSH Settings - Optional\n#\n#\n\n# Enable logging for the StackScript\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n[ ! $USERNAME ] && USERNAME='lgsmuser'\nsource \n\n# Difficulty\n[[ \"$DIFFICULTY\" = \"Peaceful\" ]] && DIFFICULTY=0\n[[ \"$DIFFICULTY\" = \"Easy\" ]] && DIFFICULTY=1\n[[ \"$DIFFICULTY\" = \"Normal\" ]] && DIFFICULTY=2\n[[ \"$DIFFICULTY\" = \"Hard\" ]] && DIFFICULTY=3\n\n# Gamemode\n[[ \"$GAMEMODE\" = \"Survival\" ]] && GAMEMODE=0\n[[ \"$GAMEMODE\" = \"Creative\" ]] && GAMEMODE=1\n[[ \"$GAMEMODE\" = \"Adventure\" ]] && GAMEMODE=2\n[[ \"$GAMEMODE\" = \"Spectator\" ]] && GAMEMODE=3\n\n# Player Idle Timeout\n[[ \"$PLAYERIDLETIMEOUT\" = \"Disabled\" ]] && PLAYERIDLETIMEOUT=0\n\n# Minecraft-specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\nsystem_install_package mailutils postfix curl netcat wget file bzip2 \\\n gzip unzip bsdmainutils python util-linux ca-certificates \\\n binutils bc jq tmux openjdk-17-jre dirmngr software-properties-common\n\n# Install LinuxGSM and Minecraft and enable the 'mcserver' service\nreadonly GAMESERVER='mcserver'\nv_linuxgsm_oneclick_install \"$GAMESERVER\" \"$USERNAME\"\n\n# Minecraft configurations\nsed -i s/server-ip=/server-ip=\"$IP\"/ /home/\"$USERNAME\"/serverfiles/server.properties\n\n# Customer config\nsed -i s/allow-flight=false/allow-flight=\"$ALLOWFLIGHT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/allow-nether=true/allow-nether=\"$ALLOWNETHER\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/announce-player-achievements=true/announce-player-achievements=\"$ANNOUNCEPLAYERACHIEVEMENTS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/difficulty=1/difficulty=\"$DIFFICULTY\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/enable-command-block=false/enable-command-block=\"$ENABLECOMMANDBLOCK\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/enable-query=true/enable-query=\"$ENABLEQUERY\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/force-gamemode=false/force-gamemode=\"$FORCEGAMEMODE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/gamemode=0/gamemode=\"$GAMEMODE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/generate-structures=true/generate-structures=\"$GENERATESTRUCTURES\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/hardcore=false/hardcore=\"$HARDCORE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/level-name=world/level-name=\"$LEVELNAME\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/level-seed=/level-seed=\"$LEVELSEED\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/level-type=DEFAULT/level-type=\"$LEVELTYPE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-build-height=256/max-build-height=\"$MAXBUILDHEIGHT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-players=20/max-players=\"$MAXPLAYERS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-tick-time=60000/max-tick-time=\"$MAXTICKTIME\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-world-size=29999984/max-world-size=\"$MAXWORLDSIZE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/motd=.*/motd=\"$MOTD\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/network-compression-threshold=256/network-compression-threshold=\"$NETWORKCOMPRESSIONTHRESHOLD\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/op-permission-level=4/op-permission-level=\"$OPPERMISSIONLEVEL\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/player-idle-timeout=0/player-idle-timeout=\"$PLAYERIDLETIMEOUT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/pvp=true/pvp=\"$PVP\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/resource-pack-sha1=/resource-pack-sha1=\"$RESOURCEPACKSHA1\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/server-port=25565/server-port=\"$PORT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/snooper-enabled=true/snooper-enabled=\"$SNOOPERENABLED\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/spawn-animals=true/spawn-animals=\"$SPAWNANIMALS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/spawn-monsters=true/spawn-monsters=\"$SPAWNMONSTERS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/spawn-npcs=true/spawn-npcs=\"$SPAWNNPCS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/use-native-transport=true/use-native-transport=\"$USENATIVETRANSPORT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/view-distance=10/view-distance=\"$VIEWDISTANCE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/rcon.password=*/rcon.password=\"\\\"$RCONPASSWORD\\\"\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/enable-rcon=false/enable-rcon=true/ /home/\"$USERNAME\"/serverfiles/server.properties\n\n# Start the service and setup firewall\nufw allow \"$PORT\"\nufw allow \"25575\"\n\n# Start and enable the Minecraft service\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "levelname", "label": "World Name", "default": "world" }, { "name": "motd", "label": "Message of the Day", "default": "Powered by Linode!" }, { "name": "allowflight", "label": "Flight Enabled", "oneof": "true,false", "default": "false" }, { "name": "allownether", "label": "Nether World Enabled", "oneof": "true,false", "default": "true" }, { "name": "announceplayerachievements", "label": "Player Achievements Enabled", "oneof": "true,false", "default": "true" }, { "name": "maxplayers", "label": "Maximum Players", "default": "25" }, { "name": "playeridletimeout", "label": "Player Idle Timeout Limit", "oneof": "Disabled,15,30,45,60", "default": "Disabled" }, { "name": "difficulty", "label": "Difficulty Level", "oneof": "Peaceful,Easy,Normal,Hard", "default": "Easy" }, { "name": "hardcore", "label": "Hardcore Mode Enabled", "oneof": "true,false", "default": "false" }, { "name": "pvp", "label": "PvP Enabled", "oneof": "true,false", "default": "true" }, { "name": "forcegamemode", "label": "Force Game Mode Enabled", "oneof": "true,false", "default": "false" }, { "name": "leveltype", "label": "World Type", "oneof": "DEFAULT,AMPLIFIED,FLAT,LEGACY", "default": "DEFAULT" }, { "name": "levelseed", "label": "World Seed", "default": "" }, { "name": "spawnanimals", "label": "Spawn Animals Enabled", "oneof": "true,false", "default": "true" }, { "name": "spawnmonsters", "label": "Spawn Monsters Enabled", "oneof": "true,false", "default": "true" }, { "name": "spawnnpcs", "label": "Spawn NPCs Enabled", "oneof": "true,false", "default": "true" }, { "name": "gamemode", "label": "Game Mode", "oneof": "Survival,Creative,Adventure,Spectator", "default": "Survival" }, { "name": "generatestructures", "label": "Structure Generation Enabled", "oneof": "true,false", "default": "true" }, { "name": "maxbuildheight", "label": "Maximum Build Height", "oneof": "50,100,200,256", "default": "256" }, { "name": "maxworldsize", "label": "Maximum World Size", "oneof": "100,1000,10000,100000,1000000,10000000,29999984", "default": "29999984" }, { "name": "viewdistance", "label": "View Distance", "oneof": "2,5,10,15,25,32", "default": "10" }, { "name": "enablecommandblock", "label": "Command Block Enabled", "oneof": "true,false", "default": "false" }, { "name": "enablequery", "label": "Querying Enabled", "oneof": "true,false", "default": "true" }, { "name": "enablercon", "label": "Enable RCON", "oneof": "true,false", "default": "false" }, { "name": "rconpassword", "label": "RCON Password", "default": "" }, { "name": "rconport", "label": "RCON Port", "default": "25575" }, { "name": "maxticktime", "label": "Maximum Tick Time", "default": "60000" }, { "name": "networkcompressionthreshold", "label": "Network Compression Threshold", "default": "256" }, { "name": "oppermissionlevel", "label": "Op-permission Level", "oneof": "1,2,3,4", "default": "4" }, { "name": "port", "label": "Port Number", "default": "25565" }, { "name": "snooperenabled", "label": "Snooper Enabled", "oneof": "true,false", "default": "true" }, { "name": "usenativetransport", "label": "Use Native Transport Enabled", "oneof": "true,false", "default": "true" }, { "name": "username", "label": "The username for the Linode's non-root admin/SSH user(must be lowercase)", "example": "lgsmuser" }, { "name": "password", "label": "The password for the Linode's non-root admin/SSH user", "example": "S3cuReP@s$w0rd" }, { "name": "pubkey", "label": "The SSH Public Key used to securely access the Linode via SSH", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 869129, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "aaPanel One-Click", "description": "aaPanel One-Click", "ordinal": 11, "logo_url": "assets/aapanel.svg", "images": [ "linode/centos7" ], "deployments_total": 5356, "deployments_active": 321, "is_public": true, "mine": false, "created": "2021-07-20T18:50:46", "updated": "2023-12-07T13:37:08", "rev_note": "", "script": "#!/bin/bash\n\n# Enable logging for the StackScript\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Yum Update\nyum update -y\n\n# Install aapanel\nyum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && echo y|bash install.sh aapanel\n\n# Log aaPanel login information\nbt default > /root/.aapanel_info\n\n# Stackscript Cleanup\nrm /root/StackScript\nrm /root/ssinclude*\necho \"Installation complete!\"", "user_defined_fields": [] }, { "id": 923033, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Akaunting One-Click", "description": "Akaunting One-Click", "ordinal": 12, "logo_url": "assets/akaunting.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 633, "deployments_active": 22, "is_public": true, "mine": false, "created": "2021-10-18T01:01:19", "updated": "2023-12-06T13:48:52", "rev_note": "", "script": "#!/bin/bash\n\n# \n# \n# \n# \n\n# \n# \n# \n# \n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nDEBIAN_FRONTEND=noninteractive apt-get update -qq >/dev/null\n\n###########################################################\n# Install NGINX\n###########################################################\napt-get install -y nginx\n\ncat <<'END' >/var/www/html/index.html\n\n \n \n \n \n \n\n Installing Akaunting\n\n \n \n\n \n \n\n \n
\n
\n \n
\n\n
\n \n
\n
\n

Installing...

Get back after 3 minutes!

\n
\n
\n \n\nEND\n\nchown www-data:www-data /var/www/html/index.html\nchmod 644 /var/www/html/index.html\n\n###########################################################\n# MySQL\n###########################################################\napt install -y mariadb-server expect\n\nfunction mysql_secure_install {\n # $1 - required - Root password for the MySQL database\n [ ! -n \"$1\" ] && {\n printf \"mysql_secure_install() requires the MySQL database root password as its only argument\\n\"\n return 1;\n }\n local -r db_root_password=\"$1\"\n local -r secure_mysql=$(\nexpect -c \"\nset timeout 10\nspawn mysql_secure_installation\nexpect \\\"Enter current password for root (enter for none):\\\"\nsend \\\"$db_root_password\\r\\\"\nexpect \\\"Change the root password?\\\"\nsend \\\"n\\r\\\"\nexpect \\\"Remove anonymous users?\\\"\nsend \\\"y\\r\\\"\nexpect \\\"Disallow root login remotely?\\\"\nsend \\\"y\\r\\\"\nexpect \\\"Remove test database and access to it?\\\"\nsend \\\"y\\r\\\"\nexpect \\\"Reload privilege tables now?\\\"\nsend \\\"y\\r\\\"\nexpect eof\n\")\n printf \"$secure_mysql\\n\"\n}\n\n# Set DB root password\necho \"mysql-server mysql-server/root_password password ${DB_PASSWORD}\" | debconf-set-selections\necho \"mysql-server mysql-server/root_password_again password ${DB_PASSWORD}\" | debconf-set-selections\n\nmysql_secure_install \"$DB_PASSWORD\"\n\n# Create DB\necho \"CREATE DATABASE ${DB_NAME};\" | mysql -u root -p\"$DB_PASSWORD\"\n\n# create DB user with password\necho \"CREATE USER '$DBUSER'@'localhost' IDENTIFIED BY '$DBUSER_PASSWORD';\" | mysql -u root -p\"$DB_PASSWORD\"\n\necho \"GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DBUSER'@'localhost';\" | mysql -u root -p\"$DB_PASSWORD\"\necho \"FLUSH PRIVILEGES;\" | mysql -u root -p\"$DB_PASSWORD\"\n\n\n###########################################################\n# Install PHP \n###########################################################\napt-get install -y zip unzip php-mbstring php-zip php-gd php-cli php-curl php-intl php-imap php-xml php-xsl php-tokenizer php-sqlite3 php-pgsql php-opcache php-simplexml php-fpm php-bcmath php-ctype php-json php-pdo php-mysql\n\n###########################################################\n# Akaunting\n###########################################################\nmkdir -p /var/www/akaunting \\\n && curl -Lo /tmp/akaunting.zip 'https://akaunting.com/download.php?version=latest&utm_source=linode&utm_campaign=developers' \\\n && unzip /tmp/akaunting.zip -d /var/www/html \\\n && rm -f /tmp/akaunting.zip\n\ncat </var/www/html/.env\nAPP_NAME=Akaunting\nAPP_ENV=production\nAPP_LOCALE=en-GB\nAPP_INSTALLED=false\nAPP_KEY=\nAPP_DEBUG=false\nAPP_SCHEDULE_TIME=\"09:00\"\nAPP_URL=\n\nDB_CONNECTION=mysql\nDB_HOST=localhost\nDB_PORT=3306\nDB_DATABASE=${DB_NAME}\nDB_USERNAME=${DBUSER}\nDB_PASSWORD=${DBUSER_PASSWORD}\nDB_PREFIX=\n\nBROADCAST_DRIVER=log\nCACHE_DRIVER=file\nSESSION_DRIVER=file\nQUEUE_CONNECTION=sync\nLOG_CHANNEL=stack\n\nMAIL_MAILER=mail\nMAIL_HOST=localhost\nMAIL_PORT=2525\nMAIL_USERNAME=null\nMAIL_PASSWORD=null\nMAIL_ENCRYPTION=null\nMAIL_FROM_NAME=null\nMAIL_FROM_ADDRESS=null\n\nFIREWALL_ENABLED=false\nEND\n\ncd /var/www/html && php artisan key:generate\n\n# Install Akaunting\nphp /var/www/html/artisan install --db-host=\"localhost\" --db-name=\"$DB_NAME\" --db-username=\"$DBUSER\" --db-password=\"$DBUSER_PASSWORD\" --company-name=\"$COMPANY_NAME\" --company-email=\"$COMPANY_EMAIL\" --admin-email=\"$ADMIN_EMAIL\" --admin-password=\"$ADMIN_PASSWORD\"\n\n# Fix permissions\nchown -Rf www-data:www-data /var/www/html\nfind /var/www/html/ -type d -exec chmod 755 {} \\;\nfind /var/www/html/ -type f -exec chmod 644 {} \\;\n\n###########################################################\n# Configure NGINX\n###########################################################\nPHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\ncat << END > /etc/nginx/nginx.conf\n# Generic startup file.\nuser www-data;\n\n#usually equal to number of CPUs you have. run command \"grep processor /proc/cpuinfo | wc -l\" to find it\nworker_processes auto;\nworker_cpu_affinity auto;\n\nerror_log /var/log/nginx/error.log;\npid /var/run/nginx.pid;\n\n# Keeps the logs free of messages about not being able to bind().\n#daemon off;\n\nevents {\nworker_connections 1024;\n}\n\nhttp {\n# rewrite_log on;\n\ninclude mime.types;\ndefault_type application/octet-stream;\naccess_log /var/log/nginx/access.log;\nsendfile on;\n# tcp_nopush on;\nkeepalive_timeout 64;\n# tcp_nodelay on;\n# gzip on;\n #php max upload limit cannot be larger than this \nclient_max_body_size 13m;\nindex index.php index.html index.htm;\n\n# Upstream to abstract backend connection(s) for PHP.\nupstream php {\n #this should match value of \"listen\" directive in php-fpm pool\n server unix:/run/php/php$PHP_VERSION-fpm.sock;\n server 127.0.0.1:9000;\n}\n\nserver {\n listen 80 default_server;\n\n server_name _;\n\n root /var/www/html;\n\n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-XSS-Protection \"1; mode=block\";\n add_header X-Content-Type-Options \"nosniff\";\n\n index index.html index.htm index.php;\n\n charset utf-8;\n\n location / {\n try_files \\$uri \\$uri/ /index.php?\\$query_string;\n }\n\n # Prevent Direct Access To Protected Files\n location ~ \\.(env|log) {\n deny all;\n }\n\n # Prevent Direct Access To Protected Folders\n location ~ ^/(^app$|bootstrap|config|database|overrides|resources|routes|storage|tests|artisan) {\n deny all;\n }\n\n # Prevent Direct Access To modules/vendor Folders Except Assets\n location ~ ^/(modules|vendor)\\/(.*)\\.((?!ico|gif|jpg|jpeg|png|js\\b|css|less|sass|font|woff|woff2|eot|ttf|svg).)*$ {\n deny all;\n }\n\n error_page 404 /index.php;\n\n # Pass PHP Scripts To FastCGI Server\n location ~ \\.php$ {\n fastcgi_split_path_info ^(.+\\.php)(/.+)\\$;\n fastcgi_pass php;\n fastcgi_index index.php;\n fastcgi_param SCRIPT_FILENAME \\$document_root\\$fastcgi_script_name;\n include fastcgi_params;\n }\n\n location ~ /\\.(?!well-known).* {\n deny all;\n }\n}\n}\nEND\n\n# Remove installation screen\nrm -f /var/www/html/index.html\n\nservice nginx reload\n\n###########################################################\n# Firewall\n###########################################################\napt-get install ufw -y\nufw limit ssh\nufw allow http\nufw allow https\n\nufw --force enable\n\n###########################################################\n# Stackscript cleanup\n###########################################################\nrm /root/StackScript\nrm /root/ssinclude*\necho \"Installation complete!\"", "user_defined_fields": [ { "name": "company_name", "label": "Company Name", "example": "My Company" }, { "name": "company_email", "label": "Company Email", "example": "my@company.com" }, { "name": "admin_email", "label": "Admin Email", "example": "my@company.com" }, { "name": "admin_password", "label": "Admin Password", "example": "s3cur39a55w0r0" }, { "name": "db_name", "label": "MySQL Database Name", "example": "akaunting" }, { "name": "db_password", "label": "MySQL root Password", "example": "s3cur39a55w0r0" }, { "name": "dbuser", "label": "MySQL Username", "example": "akaunting" }, { "name": "dbuser_password", "label": "MySQL User Password", "example": "s3cur39a55w0r0" } ] }, { "id": 985374, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Ant Media Server: Enterprise Edition One-Click", "description": "Ant Media Enterprise Edition One-Click", "ordinal": 13, "logo_url": "assets/antmediaserver.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 1370, "deployments_active": 63, "is_public": true, "mine": false, "created": "2022-03-08T17:39:39", "updated": "2023-12-07T15:14:09", "rev_note": "", "script": "#!/usr/bin/env bash\n\nset -x\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\nZIP_FILE=\"https://antmedia.io/linode/antmedia_2.5.3.zip\"\nINSTALL_SCRIPT=\"https://raw.githubusercontent.com/ant-media/Scripts/master/install_ant-media-server.sh\"\n\nwget -q --no-check-certificate $ZIP_FILE -O /tmp/antmedia.zip && wget -q --no-check-certificate $INSTALL_SCRIPT -P /tmp/\n\nif [ $? == \"0\" ]; then\n bash /tmp/install_ant-media-server.sh -i /tmp/antmedia.zip\nelse\n logger \"There is a problem in installing the ant media server. Please send the log of this console to contact@antmedia.io\"\n exit 1\nfi", "user_defined_fields": [] }, { "id": 804144, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Ant Media Server: Community Edition One-Click", "description": "Ant Media Server One-Click", "ordinal": 14, "logo_url": "assets/antmediaserver.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 5618, "deployments_active": 461, "is_public": true, "mine": false, "created": "2021-04-01T12:50:57", "updated": "2023-12-07T10:23:21", "rev_note": "", "script": "#!/usr/bin/env bash \n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nZIP_FILE=\"https://github.com/ant-media/Ant-Media-Server/releases/download/ams-v2.5.3/ant-media-server-community-2.5.3.zip\"\n\n\nINSTALL_SCRIPT=\"https://raw.githubusercontent.com/ant-media/Scripts/master/install_ant-media-server.sh\"\n\nwget -q --no-check-certificate $ZIP_FILE -O /tmp/antmedia.zip && wget -q --no-check-certificate $INSTALL_SCRIPT -P /tmp/\n\nif [ $? == \"0\" ]; then\n bash /tmp/install_ant-media-server.sh -i /tmp/antmedia.zip\nelse\n logger \"There is a problem in installing the ant media server. Please send the log of this console to contact@antmedia.io\"\n exit 1\nfi", "user_defined_fields": [] }, { "id": 1102900, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Apache Airflow One-Click", "description": "Apache Airflow One-Click App", "ordinal": 15, "logo_url": "assets/apacheairflow.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 127, "deployments_active": 4, "is_public": true, "mine": false, "created": "2022-12-20T17:32:08", "updated": "2023-11-28T13:38:46", "rev_note": "", "script": "#!/bin/bash\n#\n# \n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n## Enable logging\n\nset -x\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Register default rDNS \nexport DEFAULT_RDNS=$(dnsdomainname -A | awk '{print $1}')\n\n#set absolute domain if any, otherwise use DEFAULT_RDNS\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DEFAULT_RDNS\"\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\ncreate_a_record $SUBDOMAIN $IP $DOMAIN\n\n# install depends\nexport DEBIAN_FRONTEND=noninteractive\nsudo apt update\n#sudo apt -y upgrade\nsudo apt install -y python3-pip\nsudo apt install -y build-essential libssl-dev libffi-dev python3-dev\nsudo apt install -y python3-venv # One of the Airflow examples requires virtual environments\n\nexport AIRFLOW_HOME=~/airflow\n\n# Install Airflow using the constraints file\nAIRFLOW_VERSION=2.4.1\nPYTHON_VERSION=\"$(python3 --version | cut -d \" \" -f 2 | cut -d \".\" -f 1-2)\"\n# For example: 3.7\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n# For example: https://raw.githubusercontent.com/apache/airflow/constraints-2.4.1/constraints-3.7.txt\npip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\n\n# The Standalone command will initialise the database, make a user,\n# and start all components for you.\nairflow standalone &\n\n###\n# \n# systemd unit file and per component settings go here\n# \n### \n\n\n## install nginx reverse-proxy \napt install nginx -y \n\n#configure nginx reverse proxy\nrm /etc/nginx/sites-enabled/default\ntouch /etc/nginx/sites-available/reverse-proxy.conf\ncat < /etc/nginx/sites-available/reverse-proxy.conf\nserver {\n listen 80;\n listen [::]:80;\n server_name ${DEFAULT_RDNS};\n\n access_log /var/log/nginx/reverse-access.log;\n error_log /var/log/nginx/reverse-error.log;\n\n location / {\n proxy_pass http://localhost:8080;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forward-For \\$proxy_add_x_forwarded_for;\n }\n}\nEND\nln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/reverse-proxy.conf\n\n#enable and start nginx\nsystemctl enable nginx\nsystemctl restart nginx \n\n## UFW rules \nufw allow http \nufw allow https \nsystemctl enable ufw\n\nsleep 60 \n\n## install SSL certs. required \npip install pyOpenSSL --upgrade\napt install python3-certbot-nginx -y \ncertbot run --non-interactive --nginx --agree-tos --redirect -d ${ABS_DOMAIN} -m ${SOA_EMAIL_ADDRESS} -w /var/www/html/\n\n## write some login details\nexport ADMIN_PASS=$(cat /root/airflow/standalone_admin_password.txt)\ncat < /etc/motd \nThe installation of Apache Airflow is now complete, and the application is running in standalone mode.\n#\nYou can log into the Airflow GUI at ${ABS_DOMAIN}\nWith the credentials: \nUsername: admin\nPassword: ${ADMIN_PASS}\n#\nStandalone mode is not recommended for production.\nEND\n\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode.", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 1160820, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Appwrite One-Click", "description": "Appwrite One-Click ", "ordinal": 16, "logo_url": "assets/appwrite.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 175, "deployments_active": 11, "is_public": true, "mine": false, "created": "2023-04-21T13:09:13", "updated": "2023-12-07T09:40:21", "rev_note": "", "script": "#!/bin/bash\n### linode \n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# install docker\ncurl -fsSL https://get.docker.com -o get-docker.sh\nbash ./get-docker.sh\n\n# install haveged\nsudo apt-get install -y haveged\n\n# Install Appwrite\n# Grab latest version\nappversion=$(curl -s https://api.github.com/repos/appwrite/appwrite/releases/latest | grep -oP '\"tag_name\": \"\\K.*?(?=\")')\n\ndocker run --rm \\\n --volume /var/run/docker.sock:/var/run/docker.sock \\\n --volume \"$(pwd)\"/appwrite:/usr/src/code/appwrite:rw \\\n appwrite/appwrite:$appversion sh -c \"install --httpPort=80 --httpsPort=443 --interactive=N\"\n\necho \"Installation complete!\"", "user_defined_fields": [] }, { "id": 401699, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Ark One-Click", "description": "Ark - Latest One-Click", "ordinal": 17, "logo_url": "assets/Ark@1x.svg", "images": [ "linode/debian11" ], "deployments_total": 1145, "deployments_active": 4, "is_public": true, "mine": false, "created": "2019-03-08T21:05:54", "updated": "2023-12-05T18:43:30", "rev_note": "Remove SSH Pubkey UDF", "script": "#!/bin/bash\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\nGAMESERVER=\"arkserver\"\n\nset_hostname\napt_setup_update\n\n\n# ARK specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix \\\ncurl wget file bzip2 gzip unzip bsdmainutils \\\npython util-linux ca-certificates binutils bc \\\njq tmux lib32gcc-s1 libstdc++6 libstdc++6:i386 \n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install ARK\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\n#Game Config Options\n\nsed -i s/XPMultiplier=.*/XPMultiplier=\"$XPMULTIPLIER\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerPassword=.*/ServerPassword=\"$SERVERPASSWORD\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerHardcore=.*/ServerHardcore=\"$SERVERPASSWORD\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerPVE=.*/ServerPVE=\"$SERVERPVE\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/Message=.*/Message=\"$MOTD\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/SessionName=.*/SessionName=\"$SESSIONNAME\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerAdminPassword=.*/ServerAdminPassword=\"\\\"$RCONPASSWORD\\\"\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\n\n\n# Start the service and setup firewall\nufw_install\nufw allow 27015/udp\nufw allow 7777:7778/udp\nufw allow 27020/tcp\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup", "user_defined_fields": [ { "name": "rconpassword", "label": "RCON password" }, { "name": "sessionname", "label": "Server Name", "default": "Ark Server" }, { "name": "motd", "label": "Message of the Day", "default": "Powered by Linode!" }, { "name": "serverpassword", "label": "Server Password", "default": "" }, { "name": "hardcore", "label": "Hardcore Mode Enabled", "oneof": "True,False", "default": "False" }, { "name": "xpmultiplier", "label": "XP Multiplier", "oneof": "1,1.5,2,5,10,20", "default": "2" }, { "name": "serverpve", "label": "Server PvE", "oneof": "True,False", "default": "False" } ] }, { "id": 662118, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Azuracast One-Click", "description": "AzuraCast One-Click", "ordinal": 18, "logo_url": "assets/azuracast.svg", "images": [ "linode/debian10", "linode/ubuntu20.04" ], "deployments_total": 2692, "deployments_active": 186, "is_public": true, "mine": false, "created": "2020-08-12T15:50:09", "updated": "2023-12-05T11:47:34", "rev_note": "", "script": "#!/bin/bash\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, apt configuration and update/upgrade\nset_hostname\napt_setup_update\n\n# Install GIT\napt-get update && apt-get install -q -y git\n# Cloning AzuraCast and install\nmkdir -p /var/azuracast\ncd /var/azuracast\ncurl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/main/docker.sh > docker.sh\nchmod a+x docker.sh\nyes 'Y' | ./docker.sh setup-release\nyes '' | ./docker.sh install\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [] }, { "id": 913277, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "BeEF One-Click", "description": "BeEF One-Click", "ordinal": 19, "logo_url": "assets/beef.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 30459, "deployments_active": 1149, "is_public": true, "mine": false, "created": "2021-09-30T18:28:58", "updated": "2023-12-07T13:08:54", "rev_note": "", "script": "#!/bin/bash\n#\n# Script to install BEEF on Linode\n# \n# \n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \nbeef_config=\"/home/beef/config.yaml\"\nkey=\"privkey.pem\"\ncert=\"fullchain.pem\"\n# System Update\napt_setup_update\n# UFW\nufw allow 80\nufw allow 443\nufw allow 3000\nfunction configure_nginx {\n apt install git nginx ruby-dev -y\n # NGINX\n mkdir -p /var/www/certs/.well-known\n chown -R www-data:www-data /var/www/certs/\n cat < /etc/nginx/sites-available/$FQDN\nserver {\n listen 80;\n listen [::]:80;\n server_name $FQDN;\n root /var/www/certs;\n location / {\n try_files \\$uri \\$uri/ =404;\n }\n# allow .well-known\n location ^~ /.well-known {\n allow all;\n auth_basic off;\n alias /var/www/certs/.well-known;\n }\n}\nEOF\n ln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/$FQDN\n unlink /etc/nginx/sites-enabled/default\n systemctl restart nginx\n}\nfunction configure_ssl {\n apt install certbot python3-certbot-nginx -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\nfunction create_beef_user {\n function create_beef {\n groupadd --system beef\n useradd -s /sbin/nologin --system -g beef beef\n }\n grep beef /etc/passwd\n if [ $? -eq 1 ];then\n create_beef\n else\n echo \"[INFO] beef already on the system. Deleting user\"\n deluser --remove-home beef\n create_beef\n fi\n}\nfunction configure_beef {\n git clone https://github.com/beefproject/beef.git /home/beef\n chown -R beef: /home/beef\n cd /home/beef\n cp /etc/letsencrypt/live/$FQDN/$key .\n cp /etc/letsencrypt/live/$FQDN/$cert .\n # get line number to replace\n get_https_enable=$(grep -n -C 10 \"key:\" $beef_config | grep -v \"#\" | grep \"https:\" -A 5 | grep \"enable:\" | awk -F \"-\" {'print $1'})\n get_https_public_enabled=$(grep -n -C 10 \"key:\" $beef_config | grep -v \"#\" | grep \"https:\" -A 5 | grep \"public_enabled:\" | awk -F \"-\" {'print $1'})\n # replacing line numebr\n sed -i \"\"$get_https_enable\"s/enable: false/enable: true/\" $beef_config\n sed -i \"\"$get_https_public_enabled\"s/public_enabled: false/public_enabled: true/\" $beef_config\n sed -i \"/key:/c\\ key: \\\"$key\\\"\" $beef_config\n sed -i \"/cert:/c\\ cert: \\\"$cert\\\"\" $beef_config\n # creds\n #sed -i \"/user:/c\\ user: \\\"beef\\\"\" $beef_config\n sed -i \"/passwd:/c\\ passwd: \\\"$BEEFPASSWORD\\\"\" $beef_config\n # install local copy of beef\n # install deps\n apt install curl git build-essential openssl libreadline6-dev zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev autoconf libc6-dev libncurses5-dev automake libtool bison nodejs libcurl4-openssl-dev ruby-dev -y\n su - -s /bin/bash beef\n bundle3.0 config set --local path /home/beef/.gem\n bundle3.0 install\n gem install --user-install xmlrpc\n \n}\nfunction beef_startup {\n cat < /home/beef/start_beef\n#!/bin/bash\nfunction start_beef {\n cd /home/beef\n echo no | ./beef\n}\nstart_beef\nEOF\n chown -R beef:beef /home/beef\n chmod +x /home/beef/start_beef\n}\n \nfunction beef_job {\n cat < /etc/systemd/system/beef.service\n[Unit]\nDescription=Browser Exploitation Framework\nWants=network-online.target\nAfter=network-online.target\n[Service]\nUser=beef\nGroup=beef\nExecStart=/home/beef/start_beef\n[Install]\nWantedBy=default.target\nEOF\n systemctl daemon-reload\n systemctl start beef\n systemctl enable beef\n}\nfunction ssl_renew_cron {\n cat </root/certbot-beef-renewal.sh\n#!/bin/bash\n#\n# Script to handle Certbot renewal & BeEf\n# Debug\n# set -xo pipefail\nexport BEEF_FULL=/home/beef/fullchain.pem\nexport BEEF_PRIVKEY=/home/beef/privkey.pem\nexport FULLCHAIN=/etc/letsencrypt/live/$FQDN/fullchain.pem\nexport PRIVKEY=/etc/letsencrypt/live/$FQDN/privkey.pem\ncertbot renew\ncat \\$FULLCHAIN > \\$BEEF_FULL\ncat \\$PRIVKEY > \\$BEEF_PRIVKEY\nservice beef reload\nEND\n chmod +x /root/certbot-beef-renewal.sh\n# Setup Cron\n crontab -l > cron\n echo \"* 1 * * 1 bash /root/certbot-beef-renewal.sh\" >> cron\n crontab cron\n rm cron\n}\nfunction install_complete {\n cat < /root/beef.info\n##############################\n# BEEF INSTALLATION COMPLETE #\n##############################\nEndpoint: https://$FQDN:3000/ui/panel\nCredentials can be found here:\n/home/beef/config.yaml\nHappy hunting!\nEOF\n}\nfunction main {\n create_beef_user\n configure_nginx\n configure_ssl\n configure_beef\n beef_startup\n beef_job\n ssl_renew_cron\n install_complete\n}\nmain\n# Clean up\nstackscript_cleanup\ncat /root/beef.info", "user_defined_fields": [ { "name": "beefpassword", "label": "BEEF Password" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode. The username cannot contain any spaces or capitol letters. For this application the username 'beef' is reserved for the application, so please choose an alternative username for this deployment.", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 923034, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "BitNinja One-Click", "description": "BitNinja One-Click", "ordinal": 20, "logo_url": "assets/bitninja.svg", "images": [ "linode/centos7", "linode/debian10", "linode/ubuntu20.04", "linode/debian11" ], "deployments_total": 35, "deployments_active": 0, "is_public": true, "mine": false, "created": "2021-10-18T01:03:02", "updated": "2023-11-28T09:18:11", "rev_note": "", "script": "#!bin/bash\n\n# \n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nwget -qO- https://get.bitninja.io/install.sh | /bin/bash -s - --license_key=\"$license_key\" -y", "user_defined_fields": [ { "name": "license_key", "label": "License Key" } ] }, { "id": 1037036, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Budibase One-Click", "description": "Budibase One Click App", "ordinal": 21, "logo_url": "assets/budibase.svg", "images": [ "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 432, "deployments_active": 24, "is_public": true, "mine": false, "created": "2022-08-02T18:42:41", "updated": "2023-12-04T00:58:23", "rev_note": "", "script": "#!/bin/bash\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install the dependencies & add Docker to the APT repository\napt install -y apt-transport-https ca-certificates curl software-properties-common gnupg2 pwgen ufw\ncurl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable\"\n\n# Update & install Docker-CE\napt_setup_update\napt install -y docker.io\n\n# Check to ensure Docker is running and installed correctly\nsystemctl status docker\ndocker -v\n\n# Install Docker Compose\ncurl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose\nchmod +x /usr/local/bin/docker-compose\ndocker-compose --version\n\necho \"Creating passwords for /opt/budibase/.env\"\nVAR_JWT_SECRET=$(pwgen 16)\nVAR_MINIO_ACCESS_KEY=$(pwgen 16)\nVAR_MINIO_SECRET_KEY=$(pwgen 16)\nVAR_COUCH_DB_PASSWORD=$(pwgen 16)\nVAR_REDIS_PASSWORD=$(pwgen 16)\nVAR_INTERNAL_API_KEY=$(pwgen 16)\nIP=`hostname -I | awk '{print$1}'`\n\nmkdir -p /opt/budibase\ncd /opt/budibase\necho \"Fetch budibase docker compose file\"\ncurl -L https://raw.githubusercontent.com/Budibase/budibase/master/hosting/docker-compose.yaml -o /opt/budibase/docker-compose.yml\necho \"Fetch budibase .env template\"\ncurl -L https://raw.githubusercontent.com/Budibase/budibase/master/hosting/.env -o /opt/budibase/.env\necho \"Set passwords in /opt/budibase/.env\"\nsed -i \"s/JWT_SECRET=testsecret/JWT_SECRET=$VAR_JWT_SECRET/\" /opt/budibase/.env\nsed -i \"s/MINIO_ACCESS_KEY=budibase/MINIO_ACCESS_KEY=$VAR_MINIO_ACCESS_KEY/\" /opt/budibase/.env\nsed -i \"s/MINIO_SECRET_KEY=budibase/MINIO_SECRET_KEY=$VAR_MINIO_SECRET_KEY/\" /opt/budibase/.env\nsed -i \"s/COUCH_DB_PASSWORD=budibase/COUCH_DB_PASSWORD=$VAR_COUCH_DB_PASSWORD/\" /opt/budibase/.env\nsed -i \"s/REDIS_PASSWORD=budibase/REDIS_PASSWORD=$VAR_REDIS_PASSWORD/\" /opt/budibase/.env\nsed -i \"s/INTERNAL_API_KEY=budibase/INTERNAL_API_KEY=$VAR_INTERNAL_API_KEY/\" /opt/budibase/.env\nsed -i \"s/MAIN_PORT=10000/MAIN_PORT=$BBPORT/\" /opt/budibase/.env\ndocker-compose up -d\n\ncat </etc/profile.d/budibase_welcome.sh\n#!/bin/sh\n#\nIP=$(hostname -I | awk '{print$1}')\necho \"\n********************************************************************************\nWelcome to Budibase!\nTo help keep this server secure, the UFW firewall is enabled.\nAll ports are BLOCKED except 22 (SSH) and the Web UI port $BBPORT.\n********************************************************************************\n # Budibase UI: http://$IP:$BBPORT/\n # Website: https://budibase.com\n # Documentation: https://docs.budibase.com\n # Github: https://github.com/Budibase/budibase\n # Community Support: https://github.com/Budibase/budibase/discussions\n # Restart Budibase: cd /opt/budibase; docker-compose down; docker-compose up -d\n # Budibase config: /etc/budibase/.env\n\"\nEND\nchmod +x /etc/profile.d/budibase_welcome.sh\n# Enable UFW and add some rules to it\nufw enable\nufw limit ssh/tcp comment 'Rate limit the SSH port'\nufw allow $BBPORT/tcp comment \"TCP Listen port for Budibase\"\nufw --force enable\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "BBPORT", "label": "Budibase Port", "example": "Default: 80", "default": "80" } ] }, { "id": 869155, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Chevereto One-Click", "description": "Chevereto One-Click", "ordinal": 22, "logo_url": "assets/chevereto.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 236, "deployments_active": 6, "is_public": true, "mine": false, "created": "2021-07-20T19:07:56", "updated": "2023-10-30T19:52:12", "rev_note": "", "script": "#!/usr/bin/env bash\n# https://github.com/chevereto/linode-marketplace\n\nset -e\n\nCHEVERETO_INSTALLER_TAG=\"3.1.0\"\nWORKING_DIR=\"/var/www/html\"\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n## 03-force-ssh-logout.sh\ncat >>/etc/ssh/sshd_config </dev/null\napt install -y apache2 libapache2-mod-php\napt install -y mysql-server\napt install -y php\napt install -y php-{common,cli,curl,fileinfo,gd,imagick,intl,json,mbstring,mysql,opcache,pdo,pdo-mysql,xml,xmlrpc,zip}\napt install -y python3-certbot-apache software-properties-common unzip\n\n# 01-fs.sh\ncat >/etc/apache2/sites-available/000-default.conf <\n \n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n \n ServerAdmin webmaster@localhost\n DocumentRoot /var/www/html\n ErrorLog \\${APACHE_LOG_DIR}/error.log\n CustomLog \\${APACHE_LOG_DIR}/access.log combined\n\nEOM\n\ncat >/etc/update-motd.d/99-one-click < certbot --apache -d example.com -d www.example.com\nIMPORTANT:\n * After connecting to the server for the first time, immediately install\n Chevereto at http://\\$myip/installer.php\n * Secure your database by running:\n > mysql_secure_installation\n * Setup email delivery at http://\\$myip/dashboard/settings/email\nFor help and more information visit https://chevereto.com\n********************************************************************************\nTo delete this message of the day: rm -rf \\$(readlink -f \\${0})\nEOF\nEOM\nchmod +x /etc/update-motd.d/99-one-click\n\ncat >/etc/cron.d/chevereto </etc/php/7.4/apache2/conf.d/chevereto.ini <>/var/log/per-instance.log\n\nMYSQL_ROOT_PASS=$(openssl rand -hex 16)\nDEBIAN_SYS_MAINT_MYSQL_PASS=$(openssl rand -hex 16)\n\nCHEVERETO_DB_HOST=localhost\nCHEVERETO_DB_PORT=3306\nCHEVERETO_DB_NAME=chevereto\nCHEVERETO_DB_USER=chevereto\nCHEVERETO_DB_PASS=$(openssl rand -hex 16)\n\ncat >/root/.mysql_password <>/etc/apache2/envvars </etc/mysql/debian.cnf <>/var/log/per-instance.log\n\necho \"[OK] Chevereto Installer $CHEVERETO_INSTALLER_TAG provisioned!\"", "user_defined_fields": [] }, { "id": 869158, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "ClusterControl One-Click", "description": "ClusterControl One-Click", "ordinal": 23, "logo_url": "assets/clustercontrol.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 173, "deployments_active": 5, "is_public": true, "mine": false, "created": "2021-07-20T19:13:44", "updated": "2023-12-07T09:24:12", "rev_note": "", "script": "#!/usr/bin/env bash\n\n### UDF Variables\n\n## Severalnines settings\n#\n#\n\n## Domain settings\n#\n#\n#\n#\n\n## Let's Encrypt SSL\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n# System Update\nsystem_update\n\nworkdir=/tmp\nIP=`hostname -I | awk '{print$1}'`\n# if command -v dig &>/dev/null; then\n# echo -e \"\\nDetermining network interfaces.\" \n# ext_ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)\n# [[ ! -z $ext_ip ]] && IP=${ext_ip}\n# fi\nlog_progress() {\n\n echo \"$1\" >> /root/cc_install.log\n}\n\ninstall_cc() {\n export HOME=/root\n export USER=root\n wget --no-check-certificate https://severalnines.com/downloads/cmon/install-cc\n chmod +x install-cc\n echo \"mysql cmon password = $CMONUSER_PASSWORD\" >> /root/.cc_passwords\n echo \"mysql root password = $DBROOT_PASSWORD\" >> /root/.cc_passwords\n SEND_DIAGNOSTICS=0 S9S_CMON_PASSWORD=$CMONUSER_PASSWORD S9S_ROOT_PASSWORD=$DBROOT_PASSWORD INNODB_BUFFER_POOL_SIZE=256 ./install-cc\n}\n\nfirstboot() {\n hostnamectl set-hostname clustercontrol\n\n ssh-keygen -b 2048 -t rsa -f /root/.ssh/id_rsa -q -N \"\"\n ssh-keygen -y -f /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub\n SSH_KEY=$(cat /root/.ssh/id_rsa.pub)\n\n cat < /etc/update-motd.d/99-cc-motd \n#!/bin/sh\necho \"###\"\necho \"\"\necho \"Welcome to Severalnines Database Monitoring and Management Application - ClusterControl\"\necho \"Open your web browser to http://${IP}/clustercontrol to access ClusterControl's web application\"\necho \"\"\necho \"The public SSH key (root) is:\"\necho \"$SSH_KEY\"\necho \"\"\necho \"###\"\nEND\n\n chmod +x /etc/update-motd.d/99-cc-motd\n}\n\nenable_fw() {\n ufw default deny incoming\n ufw default allow outgoing\n ufw allow ssh\n ufw allow http\n ufw allow https\n ufw allow 9999\n ufw allow 9501\n}\n\ncleanup() {\n rm -rf /tmp/* /var/tmp/* /root/scripts\n history -c\n cat /dev/null > /root/.bash_history\n unset HISTFILE\n\n apt-get -y autoremove\n apt-get -y autoclean\n\n cat /dev/null > /var/log/lastlog; cat /dev/null > /var/log/wtmp; cat /dev/null > /var/log/auth.log\n\n ufw enable\n ufw status\n\n touch /.cc-provisioned\n}\n\nlog_progress \"** Installing ClusterControl, this could take several minutes. Please wait ...\"\ninstall_cc\nlog_progress \"** Setting motd ...\"\nfirstboot\nlog_progress \"** Enabling firewall ...\"\nenable_fw\nif [[ \"$SSL\" == \"Yes\" ]]; then\n log_progress \"** Enabling Let's Encrypt SSL ...\"\n python --version | grep -q 3.\n [[ $? -eq 0 ]] && PYTHON3=1\n if [[ -n $PYTHON3 ]]; then\n apt install -y certbot python3-certbot-apache\n else\n apt install -y certbot python-certbot-apache\n fi\n\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\nfi\ncleanup\n\n# Clean up\nlog_progress \"** Stackscript cleanup please wait ...\"\nstackscript_cleanup\n\nlog_progress \"** Installation successful...\"\n/etc/update-motd.d/99-cc-motd | tee -a /root/cc_install.log\n\nsystemctl restart sshd", "user_defined_fields": [ { "name": "dbroot_password", "label": "MySQL Root Password" }, { "name": "cmonuser_password", "label": "CMON user password" }, { "name": "token_password", "label": "Your Linode API token. This is required in order to create DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "E-Mail Address", "example": "Your email address" }, { "name": "ssl", "label": "Would you like to use a free Let's Encrypt SSL certificate? (Uses the Linode's default rDNS if no domain is specified above)", "oneof": "Yes,No", "default": "Yes" } ] }, { "id": 401700, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "CS:GO One-Click", "description": "CS:GO - Latest One-Click", "ordinal": 24, "logo_url": "assets/CSGO2.svg", "images": [ "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 2142, "deployments_active": 7, "is_public": true, "mine": false, "created": "2019-03-08T21:06:26", "updated": "2023-11-02T20:39:58", "rev_note": "Remove SSH Pubkey UDF", "script": "#!/bin/bash\n#\n\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\nGAMESERVER=\"csgoserver\"\n\n### UDF to config\n\n#Autoteambalance\nif [[ \"$AUTOTEAMBALANCE\" = \"Enabled\" ]]; then\n AUTOTEAMBALANCE=1\nelif [[ \"$AUTOTEAMBALANCE\" = \"Disabled\" ]]; then\n AUTOTEAMBALANCE=0\nfi\n\n#Buyanywhere\nif [[ \"$BUYANYWHERE\" = \"Enabled\" ]]; then\n BUYANYWHERE=1\nelif [[ \"$BUYANYWHERE\" = \"Disabled\" ]]; then\n BUYANYWHERE=0\nelif [[ \"$BUYANYWHERE\" = \"Terrorists Only\" ]]; then\n BUYANYWHERE=2\nelif [[ \"$BUYANYWHERE\" = \"Counter-Terrorists Only\" ]]; then\n BUYANYWHERE=3\nfi\n\n#friendlyfire\n\nif [[ \"$FRIENDLYFIRE\" = \"Enabled\" ]]; then\n FRIENDLYFIRE=1\nelif [[ \"$FRIENDLYFIRE\" = \"Disabled\" ]]; then\n FRIENDLYFIRE=0\nfi\n\nset_hostname\napt_setup_update\n\n\n# CSGO specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix \\\ncurl wget file bzip2 gzip unzip bsdmainutils \\\npython util-linux ca-certificates binutils bc \\\njq tmux lib32gcc1 libstdc++6 libstdc++6:i386\n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install CSGO\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\n#Game Config Options\n\n> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\n\ncat <> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\nsv_contact \"\"\nsv_lan 0\nlog on\nsv_logbans 1\nsv_logecho 1\nsv_logfile 1\nsv_log_onefile 0\nsv_hibernate_when_empty 1\nsv_hibernate_ms 5\nhost_name_store 1\nhost_info_show 1\nhost_players_show 2\nexec banned_user.cfg\nexec banned_ip.cfg\nwriteid\nwriteip\nEND\n\necho \"mp_autoteambalance $AUTOTEAMBALANCE\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"hostname $SERVERNAME\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"mp_roundtime $ROUNDTIME\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"rcon_password \\\"$RCONPASSWORD\\\"\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"sv_password \\\"$SVPASSWORD\\\"\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\nsed -i s/mp_buy_anywhere.*/mp_buy_anywhere\\ \"$BUYANYWHERE\"/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/mp_maxrounds.*/mp_maxrounds\\ \"$MAXROUNDS\"/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/mp_friendlyfire.*/mp_friendlyfire\\ \"$FRIENDLYFIRE\"/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\necho \"$MOTD\" > /home/csgoserver/serverfiles/csgo/motd.txt\n\n\nif [[ \"$FRIENDLYFIRE\" = \"1\" ]]; then\nsed -i s/ff_damage_reduction_bullets.*/ff_damage_reduction_bullets\\ 0\\.85/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/ff_damage_reduction_gernade.*/ff_damage_reduction_gernade\\ 0\\.33/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/ff_damage_reduction_gernade_self.*/ff_damage_reduction_gernade_self\\ 0\\.4/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/ff_damage_reduction_other.*/ff_damage_reduction_other\\ 1/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\necho \"sv_kick_ban_duration 0\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"mp_disable_autokick 0\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\nfi\n\n# Start the service and setup firewall\nufw_install\nufw allow 27015\nufw allow 27020/udp\nufw allow 27005/udp\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup", "user_defined_fields": [ { "name": "gslt", "label": "Game Server Login Token", "example": "Steam gameserver token. Needed to list as public server." }, { "name": "motd", "label": "Message of the Day", "default": "Powered by Linode!" }, { "name": "servername", "label": "Server Name", "default": "Linode CS:GO Server" }, { "name": "rconpassword", "label": "RCON password" }, { "name": "svpassword", "label": "CSGO server password", "default": "" }, { "name": "autoteambalance", "label": "Team Balance Enabled", "oneof": "Enabled,Disabled", "default": "Enabled" }, { "name": "roundtime", "label": "Round Time Limit", "oneof": "5,10,15,20,60", "default": "5" }, { "name": "maxrounds", "label": "Maximum Rounds", "oneof": "1,5,10,15,20", "default": "10" }, { "name": "buyanywhere", "label": "Buy Anywhere ", "oneof": "Disabled,Enabled,Counter-Terrorists Only, Terrorists Only", "default": "Disabled" }, { "name": "friendlyfire", "label": "Friendly Fire Enabled", "oneof": "Enabled,Disabled", "default": "Disabled" } ] }, { "id": 688891, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Discourse One-Click", "description": "Discourse One-Click", "ordinal": 25, "logo_url": "assets/discourse.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 1210, "deployments_active": 59, "is_public": true, "mine": false, "created": "2020-11-17T20:55:26", "updated": "2023-12-06T22:46:13", "rev_note": "", "script": "#!/bin/bash\n\n## Discourse Settings\n\n#\n#\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n# This also sets some useful variables, like $IP and $FQDN\nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -xo pipefail\n\n#Install dependencies needed for Discourse\napt install git apt-transport-https ca-certificates curl software-properties-common net-tools -y\n\n#Clone Discourse Docker repo for install and management\ngit clone https://github.com/discourse/discourse_docker.git /var/discourse\n#UFW Firewall Rules\nufw allow http\nufw allow https\nufw allow 25\nufw allow 465\nufw allow 587\nufw enable <\n#\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Python & Django\napt-get install -y python3 python3-pip\npip3 install Django\n\n# Create & Setup Django APP\nmkdir /var/www/\ncd /var/www/\ndjango-admin startproject DjangoApp\ncd DjangoApp\npython3 manage.py migrate\necho \"from django.contrib.auth.models import User; User.objects.create_superuser('$DJANGOUSER', '$DJANGOUSEREMAIL', '$DJANGOUSERPASSWORD')\" | python3 manage.py shell\nsed -i \"s/ALLOWED_HOSTS = \\[\\]/ALLOWED_HOSTS = \\['$IP'\\]/g\" DjangoApp/settings.py\npython3 manage.py runserver 0.0.0.0:8000 &\n\n# Start Django app on reboot\ncrontab -l | { cat; echo \"@reboot cd /var/www/DjangoApp && python3 manage.py runserver 0.0.0.0:8000 &\"; } | crontab -\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "djangouser", "label": "Django USER", "example": "user1" }, { "name": "djangouserpassword", "label": "Django Password", "example": "s3cure_p4ssw0rd" }, { "name": "djangouseremail", "label": "Django USER email", "example": "user@email.tld" } ] }, { "id": 607433, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Docker One-Click", "description": "Docker One Click App", "ordinal": 27, "logo_url": "assets/docker.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 35968, "deployments_active": 1827, "is_public": true, "mine": false, "created": "2019-10-31T20:14:04", "updated": "2023-12-07T16:45:49", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Docker Settings\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-docker\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n else echo \"No email entered\";\n fi\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "SOA Email", "example": "user@domain.tld", "default": "" } ] }, { "id": 401698, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Drupal One-Click", "description": "Drupal One-Click", "ordinal": 28, "logo_url": "assets/Drupal.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 1845, "deployments_active": 80, "is_public": true, "mine": false, "created": "2019-03-08T21:04:47", "updated": "2023-12-03T23:12:19", "rev_note": "", "script": "#!/usr/bin/env bash\n## Drupal Settings\n# \n# \n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Set hostname, apt configuration and update/upgrade\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Install/configure UFW\nufw allow http\nufw allow https\n\n# Install/configure MySQL\napt-get install mariadb-server -y\nsystemctl start mariadb\nsystemctl enable mariadb\nmysql_root_preinstall\nrun_mysql_secure_installation\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"CREATE DATABASE drupaldb\"\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"GRANT ALL ON drupaldb.* TO 'drupal'@'localhost' IDENTIFIED BY '$DB_PASSWORD'\";\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"FLUSH PRIVILEGES\";\n\n# Install & Configure Apache\napt-get install -y apache2\ntouch /var/log/apache2/drupal-error_log /var/log/apache2/drupal-access_log\ncp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/drupal.conf\ncat < /etc/apache2/sites-available/drupal.conf\n\n DocumentRoot /var/www/drupal\n ServerName $FQDN\n ServerAlias www.$FQDN\n \n Options FollowSymLinks\n AllowOverride All\n Order allow,deny\n allow from all\n RewriteEngine on\n RewriteBase /\n RewriteCond %{REQUEST_FILENAME} !-f\n RewriteCond %{REQUEST_FILENAME} !-d\n RewriteCond %{REQUEST_URI} !=/favicon.ico\n RewriteRule ^ index.php [L]\n\n ErrorLog /var/log/apache2/drupal-error_log\n CustomLog /var/log/apache2/drupal-access_log common\n\nEND\na2enmod rewrite\na2dissite 000-default.conf\na2ensite drupal.conf\nsed -ie \"s/KeepAlive Off/KeepAlive On/g\" /etc/apache2/apache2.conf\nsystemctl restart apache2\nsystemctl enable apache2\n\n# Install PHP 8.1\napt-get install php libapache2-mod-php php-mysql php-curl php-cgi php-gd php-mbstring php-xml php-xmlrpc -y\nPHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\ncat < /etc/php/$PHP_VERSION/apache2/php.ini\nerror_reporting = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR\nerror_log = /var/log/php/error.log\nmax_input_time = 30\nEND\nmkdir /var/log/php\nchown www-data /var/log/php\n\n# Install Drupal\nrm -r /var/www/html\ncd ~; wget -4 https://www.drupal.org/download-latest/tar.gz\ntar -xf tar.gz -C /var/www/ && mv /var/www/drupal* /var/www/drupal\nrm tar.gz\nmkdir /var/www/drupal/sites/default/files\nchmod a+w /var/www/drupal/sites/default/files\ncp /var/www/drupal/sites/default/default.settings.php /var/www/drupal/sites/default/settings.php\nchmod a+w /var/www/drupal/sites/default/settings.php\ncat <> /var/www/drupal/sites/default/settings.php\n\\$settings['trusted_host_patterns'] = [\n '^$FQDN\\$',\n];\nEND\n\n# Cleanup\nsystemctl restart apache2\nsystemctl restart mysql\n\n# SSL\napt install certbot python3-certbot-apache -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "E-Mail Address", "example": "Your email address" }, { "name": "dbroot_password", "label": "MySQL root Password", "example": "an0th3r_s3cure_p4ssw0rd" }, { "name": "db_password", "label": "Database Password", "example": "an0th3r_s3cure_p4ssw0rd" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Drupal server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 1008125, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Easypanel One-Click", "description": "Easypanel One-Click", "ordinal": 29, "logo_url": "assets/easypanel.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 1417, "deployments_active": 79, "is_public": true, "mine": false, "created": "2022-05-18T16:43:00", "updated": "2023-12-07T05:58:49", "rev_note": "", "script": "#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# install docker\ncurl -fsSL https://get.docker.com -o get-docker.sh\nsh get-docker.sh\n\n# setup easypanel\ndocker run --rm \\\n -v /etc/easypanel:/etc/easypanel \\\n -v /var/run/docker.sock:/var/run/docker.sock:ro \\\n easypanel/easypanel setup", "user_defined_fields": [] }, { "id": 691620, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "FileCloud One-Click", "description": "FileCloud One-Click", "ordinal": 30, "logo_url": "assets/filecloud.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 782, "deployments_active": 14, "is_public": true, "mine": false, "created": "2020-11-30T21:16:19", "updated": "2023-12-07T16:35:31", "rev_note": "", "script": "#!/bin/bash \n\n## Domain Settings\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source and run the New Linode Setup script for DNS configuration\n# This also sets some useful variables, like $IP and $FQDN\n\nsource \n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nset pipefail -o\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Allow traffic on ports 80 and 443\nufw allow 80\nufw allow 443\n\n# Installing Filecloud and Prequisites\nwget -qO - https://repo.filecloudlabs.com/static/pgp/filecloud.asc | sudo apt-key add -\nwget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -\necho \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list\necho \"deb [ arch=amd64 ] https://repo.filecloudlabs.com/apt/ubuntu focal/filecloud/22.1 main\" | sudo tee /etc/apt/sources.list.d/filecloud.list\napt-get update -y\napt-get install apache2 mongodb-org -y\napt install -y --no-install-recommends php8.1*\nACCEPT_EULA=Y apt-get install filecloud -y\n\nif [[ \"$SSL\" == \"Yes\" ]]; then\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\nfi\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "token_password", "label": "Your Linode API token. This is required in order to create DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "ssl", "label": "Would you like to use a free CertBot SSL certificate?", "oneof": "Yes,No", "default": "No" }, { "name": "soa_email_address", "label": "Email Address for Lets' Encrypt Certificate", "default": "" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 609392, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Flask One-Click", "description": "Flask One-Click", "ordinal": 31, "logo_url": "assets/flask.svg", "images": [ "linode/debian10" ], "deployments_total": 2160, "deployments_active": 134, "is_public": true, "mine": false, "created": "2019-11-07T06:24:17", "updated": "2023-12-07T15:54:26", "rev_note": "Initial import", "script": "#!/bin/bash\n\n## Enable logging\nexec > /var/log/stackscript.log 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\nufw_install\nufw allow http\n\n# Install Prereq's & Flask APP\napt install -y git\ncd /home\ngit clone https://github.com/abalarin/Flask-on-Linode.git flask_app_project\n\n# Install & configure Nginx\napt install -y nginx\ncat < /etc/nginx/sites-enabled/flask_app\nserver {\n listen 80;\n server_name $IP;\n location / {\n proxy_pass http://127.0.0.1:8000;\n proxy_set_header Host \\$host;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n }\n}\nEND\n\nunlink /etc/nginx/sites-enabled/default\nnginx -s reload\n\n# Install python & Packages\napt install -y python3 python3-pip\ncd /home/flask_app_project\npip3 install -r flask_app/requirements.txt\n\n# Configure Flask\ncat < /etc/config.json\n{\n \"SECRET_KEY\": \"$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)\",\n \"SQLALCHEMY_DATABASE_URI\": \"sqlite:///site.db\"\n}\nEND\n\ncat < /home/flask_app_project/flask_app/__init__.py\nfrom flask import Flask\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_login import LoginManager\nimport json\nimport urllib3\napp = Flask(__name__)\nwith open('/etc/config.json') as config_file:\n config = json.load(config_file)\napp.config['SECRET_KEY'] = config.get('SECRET_KEY')\napp.config['SQLALCHEMY_DATABASE_URI'] = config.get('SQLALCHEMY_DATABASE_URI')\ndb = SQLAlchemy(app)\nlogin_manager = LoginManager()\nlogin_manager.init_app(app)\nfrom flask_app import routes\nEND\n\n# Install and Configure Gunicorn\napt install -y gunicorn3\ngunicorn3 --workers=3 flask_app:app &\n\n# Install and Configure Supervisor\napt install -y supervisor\ncat < /etc/supervisor/conf.d/flask_app.conf\n[program:flask_app]\ndirectory=/home/flask_app_project\ncommand=gunicorn3 --workers=3 flask_app:app\nautostart=true\nautorestart=true\nstopasgroup=true\nkillasgroup=true\nstderr_logfile=/var/log/flask_app/flask_app.err.log\nstdout_logfile=/var/log/flask_app/flask_app.out.log\nEND\n\nmkdir /var/log/flask_app\ntouch /var/log/flask_app/flask_app.out.log\ntouch /var/log/flask_app/flask_app.err.log\nsupervisorctl reload\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [] }, { "id": 971045, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Focalboard One-Click", "description": "Focalboard One-Click", "ordinal": 32, "logo_url": "assets/focalboard.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 476, "deployments_active": 19, "is_public": true, "mine": false, "created": "2022-02-08T16:23:08", "updated": "2023-12-06T21:12:26", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Focalboard Settings \n#\n\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-focalboard\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n #Focalboard vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" } ] }, { "id": 1088136, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Galera Cluster One-Click", "description": "Galera Cluster One-Click", "ordinal": 33, "logo_url": "assets/galeramarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 128, "deployments_active": 8, "is_public": true, "mine": false, "created": "2022-11-15T20:41:27", "updated": "2023-12-01T14:46:14", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/galera-occ\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/galera-occ\" ]; then\n rm -rf /tmp/galera-occ\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[+] Linode private IP present\"\n else\n echo \"[!] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[+] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction setup {\n export DEBIAN_FRONTEND=non-interactive\n # install dependancies\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n if [ ! -d ~/.ssh ]; then \n mkdir ~/.ssh\n else \n echo \".ssh directory is already created\"\n fi\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # add private IP address\n rename_provisioner\n configure_privateip \n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/galera-occ\n cd /tmp/galera-occ/\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip3 install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"", "user_defined_fields": [ { "name": "cluster_name", "label": "Cluster Name" }, { "name": "token_password", "label": "Your Linode API token" }, { "name": "add_ssh_keys", "label": "Add Account SSH Keys to All Nodes?", "oneof": "yes,no" }, { "name": "sslheader", "label": "SSL Information", "header": "Yes", "default": "Yes", "required": "Yes" }, { "name": "country_name", "label": "Details for self-signed SSL certificates: Country or Region", "oneof": "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW" }, { "name": "state_or_province_name", "label": "State or Province", "example": "Example: Pennsylvania" }, { "name": "locality_name", "label": "Locality", "example": "Example: Philadelphia" }, { "name": "organization_name", "label": "Organization", "example": "Example: Akamai Technologies" }, { "name": "email_address", "label": "Email Address", "example": "Example: user@domain.tld" }, { "name": "ca_common_name", "label": "CA Common Name", "default": "Galera CA" }, { "name": "common_name", "label": "Common Name", "default": "Galera Server" }, { "name": "cluster_size", "label": "Galera cluster size", "default": "3", "oneof": "3" } ] }, { "id": 688911, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Gitea One-Click", "description": "Gitea One-Click", "ordinal": 34, "logo_url": "assets/gitea.svg", "images": [ "linode/debian10" ], "deployments_total": 1007, "deployments_active": 66, "is_public": true, "mine": false, "created": "2020-11-17T21:16:09", "updated": "2023-12-03T12:37:42", "rev_note": "", "script": "#! /bin/bash\n\n## Database Settings\n#\n#\n\n## User and SSH Security\n#\n#\n#\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n#assigns var for IP address\nreadonly ip=$(hostname -I | awk '{print$1}')\n\n#intall git\napt install -y git\n\n#install nginx\napt install -y nginx\n\n#install mysql and secure\nmysql_root_preinstall\napt-get install -y mariadb-server\nsystemctl start mariadb\nsystemctl enable mariadb\nrun_mysql_secure_installation\n\n#create mysql db and user\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"CREATE DATABASE gitea;\"\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"CREATE USER 'gitea'@'localhost' IDENTIFIED BY '$(printf '%q' \"$DB_PASSWORD\")';\"\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost' WITH GRANT OPTION;\"\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"FLUSH PRIVILEGES;\"\n\n#create user for gitea\nadduser --system --disabled-password --group --shell /bin/bash --gecos 'Git Version Control' --home /home/git git\n\n#create directories for gitea\nmkdir -p /var/lib/gitea/{custom,data,log}\nchown -R git:git /var/lib/gitea/\nchmod -R 750 /var/lib/gitea/\nmkdir /etc/gitea\nchown root:git /etc/gitea\nchmod 770 /etc/gitea\n\n#pull down gitea binary\nwget -O gitea https://dl.gitea.io/gitea/1.13.0/gitea-1.13.0-linux-amd64\nchmod +x gitea\n\n#validate gpg\napt install gnupg -y\ngpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2\ngpg --verify gitea-1.13.0-linux-amd64.asc gitea-1.13.0-linux-amd64\n\n#copy gitea to global location\ncp gitea /usr/local/bin/gitea\n\n#download systemd file from gitea\nwget https://raw.githubusercontent.com/go-gitea/gitea/master/contrib/systemd/gitea.service -P /etc/systemd/system/\n\n#add requires mysql to the systemd file\nsed -i 's/#Requires=mariadb.service/Requires=mariadb.service/' /etc/systemd/system/gitea.service\n\n#start gitea as systemd service\nsystemctl daemon-reload\nsystemctl start gitea\nsystemctl enable gitea\n\n#configures ufw rules before nginx\nsystemctl start ufw\nufw allow http\nufw allow https\nufw enable\n\n#set absolute domain if any, otherwise use localhost\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=localhost\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\n#configure nginx reverse proxy\nrm /etc/nginx/sites-enabled/default\ntouch /etc/nginx/sites-available/reverse-proxy.conf\ncat < /etc/nginx/sites-available/reverse-proxy.conf\nserver {\n listen 80;\n listen [::]:80;\n server_name ${ABS_DOMAIN};\n\n access_log /var/log/nginx/reverse-access.log;\n error_log /var/log/nginx/reverse-error.log;\n\n location / {\n proxy_pass http://localhost:3000;\n }\n}\nEND\nln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/reverse-proxy.conf\n\n#enable and start nginx\nsystemctl enable nginx\nsystemctl restart nginx\n\nsleep 60\n\n#sets certbot ssl\nif [[ $SSL = \"Yes\" ]]; then\n check_dns_propagation ${ABS_DOMAIN} ${ip}\n apt install python3-certbot-nginx -y\n certbot run --non-interactive --nginx --agree-tos --redirect -d ${ABS_DOMAIN} -m ${EMAIL_ADDRESS} -w /var/www/html/\nfi\n\nstackscript_cleanup", "user_defined_fields": [ { "name": "dbroot_password", "label": "MySQL root Password" }, { "name": "db_password", "label": "gitea Database Password" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "pwless_sudo", "label": "Enable passwordless sudo access for the limited user?", "oneof": "Yes,No", "default": "No" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "auto_updates", "label": "Configure automatic security updates?", "oneof": "Yes,No", "default": "No" }, { "name": "fail2ban", "label": "Use fail2ban to prevent automated instrusion attempts?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for your server (Domain required)", "default": "" }, { "name": "domain", "label": "Your domain (API Token required)", "default": "" }, { "name": "soa_email_address", "label": "SOA Email for your domain (Required for new domains)", "default": "" }, { "name": "mx", "label": "Do you need an MX record for this domain? (Yes if sending mail from this Linode)", "oneof": "Yes,No", "default": "No" }, { "name": "spf", "label": "Do you need an SPF record for this domain? (Yes if sending mail from this Linode)", "oneof": "Yes,No", "default": "No" }, { "name": "ssl", "label": "Would you like to use a free Let's Encrypt SSL certificate for your domain?", "oneof": "Yes,No", "default": "No" }, { "name": "email_address", "label": "Admin Email for Let's Encrypt certificate", "default": "" } ] }, { "id": 401707, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "GitLab One-Click", "description": "GitLab One-Click", "ordinal": 35, "logo_url": "assets/GitLab.svg", "images": [ "linode/ubuntu20.04", "linode/debian11" ], "deployments_total": 3265, "deployments_active": 136, "is_public": true, "mine": false, "created": "2019-03-08T21:12:21", "updated": "2023-12-07T15:03:39", "rev_note": "Remove SSH Pubkey UDF", "script": "#!/usr/bin/env bash\n\n## Gitlab Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction gitlab {\n # Install dependencies\n apt-get install curl ca-certificates apt-transport-https gnupg2 -y\n\n curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | bash\n apt-get update -y\n EXTERNAL_URL=\"https://$FQDN\" apt-get install gitlab-ce -y\n\n}\n\nfunction sslgitlab {\n # Taking advantage of Gitlab's Let's Encrypt cert capabilities\n sed -i \"s/# letsencrypt\\['enable'\\] = nil/letsencrypt\\['enable'\\] = true/g\" /etc/gitlab/gitlab.rb\n sed -i -E \"s/(# )(letsencrypt\\['auto_renew*)/\\2/g\" /etc/gitlab/gitlab.rb\n sed -i \"s/letsencrypt['auto_renew_minute'] = nil/letsencrypt['auto_renew_minute'] = 0/g\" /etc/gitlab/gitlab.rb\n sed -i \"s/# letsencrypt\\['contact_emails'\\] = \\[\\]/letsencrypt\\['contact_emails'\\] = \\['$SOA_EMAIL_ADDRESS']/g\" /etc/gitlab/gitlab.rb\n\n gitlab-ctl reconfigure\n}\n\nfunction firewallgitlab {\n ufw allow http\n ufw allow https\n}\n\nfunction main {\n gitlab\n firewallgitlab\n sslgitlab\n}\n\n# Execute Script\nmain\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "This is the Email address for the LetsEncrypt SSL Certificate", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Gitlab server's DNS records", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" } ] }, { "id": 1102905, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Gopaddle One-Click", "description": "Gopaddle One-Click app", "ordinal": 36, "logo_url": "assets/gopaddle.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 45, "deployments_active": 2, "is_public": true, "mine": false, "created": "2022-12-20T17:44:47", "updated": "2023-11-09T11:24:37", "rev_note": "", "script": "#!/bin/bash\nexec >/var/log/stackscript.log 2>&1\n# Install Docker\napt-get update -y\napt-get install -y ca-certificates curl gnupg lsb-release\nmkdir -p /etc/apt/keyrings\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\necho \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\napt-get update -y\nchmod a+r /etc/apt/keyrings/docker.gpg\napt-get update -y\napt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin\n\n# Install microk8s\napt-get install snapd -y \nsudo snap install core\nexport PATH=$PATH:/snap/bin\nsnap install microk8s --classic --channel=1.25\nsnap refresh microk8s --channel=1.25\nmicrok8s status --wait-ready\n\n\n# Install gopaddle\nmicrok8s addons repo add gp-lite https://github.com/gopaddle-io/microk8s-community-addons-gplite.git\nmicrok8s enable gopaddle-lite\n\necho Waiting for gopaddle services to move to running state ...\nmicrok8s.kubectl wait --for=condition=ready pod -l released-by=gopaddle -n gp-lite --timeout=15m\n\nRDNS=$(dnsdomainname -A | awk '{print $1}')\n\necho gopaddle-lite installation is complete ! You can now access the gopaddle dashboard @ http://$RDNS:30003/", "user_defined_fields": [] }, { "id": 607256, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Grafana One-Click", "description": "Grafana One Click App", "ordinal": 37, "logo_url": "assets/grafana.svg", "images": [ "linode/debian11" ], "deployments_total": 832, "deployments_active": 57, "is_public": true, "mine": false, "created": "2019-10-30T20:43:07", "updated": "2023-12-06T22:21:38", "rev_note": "", "script": "#!/usr/bin/env bash\n\n### Grafana OCA\n\n## Grafana Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n# Source the Bash StackScript Library\nsource \n\n# Source and run the New Linode Setup script for SSH configuration\nsource \n\n# Install PreReqs\napt-get install -y apt-transport-https \\\nsoftware-properties-common \\\nwget \\\ngnupg2 \\\nsqlite3\n\nwget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key\necho \"deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main\" | sudo tee -a /etc/apt/sources.list.d/grafana.list\napt-get -y update\napt-get -y install grafana\nsystemctl start grafana-server\nsystemctl enable grafana-server\n\n## reset Grafana admin password\n#grafana-cli --homepath \"/usr/share/grafana\" admin reset-admin-password $grafana_password. --not working -hmorris\necho \"Initializing DB.....\" && sleep 25\nsqlite3 /var/lib/grafana/grafana.db <\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction grav {\n apt-get install -y apache2 php libapache2-mod-php php-mysql mysql-server composer php-curl php-common php-gd php-json php-mbstring php-xml php-zip\n run_mysql_secure_installation_ubuntu20\n cd /var/www/html\n git clone https://github.com/getgrav/grav.git\n cd grav\n chown www-data:www-data -R .\n su -l www-data -s /bin/bash -c \"cd /var/www/html/grav && composer install --no-dev -o && bin/grav install && bin/gpm install admin\"\n chown www-data:www-data -R .\n}\n\nfunction apache_conf {\n cat < /etc/apache2/sites-available/grav.conf\n\nServerAdmin $SOA_EMAIL_ADDRESS\nDocumentRoot /var/www/html/grav/\nServerName $FQDN\nServerAlias www.$FQDN\n\nOptions FollowSymLinks\nAllowOverride All\nOrder allow,deny\nallow from all\n\nErrorLog /var/log/apache2/$FQDN-error_log\nCustomLog /var/log/apache2/$FQDN-access_log common\n\n\nEND\n a2enmod rewrite\n a2ensite grav.conf\n a2dissite 000-default.conf\n service apache2 restart\n}\n\nfunction ssl {\n apt install certbot python3-certbot-apache -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n}\nfunction firewall {\n ufw allow http\n ufw allow https\n}\n\nfunction main {\n firewall\n grav\n apache_conf\n ssl\n\n}\n\n\n# execute script\nmain\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "This is the Email address for the LetsEncrypt SSL Certificate", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 688914, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Guacamole One-Click", "description": "Guacamole One-Click", "ordinal": 39, "logo_url": "assets/guacamole.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 4452, "deployments_active": 63, "is_public": true, "mine": false, "created": "2020-11-17T21:28:05", "updated": "2023-12-05T22:38:27", "rev_note": "", "script": "#!/usr/bin/env bash\n### Apache Guacamole OCA\n### Required UDFs\n## Guacamole Settings\n#\n#\n#\n#\n#\n### Optional UDFs\n## Linode/SSH Security Settings\n#\n#\n## Domain Settings\n#\n#\n#\n## Logging and other debugging helpers\n# Put bash into verbose mode\nset -o pipefail\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Imports\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n### Main Script\n## Open the needed firewall ports\nufw allow http\nufw allow https\n# Install dependencies\nsystem_install_package build-essential libcairo2-dev libpng-dev libtool-bin libossp-uuid-dev libvncserver-dev freerdp2-dev libssh2-1-dev \\\nlibtelnet-dev libwebsockets-dev libpulse-dev libvorbis-dev libwebp-dev \\\nlibssl-dev libpango1.0-dev libswscale-dev libavcodec-dev libavutil-dev \\\nlibavformat-dev\n# Download the Guacamole Server source code\n# Fetch the latest release page\nlatest_release_page=$(curl -sL https://guacamole.apache.org/releases/ | grep -m 1 -o 'href=\"/releases/[0-9.]\\+/\"')\n# Extract the version number from the release page URL\nlatest_version=$(echo $latest_release_page | grep -Eo '[0-9]\\.[0-9]+.[0-9]+')\n# Download the server component\nwget https://downloads.apache.org/guacamole/$latest_version/source/guacamole-server-$latest_version.tar.gz\ntar -xvf guacamole-server-$latest_version.tar.gz\ncd guacamole-server-$latest_version\n# Build Guacamole Server using the downloaded source code\n./configure --with-init-dir=/etc/init.d --enable-allow-freerdp-snapshots\nmake\nmake install\n# Update installed library cache and reload systemd\nldconfig\nsystemctl daemon-reload\n# Start guacd\nsystemctl enable guacd\n## Install Guacamole Web App\n# Install Apache Tomcat\nsystem_install_package tomcat9 tomcat9-admin tomcat9-common tomcat9-user\n# Download and install the Guacamole Client\nwget https://downloads.apache.org/guacamole/$latest_version/binary/guacamole-$latest_version.war\nmv guacamole-$latest_version.war /var/lib/tomcat9/webapps/guacamole.war\nsystemctl restart tomcat9 guacd\n## Guacamole configs\nmkdir /etc/guacamole\nreadonly ENCRYPTED_GUACAMOLE_PASSWORD=\"$(echo -n \"$GUACAMOLE_PASSWORD\" | openssl md5 | awk '{print $2}')\"\ncat <> /etc/guacamole/user-mapping.xml\n\n \n \n \n \n vnc\n localhost\n 5901\n ${PASSWORD}\n \n \n\nEOF\ncat <> /etc/guacamole/guacd.conf\n[daemon]\npid_file = /var/run/guacd.pid\n#log_level = debug\n[server]\nbind_host = 127.0.0.1\nbind_port = 4822\nEOF\ncat <> /etc/guacamole/guacamole.properties\n# Hostname and port of guacamole proxy\nguacd-hostname: localhost\nguacd-port: 4822\nEOF\nsystemctl restart tomcat9 guacd\n## Install a desktop environment (XFCE) and VNC Server\n# Install XFCE & NVC\nsystem_install_package xfce4 xfce4-goodies tigervnc-standalone-server expect\n# Set the VNC Server password\nreadonly VNCSERVER_SET_PASSWORD=$(expect -c \"\nspawn sudo -u $USERNAME vncserver\nexpect \\\"Password:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Verify:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Would you like to enter a view-only password (y/n)?\\\"\nsend \\\"n\\r\\\"\nexpect eof\n\")\necho \"$VNCSERVER_SET_PASSWORD\"\nsystemctl restart tomcat9 guacd\nkillvncprocess=$(ps aux | grep \"/usr/bin/Xtigervnc :1 -localhost=1 -desktop\" | head -n 1 | awk '{ print $2; }')\nkill $killvncprocess\n# Create a systemd service for Tiger VNC\ntouch /etc/systemd/system/vncserver@.service\ncat < /etc/systemd/system/vncserver@.service\n[Unit]\nDescription=a wrapper to launch an X server for VNC\nAfter=syslog.target network.target\n[Service]\nType=forking\nUser=$USERNAME\nGroup=$USERNAME\nWorkingDirectory=/home/$USERNAME\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver -depth 24 -geometry 1280x800 -localhost :%i\nExecStop=/usr/bin/vncserver -kill :%i\n[Install]\nWantedBy=multi-user.target\nEOF\n# Start and enable the systemd service\nsystemctl start vncserver@1.service\nsystemctl enable vncserver@1.service\n## Reverse proxy for the Guacamole client\n# Install Apache\napache_install\na2enmod proxy proxy_http headers proxy_wstunnel\n# Create the VirtualHost for Guacamole\ncat < /etc/apache2/sites-available/guacamole.conf\n\n ServerName $FQDN\n ErrorLog ${APACHE_LOG_DIR}/guacamole_error.log\n CustomLog ${APACHE_LOG_DIR}/guacamole_access.log combined\n \n Require all granted\n ProxyPass http://localhost:8080/guacamole/ flushpackets=on\n ProxyPassReverse http://localhost:8080/guacamole/\n \n \n Require all granted\n ProxyPass ws://localhost:8080/guacamole/websocket-tunnel\n ProxyPassReverse ws://localhost:8080/guacamole/websocket-tunnel\n \n Header always unset X-Frame-Options\n\nEOF\n# Enable the VirtualHost\na2ensite guacamole.conf\nsystemctl restart apache2\n## HTTPS\nsystem_install_package python3-certbot-apache\ncertbot -n --apache --agree-tos --redirect --hsts --staple-ocsp --email \"$SOA_EMAIL_ADDRESS\" -d \"$FQDN\" \n## Cleanup after ourselves\nstackscript_cleanup\nreboot", "user_defined_fields": [ { "name": "username", "label": "The limited sudo/VNC user to be created for the Linode" }, { "name": "password", "label": "The password for the limited sudo/VNC user" }, { "name": "guacamole_user", "label": "The username to be used with Guacamole" }, { "name": "guacamole_password", "label": "The password to be used with Guacamole" }, { "name": "soa_email_address", "label": "Email for SSL certificate" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is required if filling out any of the domain-related fields.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record", "default": "" } ] }, { "id": 1102902, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "HaltDOS Community WAF One-Click", "description": "HaltDOS Community WAF One-Click app", "ordinal": 40, "logo_url": "assets/haltdos.svg", "images": [ "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 174, "deployments_active": 8, "is_public": true, "mine": false, "created": "2022-12-20T17:34:20", "updated": "2023-12-07T12:34:52", "rev_note": "", "script": "#!/bin/bash\n\nset -x\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\necho -e \"\\n---------------HALTDOS COMMUNITY WAF SETUP---------------\"\n\nexport NEEDRESTART_SUSPEND=1\nip=`ip route get 8.8.8.8 | awk -F\"src \" 'NR==1{split($2,a,\" \");print a[1]}'`\necho -e \"Checking OS ...\"\nsource /etc/os-release > /dev/null 2>&1\narch=`uname -m`\nif [[ \"$ID\" == \"ubuntu\" || \"$ID\" == \"debian\" ]]; then\n if [[ \"$VERSION_ID\" == \"18.04\" || \"$VERSION_ID\" == \"20.04\" || \"$VERSION_ID\" == \"22.04\" || \"$VERSION_ID\" == \"11\" ]]; then\n if [ \"$arch\" != \"x86_64\" ]; then\n echo -e \"\\e[1;31m$arch is not yet supported. Supported System Architecture - x86_64 \\e[0m\"\n fi\n else\n echo -e \"\\e[1;31mThis OS is not yet supported. Supported OS - Ubuntu 18.04, 20.04, 22.04 and Debian 11 \\e[0m\"\n exit 1\n fi\nelse\n echo -e \"\\e[1;31mThis OS is not yet supported. Supported Versions - Ubuntu 18.04, 20.04, 22.04 and Debian 11 \\e[0m\"\n exit 1\nfi\n\necho -e \"Downloading dependencies ...\"\n\napt-get update &> /dev/null\n\napt-get install -y default-jdk default-jre &> /dev/null\necho \"JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/\" >> /etc/environment\nsource /etc/environment\n\necho -e \"Downloading latest binaries ...\"\n\nsource /etc/os-release > /dev/null 2>&1\nif [ \"$VERSION_ID\" == \"18.04\" ]; then\n apt-get install -y libmaxminddb-dev python-dev python &> /dev/null \n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/ubuntu-18/hd-community-waf-x86_64.deb &> /dev/null\nelif [ \"$VERSION_ID\" == \"20.04\" ]; then\n apt-get install -y libmaxminddb-dev python-dev python &> /dev/null\n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/ubuntu-20/hd-community-waf-x86_64.deb &> /dev/null\nelif [ \"$VERSION_ID\" == \"22.04\" ]; then\n apt-get install -y libmaxminddb-dev libmaxminddb0 mmdb-bin python2-dev python2 &> /dev/null\n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/ubuntu-22/hd-community-waf-x86_64.deb &> /dev/null\nelif [[ \"$ID\" == \"debian\" && \"$VERSION_ID\" == \"11\" ]]; then\n apt-get install -y sudo libmaxminddb-dev python-dev python &> /dev/null\n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/debian-11/hd-community-waf-x86_64.deb &> /dev/null\nfi\n\napt-get install -y ./hd-community-waf.deb &> /dev/null\nrm hd-community-waf.deb\necho -e \"Haltdos Community WAF Installed\"\n\n\ncurl -s -k -o hd-community-controller.deb https://binary.haltdos.com/community/waf/gui/hd-community-controller-x86_64.deb &> /dev/null\napt-get install -y ./hd-community-controller.deb &> /dev/null\nrm hd-community-controller.deb\necho -e \"Haltdos Community Controller Installed\"\n\n\necho -e \"Haltdos Community WAF Setup Done\\n\"\necho -e \"Configure your WAF on https://$ip:9000\\n\"\nexport NEEDRESTART_SUSPEND=0", "user_defined_fields": [] }, { "id": 912262, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Harbor One-Click", "description": "Harbor One-Click", "ordinal": 41, "logo_url": "assets/harbor.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 288, "deployments_active": 15, "is_public": true, "mine": false, "created": "2021-09-29T17:06:13", "updated": "2023-12-07T16:41:14", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## harbor Settings \n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-harbor\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # harbor vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Admin Email for the Harbor server and Let's Encrypt SSL certificate" } ] }, { "id": 1037037, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "HashiCorp Nomad One-Click", "description": "HashiCorp Nomad One Click App", "ordinal": 42, "logo_url": "assets/nomad.svg", "images": [ "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 104, "deployments_active": 3, "is_public": true, "mine": false, "created": "2022-08-02T18:46:19", "updated": "2023-11-29T11:13:20", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## set some variables\nexport NOMAD_DIR=/usr/bin\nexport NOMAD_PATH=${NOMAD_DIR}/nomad\nexport NOMAD_CONFIG_DIR=/etc/nomad.d\nexport NOMAD_DATA_DIR=/opt/nomad/data\nexport NOMAD_TLS_DIR=/opt/nomad/tls\nexport NOMAD_ENV_VARS=${NOMAD_CONFIG_DIR}/nomad.conf\nexport IP=$(hostname -I | awk '{print$1}')\n\n\n## install gpg\napt-get install -y gpg\n\n## Install Nomad\nwget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg\necho \"deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/hashicorp.list\nsudo apt update -y && sudo apt install -y nomad\n\n#echo \"Start Nomad in -server mode\"\nsudo tee ${NOMAD_ENV_VARS} > /dev/null < ${NOMAD_ENV_VARS}\n[Unit]\nDescription=Nomad Agent\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nRestart=on-failure\nEnvironmentFile=/etc/nomad.d/nomad.conf\nExecStart=/usr/local/bin/nomad agent -config /etc/nomad.d $FLAGS\nExecReload=/bin/kill -HUP $MAINPID\nKillSignal=SIGTERM\nUser=root\nGroup=root\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\n## enable and start nomad\nsystemctl enable nomad\nsystemctl start nomad\n\n## Install Docker\ncurl -fsSL get.docker.com | sudo sh\n\n## Configure nginx container\ncat << EOF > /root/nginx.conf\nevents {}\n\nhttp {\n server {\n location / {\n proxy_pass http://nomad-ws;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n\n # Nomad blocking queries will remain open for a default of 5 minutes.\n # Increase the proxy timeout to accommodate this timeout with an\n # additional grace period.\n proxy_read_timeout 310s;\n\n # Nomad log streaming uses streaming HTTP requests. In order to\n # synchronously stream logs from Nomad to NGINX to the browser\n # proxy buffering needs to be turned off.\n proxy_buffering off;\n\n # The Upgrade and Connection headers are used to establish\n # a WebSockets connection.\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection \"upgrade\";\n\n # The default Origin header will be the proxy address, which\n # will be rejected by Nomad. It must be rewritten to be the\n # host address instead.\n proxy_set_header Origin \"\\${scheme}://\\${proxy_host}\";\n }\n }\n\n # Since WebSockets are stateful connections but Nomad has multiple\n # server nodes, an upstream with ip_hash declared is required to ensure\n # that connections are always proxied to the same server node when possible.\n upstream nomad-ws {\n ip_hash;\n server host.docker.internal:4646;\n }\n}\nEOF\n\n## start docker container\ndocker run -d --publish=8080:80 --add-host=host.docker.internal:host-gateway \\\n --mount type=bind,source=$PWD/nginx.conf,target=/etc/nginx/nginx.conf \\\n nginx:latest\n\n## firewall\nufw allow 22\nufw allow 80\nufw allow 443\nufw allow 4646\nufw allow 8080\n\ncat << EOF > /etc/motd\n#################################\n The Nomad GUI is now available at HTTP://${IP}:8080\n\n This is a minimal installation with limited configurations.\n Please review configurations before using this application in production.\n\n Information on Nomad configurations at https://www.nomadproject.io/docs/configuration\n#################################\nEOF\n\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 1226544, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "HashiCorp Nomad Cluster One-Click", "description": "Nomad Cluster One-Click", "ordinal": 43, "logo_url": "assets/nomadocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 97, "deployments_active": 5, "is_public": true, "mine": false, "created": "2023-08-25T19:05:25", "updated": "2023-12-03T16:18:47", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\ngit_username=\"akamai-compute-marketplace\"\nexport GIT_REPO_1=\"https://github.com/$git_username/nomad-occ.git\"\nexport GIT_REPO_2=\"https://github.com/$git_username/nomad-client-occ.git\"\nexport DEBIAN_FRONTEND=non-interactive\nexport UUID=$(uuidgen | awk -F - '{print $1}')\nexport CLUSTER_MODE='cluster'\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \n\nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n cd ${HOME}\n if [ -d \"/tmp/linode\" ]; then\n rm -rf /tmp/linode\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[warn] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[info] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}-server-1-${UUID}\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\n\nfunction tag_provisioner {\n echo \"[info] tagging the provisioner\"\n REGION=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .region)\n export REGION=\"${REGION}\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" -X PUT \\\n -d \"{\\\"tags\\\": [\\\"${UUID}-${REGION}\\\"]}\" \\ \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID} \n}\n\nfunction setup {\n # install dependencies\n export DEBIAN_FRONTEND=non-interactive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n tag_provisioner\n configure_privateip \n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO_1} /tmp/linode\n git clone ${GIT_REPO_2} /tmp/linode/nomad-client-occ\n # clone one branch to test \n # git clone -b develop ${GIT_REPO_1} /tmp/linode\n # git clone -b develop ${GIT_REPO_2} /tmp/linode/nomad-client-occ\n cd /tmp/linode\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"", "user_defined_fields": [ { "name": "token_password", "label": "Your Linode API token" }, { "name": "sudo_username", "label": "The limited sudo user to be created in the cluster" }, { "name": "email_address", "label": "Email Address", "example": "Example: user@domain.tld" }, { "name": "clusterheader", "label": "Cluster Settings", "default": "Yes", "header": "Yes" }, { "name": "add_ssh_keys", "label": "Add Account SSH Keys to All Nodes?", "oneof": "yes,no", "default": "yes" }, { "name": "cluster_size", "label": "Total instance count", "default": "6", "oneof": "6" }, { "name": "servers", "label": "Nomad Server count", "default": "3", "oneof": "3" }, { "name": "clients", "label": "Nomad client size", "default": "3", "oneof": "3" } ] }, { "id": 1226545, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "HashiCorp Nomad Clients Cluster One-Click", "description": "Nomad Cluster Clients One-Click", "ordinal": 44, "logo_url": "assets/nomadclientsocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 3, "deployments_active": 0, "is_public": true, "mine": false, "created": "2023-08-25T19:07:27", "updated": "2023-11-14T15:53:47", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n cd ${HOME}\n if [ -d \"/tmp/linode\" ]; then\n rm -rf /tmp/linode\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[warn] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[info] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}-client-1-${UUID}\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction tag_provisioner {\n echo \"[info] tagging the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" -X PUT \\\n -d \"{\\\"tags\\\": [\\\"${CLUSTER_UUID}\\\"]}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID} \n}\n\nfunction setup {\n # install dependencies\n export DEBIAN_FRONTEND=noninteractive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n tag_provisioner\n configure_privateip \n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/linode\n # clone one branch to test \n # git clone -b develop ${GIT_REPO} /tmp/linode\n cd /tmp/linode\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"", "user_defined_fields": [ { "name": "token_password", "label": "Your Linode API token" }, { "name": "sudo_username", "label": "The limited sudo user to be created in the cluster" }, { "name": "clusterheader", "label": "Cluster Settings", "default": "Yes", "header": "Yes" }, { "name": "add_ssh_keys", "label": "Add Account SSH Keys to All Nodes?", "oneof": "yes,no", "default": "yes" }, { "name": "cluster_size", "label": "Nomad Client Count", "default": "3", "oneof": "3,5,7" }, { "name": "consul_nomad_autojoin_token_password", "label": "consul_nomad_autojoin_token generated by Nomad Server OCC" }, { "name": "cluster_uuid", "label": "cluster_uuid tag for the Nomad Server OCC being joined to.", "# git repogit_username": "akamai-compute-marketplace", "export git_repo": "https://github.com/$git_username/nomad-client-occ.git" } ] }, { "id": 1037038, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "HashiCorp Vault One-Click", "description": "HashiCorp Vault One Click App", "ordinal": 45, "logo_url": "assets/vault.svg", "images": [ "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 216, "deployments_active": 18, "is_public": true, "mine": false, "created": "2022-08-02T18:47:32", "updated": "2023-12-06T01:29:13", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nexport IP=$(hostname -I | awk '{print$1}')\nexport VAULT_ADDR=\"http://${IP}:8200\"\n\n## install gpg\napt install -y gpg\n\n## add hashicorp gpg key and repo\nwget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg >/dev/null\necho \"deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/hashicorp.list\n\n## install vault\napt update && apt install -y vault\n\n## basic vault configs\nmkdir -p /vault/data\nchown -R vault:vault /vault\ncat << EOF > /etc/vault.d/vault.hcl\nstorage \"raft\" {\n path = \"/vault/data\"\n node_id = \"node1\"\n}\n\nlistener \"tcp\" {\n address = \"${IP}:8200\"\n tls_disable = \"true\"\n}\n\ndisable_mlock = true\n\napi_addr = \"http://127.0.0.1:8200\"\ncluster_addr = \"https://127.0.0.1:8201\"\nui = true\nEOF\n\n## systemd for vault\nsystemctl enable vault.service\n\n## Start vault server and stash the tokens\nsystemctl start vault.service\ntouch /root/.vault_tokens.txt\nsleep 20\nvault operator init | grep 'Token\\|Unseal' >> /root/.vault_tokens.txt\n\n## firewall\nufw allow 22\nufw allow 8200\n\n## config info and recommendations\ncat << EOF > /etc/motd\n#####################################\n The Vault server GUI is now available at ${VAULT_ADDR}\n The randomly generate Unseal Tokens and Initial Root Token are listed in /root/.vault_tokens.txt\n ** STORE THESE VALUES SOMEWHERE SAFE AND SECURE **\n\n This is a minimal installation with limited configurations.\n Please review configurations before using this application in production.\n\n Information on Vault configurations at https://www.vaultproject.io/docs/configuration\n######################################\nEOF\n\nsleep 20\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 1177605, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Illa Builder One-Click", "description": "Illa Builder One-Click App", "ordinal": 46, "logo_url": "assets/illabuilder.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 94, "deployments_active": 3, "is_public": true, "mine": false, "created": "2023-05-17T14:22:00", "updated": "2023-11-30T00:37:08", "rev_note": "", "script": "#!/bin/bash\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Sources OCA helpers\nsource \nsource \nsource \nsource \n# Apt update/upgrade\nexport DEBIAN_FRONTEND=non-interactive\napt update && apt upgrade -y\n\n# Install the dependencies & add Docker to the APT repository\napt install -y apt-transport-https ca-certificates curl software-properties-common gnupg2 pwgen ufw\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable\"\n\n# Update & install Docker-CE\napt_setup_update\napt install -y docker-ce\n\n# Check to ensure Docker is running and installed correctly\nsystemctl status docker\ndocker -v\n\n# Env config\nILLA_HOME_DIR=~/illa\nPG_VOLUMN=${ILLA_HOME_DIR}/database\nDRIVE_VOLUMN=${ILLA_HOME_DIR}/drive\n\n\n# Init\nmkdir -p ${ILLA_HOME_DIR}\nmkdir -p ${PG_VOLUMN}\nmkdir -p ${DRIVE_VOLUMN}\n\n# Run\ndocker run -d \\\n --name illa_builder \\\n -v $PG_VOLUMN:/opt/illa/database \\\n -v $DRIVE_VOLUMN:/opt/illa/drive \\\n -p 80:2022 \\\n illasoft/illa-builder:latest\n\necho \"\n********************************************************************************\nWelcome to ILLA Builder!\n********************************************************************************\n # ILLA Builder: http://\"$FQDN\"\n # Website: https://www.illacloud.com\n # Documentation: https://www.illacloud.com/docs/about-illa\n # Github: https://github.com/illacloud\n # Community Support: https://github.com/orgs/illacloud/discussions\n\"", "user_defined_fields": [] }, { "id": 607401, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Jenkins One-Click", "description": "Jenkins One-Click App", "ordinal": 47, "logo_url": "assets/jenkins.svg", "images": [ "linode/debian11" ], "deployments_total": 1994, "deployments_active": 130, "is_public": true, "mine": false, "created": "2019-10-31T15:29:54", "updated": "2023-12-06T15:30:30", "rev_note": "Initial import", "script": "#!/bin/bash\n\nsource \nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Prereq's & Jenkins\napt install -y default-jre wget gnupg2\nwget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | apt-key add -\nsh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'\napt_setup_update\napt install -y jenkins\nsystemctl enable --now jenkins\n\n# Cleanup \nstackscript_cleanup", "user_defined_fields": [] }, { "id": 869623, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "JetBackup One-Click", "description": "JetBackup One-Click", "ordinal": 48, "logo_url": "assets/jetbackup.svg", "images": [ "linode/centos7", "linode/almalinux8" ], "deployments_total": 102, "deployments_active": 1, "is_public": true, "mine": false, "created": "2021-07-21T12:45:59", "updated": "2023-11-21T02:29:13", "rev_note": "", "script": "#!/bin/bash\n\n# JetBackup StackScript UDF Variables\n# \n# \n#\n# The next line makes the Official cPanel StackScript available if cPanel/WHM is selected as the control panel. Do not remove this line.\n# source \n#\n# Log File Paths:\n# StackScript Log: /var/log/stackscript.log\n# cPanel/WHM installation: /var/log/stackscript-595742.log\n# Debugging: /var/log/stackscript-debug.log\n#\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>/var/log/stackscript-debug.log\necho \"PID: $$\"\nCONTROLPANEL=${CONTROLPANEL}\nRELEASE=${RELEASETIER}\nJBDIR=\"/usr/local/jetapps/etc/jetbackup5\"\n\nif [[ -z ${CONTROLPANEL} ]]; then\necho \"Error: No panel selected. Please select a panel to deploy JetBackup.\"\nexit 1\nelif [[ -d ${JBDIR} ]]; then\necho \"Error: JetBackup already installed. Aborting StackScript.\"\nexit 0\nfi\n\necho \"Installing JetApps Repository\"\nrpm --import http://repo.jetlicense.com/centOS/RPM-GPG-KEY-JETAPPS\nyum -y -q install http://repo.jetlicense.com/centOS/jetapps-repo-latest.rpm\nyum -y -q install jetapps --disablerepo=* --enablerepo=jetapps\necho \"JetApps Repository Successfully Installed.\"\n\ncpanelinstall() {\n\necho \"Running cPanel/WHM Marketplace StackScript. You can track the progress of cPanel/WHM with: tail -f /var/log/stackscript-595742.log \"\n(source /root/ssinclude-595742 >>/var/log/stackscript-595742.log 2>&1)\n\n}\n\n# JETBACKUP 5 FOR LINUX - STANDALONE INSTALLATION\n\nif [ \"${CONTROLPANEL}\" = \"Linux\" ]; then\necho \"Installing JetBackup 5.\"\npackage='jetbackup5-linux'\njetapps --install $package $RELEASE\njbhostname=$(hostname)\njbhostname=\"https://${jbhostname}:3035\"\necho \"Adding a Firewall rule to open port 3035. Port 3035 must be open for access to the JetBackup 5 Linux UI.\"\nfirewall-cmd --permanent --add-port=3035/tcp\nfirewall-cmd --reload\necho \"To go to JetBackup and Accept the User Agreement, go to ${jbhostname} and enter your root login credentials.\"\necho \"To generate a one-time JetBackup 5 login URL after installation and acceptance of the EULA type the following command in the terminal:\"\necho \"jb5login\"\nfi\n\n# JETBACKUP 5 FOR CPANEL/WHM INSTALLATION\n\nif [ \"${CONTROLPANEL}\" = \"cPanel/WHM\" ]; then\n\npackage='jetbackup5-cpanel'\ncpanelinstall\nsleep 2\necho \"Installing JetBackup 5.\"\njetapps --install $package $RELEASE\necho \"To log in to cPanel/WHM as root user, please enter the following command to generate a one-time login token:\"\necho \"\"\necho \"whmlogin\"\nfi\n\necho \"Review the JetBackup 5 Getting Started Guide at https://docs.jetbackup.com/v5.1/adminpanel/gettingStarted.html\"\ninstallVersion=\"$(jetbackup5 --version | cut -d ' ' -f 1,3,4 | sed \"2 d\")\"\necho \"${installVersion} Successfully Installed!\"\nrm /root/ssinclude-595742\nrm /root/StackScript\nexit 0", "user_defined_fields": [ { "name": "CONTROLPANEL", "label": "Choose a Control Panel to use with JetBackup 5. cPanel/WHM or Linux (No Control Panel)", "default": "cPanel/WHM", "oneof": "cPanel/WHM,Linux" }, { "name": "RELEASETIER", "label": "Choose a JetBackup Release Tier.", "default": "stable", "oneof": "stable,beta,edge" } ] }, { "id": 662121, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Jitsi One-Click", "description": "Jitsi One-Click", "ordinal": 49, "logo_url": "assets/jitsi.svg", "images": [ "linode/ubuntu20.04", "linode/ubuntu22.04" ], "deployments_total": 4515, "deployments_active": 129, "is_public": true, "mine": false, "created": "2020-08-12T16:08:51", "updated": "2023-12-06T18:45:50", "rev_note": "", "script": "#!/bin/bash\n\n## Jitsi Settings\n#\n\n## Domain Settings\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n\n# This also sets some useful variables, like $IP and $FQDN\nsource \nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# dependencies\nexport DEBIAN_FRONTEND=noninteractive\napt install apt-transport-https gnupg2 curl wget -y\napt-add-repository universe\napt update -y\n\n#Install Jitisi dep Prosody\necho deb http://packages.prosody.im/debian $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list\nwget https://prosody.im/files/prosody-debian-packages.key -O- | sudo apt-key add -\napt install lua5.2\n\n#Install Nginx\napt install -y nginx\nsystemctl start nginx\nsystemctl enable nginx\n\n#Install Jitsi Meet\ncurl https://download.jitsi.org/jitsi-key.gpg.key | sudo sh -c 'gpg --dearmor > /usr/share/keyrings/jitsi-keyring.gpg'\necho 'deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/' | sudo tee /etc/apt/sources.list.d/jitsi-stable.list > /dev/null\n\n# update all package sources\napt update -y\necho \"jitsi-videobridge jitsi-videobridge/jvb-hostname string $FQDN\" | debconf-set-selections\necho \"jitsi-meet-web-config jitsi-meet/cert-choice select 'Generate a new self-signed certificate (You will later get a chance to obtain a Let's encrypt certificate)'\" | debconf-set-selections\napt --option=Dpkg::Options::=--force-confold --option=Dpkg::options::=--force-unsafe-io --assume-yes install jitsi-meet\n\n# Firewall\nsudo ufw allow 80/tcp\nsudo ufw allow 443/tcp\nsudo ufw allow 10000/udp\nsudo ufw allow 22\nsudo ufw allow 3478/udp\nsudo ufw allow 5349/tcp\nsudo ufw enable\n\n# SSL \ncheck_dns_propagation \"${FQDN}\" \"${IP}\"\n/usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh <\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -xo pipefail\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\nfunction lampjoomla {\n apt-get install apache2 mariadb-server php php-common libapache2-mod-php php-cli php-fpm php-mysql php-json php-opcache php-gmp php-curl php-intl php-mbstring php-xmlrpc php-gd php-xml php-zip -y\n PHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\n cat < /etc/php/$PHP_VERSION/apache2/php.ini\nmemory_limit = 512M\nupload_max_filesize = 256M\npost_max_size = 256M \nmax_execution_time = 300\noutput_buffering = off\ndisplay_errors = off\nupload_tmp_dir = \"/var/www/html/joomla/tmp\"\nEND\n}\n\nfunction databaseconf {\n run_mysql_secure_installation\n mysql -uroot -p$DBROOT_PASSWORD -e \"CREATE DATABASE joomla_db;\"\n mysql -uroot -p$DBROOT_PASSWORD -e \"CREATE USER 'joomla'@'localhost' IDENTIFIED BY '$DBUSER_PASSWORD';\"\n mysql -uroot -p$DBROOT_PASSWORD -e \"GRANT ALL PRIVILEGES ON joomla_db.* TO 'joomla'@'localhost';\"\n}\n\nfunction apachejoomla {\n apt-get install wget unzip -y\n mkdir -p /var/www/html/joomla\n cd /tmp && wget https://downloads.joomla.org/cms/joomla4/4-1-0/Joomla_4-1-0-Stable-Full_Package.zip?format=zip\n unzip Joomla_4* -d /var/www/html/joomla\n chown -R www-data:www-data /var/www/html/joomla \n chmod -R 755 /var/www/html/joomla\n cat < /etc/apache2/sites-available/joomla.conf\n\n ServerAdmin $SOA_EMAIL_ADDRESS\n DocumentRoot /var/www/html/joomla\n ServerName $FQDN\n\n \n Options FollowSymlinks\n AllowOverride All\n Require all granted\n \n\n ErrorLog ${APACHE_LOG_DIR}/$FQDN_error.log\n CustomLog ${APACHE_LOG_DIR}/$FQDN_access.log combined\n\n\nEND\n a2ensite joomla.conf\n a2enmod rewrite\n a2enmod php$PHP_VERSION\n a2dissite 000-default.conf\n systemctl restart apache2\n\n ufw allow http\n ufw allow https\n}\nfunction ssljoomla {\n apt install certbot python3-certbot-apache -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n}\n\nfunction main {\n lampjoomla\n databaseconf\n apachejoomla\n ssljoomla\n stackscript_cleanup\n}\n# Execute script\nmain", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "dbroot_password", "label": "MySQL Root Password", "example": "s3cur3_9a55w04d" }, { "name": "dbuser_password", "label": "MySQL User Password", "example": "s3cur3_9a55w04d" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 985380, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Joplin One-Click", "description": "Joplin One-Click", "ordinal": 51, "logo_url": "assets/joplin.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 420, "deployments_active": 31, "is_public": true, "mine": false, "created": "2022-03-08T18:14:30", "updated": "2023-12-06T21:12:55", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Joplin setup\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-joplin\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n}\n\nfunction udf {\n \n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n \n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # Joplin vars\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n \n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" } ] }, { "id": 688912, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Kepler Builder One-Click", "description": "Kepler Builder One-Click", "ordinal": 52, "logo_url": "assets/keplerbuilder.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 264, "deployments_active": 4, "is_public": true, "mine": false, "created": "2020-11-17T21:17:33", "updated": "2023-12-06T21:13:24", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Wordpress Settings\n#\n#\n\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-keplerbuilder\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n webserver_stack: ${web_stack}\n site_title: ${SITE_TITLE}\n wp_admin_user: ${WP_ADMIN_USER}\n wp_db_user: ${WP_DB_USER}\n wp_db_name: ${WP_DB_NAME}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "webserver_stack", "label": "The stack you are looking to deploy Wordpress on", "oneof": "LAMP,LEMP" }, { "name": "site_title", "label": "Website title", "example": "My Blog" }, { "name": "wp_admin_user", "label": "Admin username", "example": "admin" }, { "name": "wp_db_user", "label": "Wordpress database user", "example": "wordpress" }, { "name": "wp_db_name", "label": "Wordpress database name", "example": "wordpress" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 401701, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "LAMP One-Click", "description": "LAMP One-Click", "ordinal": 53, "logo_url": "assets/LAMP.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 13726, "deployments_active": 1105, "is_public": true, "mine": false, "created": "2019-03-09T02:07:09", "updated": "2023-12-07T12:39:27", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## LAMP Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-lamp\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n webserver_stack: lamp\n soa_email_address: ${SOA_EMAIL_ADDRESS}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 606691, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "LEMP One-Click", "description": "LEMP Stack", "ordinal": 54, "logo_url": "assets/LEMP.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 4144, "deployments_active": 309, "is_public": true, "mine": false, "created": "2019-10-27T15:29:04", "updated": "2023-12-07T15:10:35", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## LEMP Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-lemp\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n webserver_stack: lemp\n soa_email_address: ${SOA_EMAIL_ADDRESS}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 923032, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "LiteSpeed cPanel One-Click", "description": "LiteSpeed cPanel One-Click", "ordinal": 55, "logo_url": "assets/litespeedcpanel.svg", "images": [ "linode/almalinux8" ], "deployments_total": 1015, "deployments_active": 21, "is_public": true, "mine": false, "created": "2021-10-18T00:57:12", "updated": "2023-12-01T13:53:07", "rev_note": "", "script": "#!/bin/bash\n## Logging\nexec > /var/log/stackscript.log 2>&1\n## Install cPanel\nyum install -y kernel grub2\nsed -i -e \"s/GRUB_TIMEOUT=5/GRUB_TIMEOUT=10/\" /etc/default/grub\nsed -i -e \"s/crashkernel=auto rhgb console=ttyS0,19200n8/console=ttyS0,19200n8/\" /etc/default/grub\nmkdir /boot/grub\ngrub2-mkconfig -o /boot/grub/grub.cfg\nsystemctl stop firewalld.service\nsystemctl disable firewalld.service\nsystemctl stop NetworkManager\nsystemctl disable NetworkManager\nsystemctl enable network\nsystemctl start network\nyum remove NetworkManager -y\ncd /home \ncurl -o latest -L https://securedownloads.cpanel.net/latest && sh latest\nyum remove ea-apache24-mod_ruid2 -y\n## Install LSWS on cPanel\nADMIN_PASS=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16 ; echo '')\ncat <>/home/lsws.options\n## 1 = enable, 0 = disable, 2 = user home directory\nphp_suexec=\"2\"\nport_offset=\"0\"\nadmin_user=\"admin\"\nadmin_pass=\"${ADMIN_PASS}\"\nadmin_email=\"root@localhost\"\neasyapache_integration=\"1\"\nauto_switch_to_lsws=\"1\"\ndeploy_lscwp=\"1\"\nEOT\nbash <( curl https://get.litespeed.sh ) TRIAL", "user_defined_fields": [] }, { "id": 1008123, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "LiveSwitch One-Click", "description": "LiveSwitch One-Click", "ordinal": 56, "logo_url": "assets/liveswitch.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 193, "deployments_active": 1, "is_public": true, "mine": false, "created": "2022-05-18T16:41:37", "updated": "2023-12-03T04:57:47", "rev_note": "", "script": "#!/bin/bash\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n## Import the Bash StackScript Library\nsource \n\nsudo dpkg --configure -a\n\n# kill any background updater jobs\nsudo killall apt apt-get\n\n# helpers\nsudo apt-get install dialog apt-utils -y -q\n\nsudo DEBIAN_FRONTEND=noninteractive apt-get update -y\nsudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef -y\n\n# firewall\n# normal defaults\nsudo ufw default deny incoming\nsudo ufw default allow outgoing\n# ssh on\nsudo ufw allow ssh\n# dynamic inbound traffic\nsudo ufw allow 49152:65535/udp\n# TURN\nsudo ufw allow 3478/udp\n# TURN TCP\nsudo ufw allow 80/tcp\n# TURNS\nsudo ufw allow 443/tcp\n# admin (only really should do this for a demo system where it's all on one box)\nsudo ufw allow 9090/tcp\nsudo ufw allow 9443/tcp\n# gateway (only really should do this for a demo system where it's all on one box)\nsudo ufw allow 8080/tcp\nsudo ufw allow 8443/tcp\n\n# sip\n# sudo ufw allow 5061/udp\n# sudo ufw allow 5061/tcp\n\n# we will turn on the firewall at the end because it disconnects us\n\n# install docker\nsudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -\nsudo add-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable\"\napt-cache policy docker-ce\nsudo apt-get install -y docker-ce\n\n# entropy fix for docker\nsudo apt-get install -y haveged\n\n# install docker compose\nsudo curl -L \"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\nsudo chmod +x /usr/local/bin/docker-compose\n\n# retrieve docker compose files\nmkdir -p /opt/liveswitch\nsudo curl -L \"https://raw.githubusercontent.com/jvenema/liveswitch-docker-compose/main/docker-compose-liveswitch.service\" -o /opt/liveswitch/docker-compose-liveswitch.service\nsudo curl -L \"https://raw.githubusercontent.com/jvenema/liveswitch-docker-compose/main/docker-compose.yml\" -o /opt/liveswitch/docker-compose.yml\n\n# install liveswitch docker compose\nsudo cp /opt/liveswitch/docker-compose-liveswitch.service /etc/systemd/system/\nsudo systemctl enable docker\nsudo systemctl enable docker-compose-liveswitch\nsudo systemctl start docker-compose-liveswitch\n\n# clean up some logs\nsudo rm -f /var/log/cloud-init-output.log\nsudo rm -f /var/log/dpkg.log\nsudo rm -f /var/log/kern.log\nsudo rm -f /var/log/ufw.log\n\n# turn on the firewall\nsudo ufw --force enable\nsudo reboot", "user_defined_fields": [] }, { "id": 869159, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MagicSpam One-Click", "description": "MagicSpam One-Click", "ordinal": 57, "logo_url": "assets/magicspam.svg", "images": [ "linode/centos7" ], "deployments_total": 5, "deployments_active": 0, "is_public": true, "mine": false, "created": "2021-07-20T19:13:52", "updated": "2023-10-18T12:38:33", "rev_note": "", "script": "#!/bin/bash\n\n# \n# \n# \n\n# source the stackscript for the selected control panel\nif [ \"$CONTROL_PANEL\" == \"cPanel\" ]; then\n # redirect ALL output to the stackscript log for future troubleshooting\n exec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n # cPanel Marketplace App install\n source \n\n # set the hostname to replicate Plesk stackscript for consistent behavior\n IPADDR=$(/sbin/ifconfig eth0 | awk '/inet / { print $2 }' | sed 's/addr://')\n echo $HOSTNAME > /etc/hostname\n hostname -F /etc/hostname\n echo $IPADDR $HOSTNAME >> /etc/hosts\nelif [ \"$CONTROL_PANEL\" == \"Plesk\" ]; then\n # Plesk Marketplace App install\n # NOTE: do not redirect output to the stackscript log to avoid duplicate log\n # lines as the Plesk stackscript already redirects to it\n source \nelse\n echo \"Invalid control panel option detected. Aborting...\"\n exit 1\nfi\n\n# install MagicSpam via the installer script\nwget https://www.magicspam.com/download/magicspam-installer.sh -O /root/magicspam-installer\nchmod +x /root/magicspam-installer\n/root/magicspam-installer -l \"$MS_LICENSE_KEY\"", "user_defined_fields": [ { "name": "control_panel", "label": "The Control Panel to deploy alongside with MagicSpam. Make sure to select an Image supported by the selected Control Panel. For more information, please refer to the MagicSpam App Information Sidebar.", "oneof": "cPanel,Plesk" }, { "name": "ms_license_key", "label": "The MagicSpam license key. Please make sure to use the appropriate license key for the selected Control Panel. For more information, please refer to the MagicSpam App information sidebar." }, { "name": "hostname", "label": "The server's hostname." } ] }, { "id": 1243759, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MainConcept FFmpeg Plugins Demo One-Click", "description": "MainConcept FFmpeg Plugins", "ordinal": 58, "logo_url": "assets/mainconcept.svg", "images": [ "linode/debian11" ], "deployments_total": 6, "deployments_active": 1, "is_public": true, "mine": false, "created": "2023-09-28T15:02:48", "updated": "2023-12-06T21:14:38", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\n\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-ffmpeg-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" } ] }, { "id": 1243760, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MainConcept Live Encoder Demo One-Click", "description": "MainConcept Live Encoder\r\n\r\n", "ordinal": 59, "logo_url": "assets/mainconcept.svg", "images": [ "linode/centos-stream9" ], "deployments_total": 20, "deployments_active": 1, "is_public": true, "mine": false, "created": "2023-09-28T15:04:08", "updated": "2023-12-06T15:19:44", "rev_note": "", "script": "#!/bin/bash\n\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-live-encoder-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(dnsdomainname -A | awk '{print $1}')\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n yum install dnf -y\n dnf update -y\n dnf upgrade -y\n dnf install -y git python3 python3-pip\n\n dnf makecache\n dnf install epel-release -y\n dnf makecache\n dnf install ansible -y\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone --single-branch --branch ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -vvvv $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address for SSL Generation", "default": "" } ] }, { "id": 1243762, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MainConcept P2 AVC ULTRA Transcoder Demo One-Click", "description": "MainConcept P2 AVC ULTRA Transcoder", "ordinal": 60, "logo_url": "assets/mainconcept.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 1, "deployments_active": 0, "is_public": true, "mine": false, "created": "2023-09-28T15:05:01", "updated": "2023-12-07T16:54:44", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## MainConcept P2 AVC Ultra Transcoder Demo Settings\n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-p2-avc-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n mc_port: ${MC_PORT}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"No domain entered\";\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "mc_port", "label": "MainConcept P2 AVC Ultra Transcoder API Port", "example": "Default: 8080", "default": "8080" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "soa_email_address", "label": "Email address for domain SOA. REQUIRED for DNS", "example": "user@domain.tld", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 1243763, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MainConcept XAVC Transcoder Demo One-Click", "description": "MainConcept XAVC Transcoder", "ordinal": 61, "logo_url": "assets/mainconcept.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 2, "deployments_active": 0, "is_public": true, "mine": false, "created": "2023-09-28T15:05:47", "updated": "2023-12-06T21:20:30", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## MainConcept XAVC Transcoder Demo Settings\n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-xavc-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n mc_port: ${MC_PORT}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"No domain entered\";\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "mc_port", "label": "MainConcept XAVC Transcoder API Port", "example": "Default: 8080", "default": "8080" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "soa_email_address", "label": "Email address for domain SOA. REQUIRED for DNS", "example": "user@domain.tld", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 1243764, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MainConcept XDCAM Transcoder Demo One-Click", "description": "MainConcept XDCAM Transcoder", "ordinal": 62, "logo_url": "assets/mainconcept.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 1, "deployments_active": 0, "is_public": true, "mine": false, "created": "2023-09-28T15:06:28", "updated": "2023-12-06T21:21:16", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## MainConcept XDCAM Transcoder Demo Settings\n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-xdcam-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n mc_port: ${MC_PORT}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n \n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"No domain entered\";\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "mc_port", "label": "MainConcept XDCAM Transcoder API Port", "example": "Default: 8080", "default": "8080" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "soa_email_address", "label": "Email address for domain SOA. REQUIRED for DNS", "example": "user@domain.tld", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 1096122, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Mastodon One-Click", "description": "Mastodon is an open-source and decentralized micro-blogging platform, supporting federation and public access to the server.", "ordinal": 63, "logo_url": "assets/mastodon.svg", "images": [ "linode/debian11" ], "deployments_total": 1689, "deployments_active": 63, "is_public": true, "mine": false, "created": "2022-12-05T15:57:04", "updated": "2023-12-03T22:02:29", "rev_note": "", "script": "#!/bin/bash\nset -x\n## Mastodon Settings\n#\n#\n#\n#\n#\n#\n\n\n# git repo + workdirs\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/mastodon-oca.git\"\nexport WORK_DIR=\"/tmp/oca-deployment\"\nexport LINODE_API_TOKEN=\"${TOKEN_PASSWORD}\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nsource \n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n}\n\nfunction setup {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip python3-dev build-essential\n\n #clone repo and set up ansible environment\n mkdir -p ${WORK_DIR}\n cd ${WORK_DIR}\n git clone $GIT_REPO\n cd mastodon-oca\n\n # write udf vars\n cat < group_vars/mastodon/vars\n domain: ${DOMAIN}\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n owner_username: ${OWNER_USERNAME}\n owner_email: ${OWNER_EMAIL}\n single_user_mode: ${SINGLE_USER_MODE}\nEND\n\n #venv\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n}\n\nfunction run {\n# run playbooks\n ansible-playbook -v site.yml\n}\n\n# main\nsetup\nrun\ncleanup\necho \"Installation Complete!\"", "user_defined_fields": [ { "name": "domain", "label": "Domain name for your Mastodon instance.", "example": "domain.tld" }, { "name": "token_password", "label": "Your Linode API token" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "owner_username", "label": "Username for Mastodon Owner", "example": "" }, { "name": "owner_email", "label": "Email address for Mastodon Owner", "example": "owner@example.com" }, { "name": "single_user_mode", "label": "Do you want to start Mastodon in single-user mode?", "oneof": "Yes,No" } ] }, { "id": 611895, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MEAN One-Click", "description": "MEAN One-Click", "ordinal": 64, "logo_url": "assets/mean.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 726, "deployments_active": 36, "is_public": true, "mine": false, "created": "2019-11-14T04:49:44", "updated": "2023-12-06T14:01:30", "rev_note": "Initial import", "script": "#!/usr/bin/env bash\n\n## MEAN Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction dependmean {\n apt-get install -y build-essential git fontconfig libpng-dev ruby ruby-dev wget gnupg\n gem install sass\n}\n\nfunction mongoinstall {\n cd && wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\n if [ \"${detected_distro[distro]}\" = 'debian' ]; then \n echo \"deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\n elif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\n else \n echo \"Setting this up for the future incase we add more distros\"\n fi\n apt-get update -y\n apt-get install -y mongodb-org\n systemctl enable mongod.service\n systemctl start mongod.service\n}\n\n\nfunction meaninstall {\n apt-get install -y curl software-properties-common\n curl -fsSL https://deb.nodesource.com/setup_16.x | bash -\n apt-get install -y nodejs\n\n # MEAN APP CONFIGURATION\n cd && mkdir -p /opt/mean\n cd /opt/mean\n cat <> package.json\n{\n\"name\" : \"mean\",\n\"version\": \"0.0.1\"\n}\nEND\n npm install express --save\n npm install angular\n cat <> server.js\nvar express = require('express');\nvar app = express();\nvar port = 3000;\napp.get('/', function(req, res) {\nres.send('Hello World Powered By: Linode Marketplace');\n});\napp.listen(port, function(){\nconsole.log(\"Listening at port: \" + port);\n})\nEND\n # Start App on reboot\n cd && npm install pm2 -g\n pm2 start --name=\"MEAN_APP\" /opt/mean/server.js\n pm2 startup \n pm2 save\n}\n\nfunction nginxmean {\n apt-get install nginx -y \n cat < /etc/nginx/sites-available/$FQDN\nserver {\n server_name $FQDN www.$FQDN;\n location / {\n proxy_pass http://localhost:3000;\n proxy_http_version 1.1;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection 'upgrade';\n proxy_set_header Host \\$host;\n proxy_cache_bypass \\$http_upgrade;\n }\n}\nEND\n ln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/\n unlink /etc/nginx/sites-enabled/default\n nginx -t\n systemctl reload nginx\n}\n\nfunction sslmean {\n apt install certbot python3-certbot-nginx -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction firewallmean {\n ufw allow http\n ufw allow https\n}\n\nfunction main {\n dependmean\n firewallmean\n mongoinstall\n meaninstall\n nginxmean\n sslmean\n\n}\n\n# execute script\nmain\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address for SSL certificate" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 401702, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MERN One-Click", "description": "MERN One-Click", "ordinal": 65, "logo_url": "assets/MERN.svg", "images": [ "linode/debian10", "linode/ubuntu20.04", "linode/debian11" ], "deployments_total": 1430, "deployments_active": 57, "is_public": true, "mine": false, "created": "2019-03-08T21:07:40", "updated": "2023-12-02T17:05:28", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 3000\nfail2ban_install\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install dependencies\napt-get install -y build-essential git \n\n# Install Mongodb\napt-get install -y wget gnupg\nwget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \necho \"deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\necho \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\napt-get update -y\napt-get install -y mongodb-org\nsystemctl enable mongod.service\nsystemctl start mongod.service\n\n# Install NodeJS and NPM\napt-get install -y curl software-properties-common\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \ncurl -fsSL https://deb.nodesource.com/setup_16.x | bash -\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\ncurl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\napt-get install -y nodejs\n\n# Install ExpressJS\nnpm update -g\nnpm install --global express\nnpm link express\nnpm -g install create-react-app\ncd /opt\ncreate-react-app hello-world\nnpm i --package-lock-only\nnpm audit fix\n\n# Start App on reboot\ncat < /lib/systemd/system/hello-world.service\n[Unit]\nDescription=Hello World React Application Service\nRequires=hello-world.service\nAfter=hello-world.service\n\n[Service]\nType=simple\nUser=root\nRemainAfterExit=yes\nRestart=on-failure\nWorkingDirectory=/opt/hello-world\nExecStart=npm start --host 0.0.0.0 --port=3000\n\n[Install]\nWantedBy=multi-user.target\nEND\n\nsystemctl daemon-reload\nsystemctl start hello-world\nsystemctl enable hello-world\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 1051714, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Microweber One-Click", "description": "Microweber One-Click", "ordinal": 66, "logo_url": "assets/microweber.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 476, "deployments_active": 22, "is_public": true, "mine": false, "created": "2022-09-01T15:43:41", "updated": "2023-12-02T20:24:43", "rev_note": "", "script": "#!/usr/bin/env bash\n# https://github.com/microweber/microweber\nset -o pipefail\nMICROWEBER_INSTALLER_TAG=\"1.3.1\"\nWORKING_DIR=\"/var/www/html\"\nDOWNLOAD_URL='http://updater.microweberapi.com/builds/master/microweber.zip'\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## 03-force-ssh-logout.sh\ncat >>/etc/ssh/sshd_config </dev/null\napt install -y apache2 libapache2-mod-php8.1\napt install -y mysql-server\napt install -y php8.1-{bcmath,xml,fpm,mysql,iconv,xsl,zip,intl,ldap,gd,cli,dev,bz2,curl,exif,mbstring,pgsql,sqlite3,tokenizer,opcache,soap,cgi,common,imap,opcache}\napt install -y python3-certbot-apache software-properties-common unzip curl\napt install -y php-pear\npecl install -f libsodium\nsed -i 's/;opcache.enable\\s*=.*/opcache.enable=1/g' /etc/php/8.1/cli/php.ini\necho 'extension=sodium.so' > /etc/php/8.1/cli/10-sodium.ini\necho 'extension=sodium.so' > /etc/php/8.1/fpm/10-sodium.ini\necho 'extension=sodium.so' > /etc/php/8.1/cgi/10-sodium.ini\n# 01-fs.sh\ncat >/etc/apache2/sites-available/000-default.conf <\n \n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n \n ServerAdmin webmaster@localhost\n DocumentRoot /var/www/html\n ErrorLog \\${APACHE_LOG_DIR}/error.log\n CustomLog \\${APACHE_LOG_DIR}/access.log combined\n\nEOM\ncat >/etc/update-motd.d/99-one-click < certbot --apache -d example.com -d www.example.com\nIMPORTANT:\n * After connecting to the server for the first time, immediately install\n Microweber at http://\\$myip/\n * Secure your database by running:\n > mysql_secure_installation\nFor help and more information visit https://microweber.org\n********************************************************************************\nTo delete this message of the day: rm -rf \\$(readlink -f \\${0})\nEOF\nEOM\nchmod +x /etc/update-motd.d/99-one-click\ncat >/etc/cron.d/microweber </etc/php/8.1/apache2/conf.d/30-microweber.ini <>/var/log/per-instance.log\nMYSQL_ROOT_PASS=$(openssl rand -hex 16)\nDEBIAN_SYS_MAINT_MYSQL_PASS=$(openssl rand -hex 16)\nMICROWEBER_DB_HOST=localhost\nMICROWEBER_DB_PORT=3306\nMICROWEBER_DB_NAME=microweber\nMICROWEBER_DB_USER=microweber\nMICROWEBER_DB_PASS=$(openssl rand -hex 16)\ncat >/root/.mysql_password <>/etc/apache2/envvars </etc/mysql/debian.cnf <>/var/log/per-instance.log\necho \"[OK] Microweber Installer $MICROWEBER_INSTALLER_TAG provisioned!\"", "user_defined_fields": [] }, { "id": 691614, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Mist.io One-Click", "description": "Mist.io One-Click", "ordinal": 67, "logo_url": "assets/mistio.svg", "images": [ "linode/debian10" ], "deployments_total": 321, "deployments_active": 0, "is_public": true, "mine": false, "created": "2020-11-30T20:25:44", "updated": "2023-12-02T16:02:43", "rev_note": "", "script": "#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# apt-get updates\n echo 'Acquire::ForceIPv4 \"true\";' > /etc/apt/apt.conf.d/99force-ipv4\n export DEBIAN_FRONTEND=noninteractive\n apt-get update -y\n\n# \n\n# \n\n## install docker\nsudo apt-get install -y \\\n apt-transport-https \\\n ca-certificates \\\n curl \\\n gnupg-agent \\\n software-properties-common\n\ncurl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -\n\nsudo add-apt-repository \\\n \"deb [arch=amd64] https://download.docker.com/linux/debian \\\n $(lsb_release -cs) \\\n stable\"\n\nsudo apt-get update\n\nsudo apt-get install -y docker-ce docker-ce-cli containerd.io\n\n## install docker-compose\nsudo curl -L \"https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n\nsudo chmod +x /usr/local/bin/docker-compose\n\n## get latest mist\nmkdir ~/mist && cd ~/mist\n\nexport MIST_CE_REPO=https://github.com/mistio/mist-ce/releases/latest\nexport LATEST_TAG=\"$(curl -sI \"${MIST_CE_REPO}\" | grep -Po 'tag\\/\\K(v\\S+)')\"\n\nwget https://github.com/mistio/mist-ce/releases/download/$LATEST_TAG/docker-compose.yml\n\n# set CORE_URI\nmkdir settings\nexport IP=$(ip r | grep /24 | grep -Eo \"([0-9]{1,3}[\\.]){3}[1-9]{1,3}\")\necho 'CORE_URI=\"http://'$IP'\"' > settings/settings.py\n\ndocker-compose up -d\n\nwhile !(curl -sSLf http://localhost >/dev/null); do\n sleep 5\ndone\n\ndocker-compose exec -T api ./bin/adduser --admin \"${MIST_EMAIL}\" --password \"${MIST_PASSWORD}\"", "user_defined_fields": [ { "name": "mist_email", "label": "Mist admin user's email.", "example": "Set your admin user's email." }, { "name": "mist_password", "label": "Mist admin user's password.", "example": "Set your admin user's password." } ] }, { "id": 609195, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MongoDB One-Click", "description": "MongoDB One-Click", "ordinal": 68, "logo_url": "assets/mongodb.svg", "images": [ "linode/ubuntu20.04", "linode/debian11" ], "deployments_total": 1757, "deployments_active": 79, "is_public": true, "mine": false, "created": "2019-11-06T07:14:07", "updated": "2023-10-18T12:38:33", "rev_note": "", "script": "#!/bin/bash\n## Mongo Settings\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction mongoinstall {\n apt-get install -y wget gnupg\n if [ $MONGOVERSION == \"5.0\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\n elif [ $MONGOVERSION == \"4.4\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list\n elif [ $MONGOVERSION == \"4.2\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.2 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.list\n elif [ $MONGOVERSION == \"4.0\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-4.0.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list\n fi\n\n apt-get update -y\n apt-get install -y mongodb-org\n systemctl enable mongod.service\n systemctl start mongod.service\n}\n\nfunction createmongouser {\n echo \"Creating Mongo User\" & sleep 3\n mongo < /etc/mongod.conf\n# mongod.conf\n# for documentation of all options, see:\n# http://docs.mongodb.org/manual/reference/configuration-options/\n# Where and how to store data.\nstorage:\n dbPath: /var/lib/mongodb\n journal:\n enabled: true\n# engine:\n# wiredTiger:\n# where to write logging data.\nsystemLog:\n destination: file\n logAppend: true\n path: /var/log/mongodb/mongod.log\n# network interfaces\nnet:\n port: 27017\n bindIp: 127.0.0.1\n# how the process runs\nprocessManagement:\n timeZoneInfo: /usr/share/zoneinfo\nsecurity:\n authorization: enabled\n#operationProfiling:\n#replication:\n#sharding:\n## Enterprise-Only Options:\n#auditLog:\n#snmp:\nEOF\n service mongod restart\n}\n\nfunction main {\n mongoinstall\n createmongouser \n setauth\n}\n\nmain\nstackscript_cleanup", "user_defined_fields": [ { "name": "db_password", "label": "Mongo Password" }, { "name": "mongoversion", "label": "Mongo Version", "oneof": "5.0,4.4,4.2,4.0", "default": "5.0" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address for soa record", "default": "" } ] }, { "id": 1067004, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MongoDB Cluster One-Click", "description": "MongoDB replica set", "ordinal": 69, "logo_url": "assets/mongodbmarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 49, "deployments_active": 0, "is_public": true, "mine": false, "created": "2022-09-29T18:32:36", "updated": "2023-10-18T12:38:33", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\nexport GIT_PAT=\"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\"\nexport GIT_REPO=\"https://linode-solutions:${GIT_PAT}@github.com/linode-solutions/mongodb-occ.git\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/mongodb-cluster\" ]; then\n rm -rf /tmp/mongodb-cluster\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction destroy_linode {\n curl -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X DELETE \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction add_privateip {\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[+] Linode private IP present\"\n else\n echo \"[!] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[+] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction setup {\n # install dependancies\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # Rename Provisioner & add Private IP \n rename_provisioner\n configure_privateip \n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/mongodb-cluster\n cd /tmp/mongodb-cluster\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"", "user_defined_fields": [ { "name": "token_password", "label": "Your Linode API token" }, { "name": "sudo_username", "label": "The limited sudo user to be created in the cluster" }, { "name": "cluster_name", "label": "Domain Name" }, { "name": "add_ssh_keys", "label": "Add Account SSH Keys to All Nodes?", "oneof": "yes,no", "default": "yes" }, { "name": "sslheader", "label": "SSL Information", "header": "Yes", "default": "Yes", "required": "Yes" }, { "name": "country_name", "label": "Details for self-signed SSL certificates: Country or Region", "oneof": "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW" }, { "name": "state_or_province_name", "label": "State or Province", "example": "Example: Pennsylvania" }, { "name": "locality_name", "label": "Locality", "example": "Example: Philadelphia" }, { "name": "organization_name", "label": "Organization", "example": "Example: Akamai Technologies" }, { "name": "email_address", "label": "Email Address", "example": "Example: user@domain.tld" }, { "name": "ca_common_name", "label": "CA Common Name", "default": "Mongo CA" }, { "name": "common_name", "label": "Common Name", "default": "Mongo Server" }, { "name": "cluster_size", "label": "MongoDB cluster size", "default": "3", "oneof": "3" } ] }, { "id": 869127, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Moodle One-Click", "description": "Moodle One-Click", "ordinal": 70, "logo_url": "assets/moodle.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 1298, "deployments_active": 103, "is_public": true, "mine": false, "created": "2021-07-20T18:48:49", "updated": "2023-12-07T16:01:39", "rev_note": "", "script": "#!/usr/bin/env bash\n\n### UDF Variables\n## Moodle settings\n#\n#\n#\n#\n\n## Domain settings\n#\n#\n#\n\n## Linode/SSH Security Settings \n#\n#\n\n## Linode/SSH Settings - Optional\n#\n#\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n# System Update\nsystem_update\n\n# Install dependencies \napt install -y apache2 mysql-client mysql-server php libapache2-mod-php git graphviz aspell ghostscript clamav php7.4-pspell php7.4-curl php7.4-gd php7.4-intl php7.4-mysql php7.4-xml php7.4-xmlrpc php7.4-ldap php7.4-zip php7.4-soap php7.4-mbstring\n\n# Firewall\nufw allow http \nufw allow https\n\n# Secure MySQL\nrun_mysql_secure_installation_ubuntu20\n\n# Install Moodle\ncd /var/www/html\ngit clone git://git.moodle.org/moodle.git\ncd moodle\ngit branch --track MOODLE_39_STABLE origin/MOODLE_39_STABLE\ngit checkout MOODLE_39_STABLE\n\n# Configure Moodle\nmkdir /var/moodledata\nchmod -R 777 /var/moodledata \nchmod -R 755 /var/www/html/moodle \n\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"CREATE DATABASE moodle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\"\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"CREATE USER 'moodle'@'localhost' IDENTIFIED BY '$DB_PASSWORD';\";\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,CREATE TEMPORARY TABLES,DROP,INDEX,ALTER ON moodle.* TO 'moodle'@'localhost';\"\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"FLUSH PRIVILEGES\";\n\ncat < /etc/apache2/sites-available/moodle.conf\n\n ServerAdmin admin@$FQDN\n DocumentRoot /var/www/html/moodle/\n ServerName $FQDN\n ServerAlias www.$FQDN \n \n Options +FollowSymlinks\n AllowOverride All\n Require all granted\n \n ErrorLog \\${APACHE_LOG_DIR}/error.log\n CustomLog \\${APACHE_LOG_DIR}/access.log combined\n\nEND\n\na2enmod rewrite\na2ensite moodle.conf\na2dissite 000-default.conf\nservice apache2 restart\n\napt install certbot python3-certbot-apache -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\n/usr/bin/php admin/cli/install.php --chmod=777 --lang=en_us --wwwroot=https://$FQDN --dataroot=/var/moodledata/ --dbtype=mysqli --dbhost=localhost --dbname=moodle --dbuser=moodle --dbpass=$DB_PASSWORD --dbport=3306 --dbsocket=1 --prefix=mdl_ --fullname=moodle --shortname=moodle --summary=\"Moodle: Powered By Linode Marketplace\" --adminuser=moodle --adminpass=\"$ADMIN_PASSWORD\" --adminemail=$SOA_EMAIL_ADDRESS --upgradekey= --non-interactive --agree-license\n\nchown -R www-data: /var/www/html/moodle\n\n# Clean up\nstackscript_cleanup", "user_defined_fields": [ { "name": "admin_password", "label": "Moodle Admin Password" }, { "name": "soa_email_address", "label": "Moodle Admin Email" }, { "name": "dbroot_password", "label": "MySQL Root Password" }, { "name": "db_password", "label": "Moodle database User password" }, { "name": "token_password", "label": "Your Linode API token. This is required in order to create DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "username", "label": "The username for the Linode's admin/SSH user (Please ensure that the username entered does not contain any uppercase characters)", "example": "user1" }, { "name": "password", "label": "The password for the Linode's admin/SSH user", "example": "S3cuReP@s$w0rd" }, { "name": "pubkey", "label": "The SSH Public Key used to securely access the Linode via SSH", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 607026, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "MySQL/MariaDB One-Click", "description": "MySql One Click", "ordinal": 71, "logo_url": "assets/mysql.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 4585, "deployments_active": 334, "is_public": true, "mine": false, "created": "2019-10-29T19:03:33", "updated": "2023-12-06T23:34:10", "rev_note": "Initial import", "script": "#!/usr/bin/env bash\n\n## MySQL Settings\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 3306\nfail2ban_install\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\nif [[ \"$DATABASE\" == \"MySQL\" ]]; then\n # Install/configure MySQL\n apt install -y mysql-server\n # Secure MySQL install\n run_mysql_secure_installation_ubuntu20 \nelse \n # Install/configure MySQL\n apt install -y mariadb-server\n # Secure MySQL install\n run_mysql_secure_installation\nfi\n\nmysql -uroot -p$DBROOT_PASSWORD -e \"create database $DATABASE_NAME;\"\nmysql -uroot -p$DBROOT_PASSWORD -e \"CREATE USER '$DBUSER' IDENTIFIED BY '$DBUSER_PASSWORD';\"\nmysql -uroot -p$DBROOT_PASSWORD -e \"GRANT ALL PRIVILEGES ON $DATABASE_NAME.* TO '$DBUSER'@'%' WITH GRANT OPTION;\"\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "database", "label": "Would you like to install MySQL or MariaDB?", "oneof": "MySQL,MariaDB" }, { "name": "dbroot_password", "label": "MySQL Root Password", "example": "s3cur3_9a55w04d" }, { "name": "dbuser", "label": "MySQL User", "example": "user1" }, { "name": "dbuser_password", "label": "MySQL User Password", "example": "s3cur3_9a55w04d" }, { "name": "database_name", "label": "Create Database", "example": "testdb" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 970561, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "NodeJS One-Click", "description": "NodeJS One-Click", "ordinal": 72, "logo_url": "assets/nodejs.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 2145, "deployments_active": 267, "is_public": true, "mine": false, "created": "2022-02-07T17:21:41", "updated": "2023-12-07T16:17:55", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## NodeJS Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction nodejs {\n if [ \"${detected_distro[distro]}\" = 'debian' ]; then \n curl -fsSL https://deb.nodesource.com/setup_16.x | bash -\n elif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\n curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -\n else \n echo \"Setting this up for the future incase we add more distros\"\n fi\n apt-get install -y nodejs\n \n mkdir -p /opt/nodejs\n cat < /opt/nodejs/hello.js\nconst http = require('http');\n\nconst hostname = 'localhost';\nconst port = 3000;\n\nconst server = http.createServer((req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/plain');\n res.end('Hello World Powered By Linode Marketplace');\n});\n\nserver.listen(port, hostname, () => {\n console.log(`Server running at http://localhost:3000/`);\n});\nEND\n}\n\nfunction pm2nodejs {\n npm install pm2@latest -g --no-audit\n cd /opt/nodejs/\n pm2 start hello.js\n sleep 5\n pm2 startup systemd\n sleep 5\n pm2 save\n}\n\nfunction nginxnodejs {\n apt-get install nginx -y \n cat < /etc/nginx/sites-available/$FQDN\nserver {\n server_name $FQDN www.$FQDN;\n\n location / {\n proxy_pass http://localhost:3000;\n proxy_http_version 1.1;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection 'upgrade';\n proxy_set_header Host \\$host;\n proxy_cache_bypass \\$http_upgrade;\n }\n\n}\nEND\n ln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/\n unlink /etc/nginx/sites-enabled/default\n nginx -t\n systemctl reload nginx\n}\n\nfunction sslnodejs {\n apt install certbot python3-certbot-nginx -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction firewallnodejs {\n ufw allow http\n ufw allow https\n\n}\nfunction main {\n nodejs\n pm2nodejs\n firewallnodejs \n nginxnodejs \n sslnodejs \n}\n\n# Execute Script\nmain\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "This is the Email address for the LetsEncrypt SSL Certificate", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 869156, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "NirvaShare One-Click", "description": "NirvaShare One-Click", "ordinal": 73, "logo_url": "assets/nirvashare.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 216, "deployments_active": 3, "is_public": true, "mine": false, "created": "2021-07-20T19:08:35", "updated": "2023-12-06T21:21:49", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Nirvashare Settings \n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-nirvashare\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n}\n\nfunction udf {\n \n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # Nirvashare \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" } ] }, { "id": 971043, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Odoo One-Click", "description": "Odoo One-Click", "ordinal": 74, "logo_url": "assets/odoo.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 1816, "deployments_active": 81, "is_public": true, "mine": false, "created": "2022-02-08T16:21:37", "updated": "2023-12-07T15:35:58", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## ODOO Settings \n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-odoo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # ODOO vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" } ] }, { "id": 1102907, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "ONLYOFFICE Docs One-Click", "description": "ONLYOFFICE Docs One-Click app", "ordinal": 75, "logo_url": "assets/onlyoffice.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 291, "deployments_active": 13, "is_public": true, "mine": false, "created": "2022-12-20T17:50:23", "updated": "2023-12-02T15:29:24", "rev_note": "", "script": "#!/usr/bin/env bash\n# \n# \n# \n\n# SSL Settings\n# \n# \n# \n# \n\n# Enable Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n## Register default rDNS \nexport DEFAULT_RDNS=$(dnsdomainname -A | awk '{print $1}')\n\n#set absolute domain if any, otherwise use DEFAULT_RDNS\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DEFAULT_RDNS\"\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n\n# Get and install docker\n# curl -fsSL get.docker.com | sudo sh\napt install -y apt-transport-https ca-certificates curl software-properties-common\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg\necho \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null \napt update\napt install -y docker-ce\nsystemctl enable --now docker.service\n\nCONTAINER_NAME=\"onlyoffice-docs\"\n\n# Run ONLYOFFICE-Docs with SSL\nif [[ \"${SSL_ENABLED}\" == \"true\" ]]; then\n\tif [[ -z ${ABS_DOMAIN} ]]; then\n\t\techo \"Missing required LETS_ENCRYPT_DOMAIN parameter for correct SSL work\"\n\t\texit 1\n\tfi\n\tif [[ -z ${LETS_ENCRYPT_MAIL} ]]; then\n\t\techo \"Missing required LETS_ENCRYPT_MAIL parameter for correct SSL work\"\n\t\texit 1\n fi\n\tsudo docker run -i -t -d -p 80:80 -p 443:443 \\\n\t\t-e JWT_ENABLED=${JWT_ENABLED} \\\n \t\t-e JWT_SECRET=${JWT_SECRET} \\\n\t\t-e LETS_ENCRYPT_DOMAIN=${ABS_DOMAIN} \\\n -e LETS_ENCRYPT_MAIL=${LETS_ENCRYPT_MAIL} \\\n\t\t-v /app/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \\\n\t\t-v /app/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \\\n \t-v /app/onlyoffice/DocumentServer/lib:/var/lib/onlyoffice \\\n \t-v /app/onlyoffice/DocumentServer/rabbitmq:/var/lib/rabbitmq \\\n \t-v /app/onlyoffice/DocumentServer/redis:/var/lib/redis \\\n \t-v /app/onlyoffice/DocumentServer/db:/var/lib/postgresql \\\n\t\t--name ${CONTAINER_NAME} \\\n\t\tonlyoffice/documentserver:${DOCS_VERSION}\n\telse \n# Run ONLYOFFICE-Docs without SSL\n\tsudo docker run -i -t -d -p 80:80 \\\n -e JWT_ENABLED=${JWT_ENABLED} \\\n -e JWT_SECRET=${JWT_SECRET} \\\n -v /app/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \\\n -v /app/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \\\n -v /app/onlyoffice/DocumentServer/lib:/var/lib/onlyoffice \\\n -v /app/onlyoffice/DocumentServer/rabbitmq:/var/lib/rabbitmq \\\n -v /app/onlyoffice/DocumentServer/redis:/var/lib/redis \\\n -v /app/onlyoffice/DocumentServer/db:/var/lib/postgresql \\\n --name ${CONTAINER_NAME} \\\n onlyoffice/documentserver:${DOCS_VERSION}\nfi\n\n# Wait for run\nready_check() {\n echo -e \"\\e[0;32m Waiting for the launch of DocumentServer... \\e[0m\" \n for i in {1..30}; do\n echo \"Getting the DocumentServer status: ${i}\"\n OUTPUT=\"$(curl -Is http://localhost/healthcheck/ | head -1 | awk '{ print $2 }')\"\n if [ \"${OUTPUT}\" == \"200\" ]; then\n echo -e \"\\e[0;32m DocumentServer is ready \\e[0m\"\n local DS_READY\n DS_READY='yes'\n break\n else\n sleep 10\n fi\n done\n if [[ \"${DS_READY}\" != 'yes' ]]; then\n err \"\\e[0;31m Something goes wrong documentserver does not started, check logs with command --> docker logs -f ${CONTAINER_NAME} \\e[0m\"\n exit 1\n fi\n}\n\nready_check\n\n# Enable Docs-example\nsudo docker exec ${CONTAINER_NAME} supervisorctl start ds:example\n\n# Add Docs-example to autostart\nsudo docker exec ${CONTAINER_NAME} sudo sed 's,autostart=false,autostart=true,' -i /etc/supervisor/conf.d/ds-example.conf\n\n# Add MOTD \ncat >/etc/motd < >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n### Install OpenLiteSpeed and Django\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/djangosetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )\n### Reboot server\nreboot", "user_defined_fields": [] }, { "id": 923031, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "OpenLiteSpeed NodeJS One-Click", "description": "OpenLiteSpeed NodeJS One-Click", "ordinal": 77, "logo_url": "assets/openlitespeednodejs.svg", "images": [ "linode/centos7", "linode/debian10", "linode/ubuntu20.04", "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 497, "deployments_active": 20, "is_public": true, "mine": false, "created": "2021-10-18T00:52:51", "updated": "2023-12-04T04:38:59", "rev_note": "", "script": "#!/bin/bash\n### linode\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n### Install OpenLiteSpeed and NodeJS\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/nodejssetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )", "user_defined_fields": [] }, { "id": 923030, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "OpenLiteSpeed Rails One-Click", "description": "OpenLiteSpeed Rails One-Click", "ordinal": 78, "logo_url": "assets/openlitespeedrails.svg", "images": [ "linode/centos7", "linode/debian10", "linode/ubuntu20.04", "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 50, "deployments_active": 0, "is_public": true, "mine": false, "created": "2021-10-18T00:51:05", "updated": "2023-11-15T06:56:36", "rev_note": "", "script": "#!/bin/bash\n### linode\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n### Install OpenLiteSpeed and Rails\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/railssetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )", "user_defined_fields": [] }, { "id": 691622, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "OpenLiteSpeed WordPress One-Click", "description": "OpenLiteSpeed WordPress One-Click", "ordinal": 79, "logo_url": "assets/openlitespeedwordpress.svg", "images": [ "linode/centos7", "linode/debian10", "linode/ubuntu20.04", "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 7927, "deployments_active": 626, "is_public": true, "mine": false, "created": "2020-11-30T21:25:01", "updated": "2023-12-07T09:35:53", "rev_note": "", "script": "#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n### linode\n### Install OpenLiteSpeed and WordPress\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/wpimgsetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )\n### Clean up ls tmp folder\nsudo rm -rf /tmp/lshttpd/*", "user_defined_fields": [] }, { "id": 401719, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "OpenVPN One-Click", "description": "OpenVPN OCA Debian 11 & ubuntu 20", "ordinal": 80, "logo_url": "assets/OpenVPN.svg", "images": [ "linode/ubuntu20.04", "linode/debian11" ], "deployments_total": 40267, "deployments_active": 1649, "is_public": true, "mine": false, "created": "2019-03-09T03:02:02", "updated": "2023-12-07T16:05:16", "rev_note": "Install extra dependencies ", "script": "#!/bin/bash\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Install OpenVPN dependencies\napt update && apt -y install ca-certificates wget net-tools gnupg\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \nwget -qO - https://as-repository.openvpn.net/as-repo-public.gpg | apt-key add -\necho \"deb http://as-repository.openvpn.net/as/debian bullseye main\">/etc/apt/sources.list.d/openvpn-as-repo.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\nwget -qO - https://as-repository.openvpn.net/as-repo-public.gpg | apt-key add -\necho \"deb http://as-repository.openvpn.net/as/debian focal main\">/etc/apt/sources.list.d/openvpn-as-repo.list\nelse \necho \"Distro Not Supported\"\nfi\n\n## Apt Update & Install OpenVPN\napt update -y && apt -y install openvpn-as\n\n# UFW install\nufw_install\nufw allow 1194/udp\nsed -ie \"s/DEFAULT_FORWARD_POLICY=\\\"DROP\\\"/DEFAULT_FORWARD_POLICY=\\\"ACCEPT\\\"/g\" /etc/default/ufw\n\n# Cleanup\nstackscript_cleanup\n\n# Adding to display default password as last line in LISH console\nsleep 3\ncat /usr/local/openvpn_as/init.log | grep 'To login'; echo \"(password can be changed on Admin UI)\"", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is required for creating DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Admin Email for the server", "default": "" } ] }, { "id": 804172, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Owncast One-Click", "description": "Owncast One-Click", "ordinal": 81, "logo_url": "assets/owncast.svg", "images": [ "linode/debian10" ], "deployments_total": 1789, "deployments_active": 82, "is_public": true, "mine": false, "created": "2021-04-01T15:24:50", "updated": "2023-12-06T19:20:31", "rev_note": "", "script": "#!/usr/bin/bash\n#\n#\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Add owncast user\nadduser owncast --disabled-password --gecos \"\"\n\n# Install dependencies\napt-get install -y libssl-dev unzip curl\n\n# Install Owncast\nmkdir -p /opt/owncast\ncd /opt/owncast || exit\n\ncurl -s https://owncast.online/install.sh | bash\nchown -R owncast:owncast /opt/owncast\n\n# Setup Owncast as a systemd service\ncat >/etc/systemd/system/owncast.service </etc/caddy/Caddyfile </etc/motd <\n#\n#\n## LAMP Stack Settings\n#\n#\n#\n#\n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n\n# This also sets some useful variables, like $IP and $FQDN\nsource \n\n## Update\napt_setup_update\n\n## Local Functions used by this StackScript\nfunction owncloud_install {\n system_install_package unzip php-gd php-json php-curl php-mbstring \\\n php-intl php-imagick php-xml php-zip\n PHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\n cd /var/www\n wget https://download.owncloud.com/server/stable/owncloud-complete-latest.zip\n unzip owncloud-complete-latest.zip\n chown -R www-data:www-data owncloud\n rm owncloud-complete-latest.zip\n local -a input_text=(\n \"Alias / \\\"/var/www/owncloud/\\\"\"\n \"\"\n \" Options +FollowSymlinks\"\n \" AllowOverride All\"\n \"\"\n \" Dav off\"\n \"\"\n \"SetEnv HOME /var/www/owncloud\"\n \"SetEnv HTTP_HOME /var/www/owncloud\"\n \"\"\n )\n for i in \"${input_text[@]}\"; do\n echo \"$i\" >> /etc/apache2/sites-available/owncloud.conf\n done\n a2ensite owncloud\n a2enmod rewrite headers env dir mime\n sed -i '/^memory_limit =/s/=.*/= 512M/' /etc/php/$PHP_VERSION/apache2/php.ini\n systemctl restart apache2\n echo \"ownCloud is installed\"\n}\n\nfunction owncloud_vhost_configure {\n local -r fqdn=\"$1\"\n local -r soa_email_address=\"$2\"\n local -a input_text=(\n \"\"\n \" ServerName ${fqdn}\"\n \" ServerAdmin ${soa_email_address}\"\n \" DocumentRoot /var/www/owncloud\"\n \" \"\n \" Require all granted\"\n \" AllowOverride All\"\n \" Options FollowSymLinks MultiViews\"\n \" SetEnv HOME /var/www/owncloud\"\n \" SetEnv HTTP_HOME /var/www/owncloud\"\n \" \"\n \"\"\n )\n echo \"\" >> /etc/apache2/sites-available/owncloud.conf\n for i in \"${input_text[@]}\"; do\n echo \"$i\" >> /etc/apache2/sites-available/owncloud.conf\n done\n}\n\n## Main Script\n# Install and configure the LAMP Stack\nlamp_stack \"$DB_NAME\" \"$DB_ROOT_PASSWORD\" \"${DB_USERNAME:-owncloud}\" \"$DB_USER_PASSWORD\"\n\n# Install ownCloud to be accessed via domain and configure the VirtualHost\nowncloud_install \"$FQDN\"\nowncloud_vhost_configure \"$FQDN\" \"$SOA_EMAIL_ADDRESS\"\n\n# Configure ownCloud - This replaces the installer GUI that was in the previous version of this OCA\nsudo -u www-data php /var/www/owncloud/occ maintenance:install \\\n --database \"mysql\" \\\n --database-name \"$DB_NAME\" \\\n --database-user \"${DB_USERNAME:-owncloud}\" \\\n --database-pass \"$DB_USER_PASSWORD\" \\\n --admin-user \"$OC_ADMIN\" \\\n --admin-pass \"$OC_ADMIN_PASSWORD\"\nsudo -u www-data php /var/www/owncloud/occ conf:sys:set trusted_domains 1 --value=$FQDN\nsudo -u www-data php /var/www/owncloud/occ conf:sys:set trusted_domains 2 --value=$IP\necho \"Trusted Domain setting added\"\n\n# Open the needed firewall ports\nufw allow http\nufw allow https\napt install certbot python3-certbot-apache -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\n# Clean up\nstackscript_cleanup", "user_defined_fields": [ { "name": "oc_admin", "label": "The name of the admin user for ownCloud" }, { "name": "oc_admin_password", "label": "The password for ownCloud's admin user" }, { "name": "soa_email_address", "label": "Admin Email for the ownCloud server" }, { "name": "db_name", "label": "The name of the database", "default": "owncloud" }, { "name": "db_root_password", "label": "The root password for the database" }, { "name": "db_username", "label": "The name of the database user to create", "default": "owncloud" }, { "name": "db_user_password", "label": "The password for the created database user" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is required for creating DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" } ] }, { "id": 1102906, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Passky One-Click", "description": "Passky One-Click app", "ordinal": 83, "logo_url": "assets/passky.svg", "images": [ "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 184, "deployments_active": 11, "is_public": true, "mine": false, "created": "2022-12-20T17:48:51", "updated": "2023-12-07T09:51:25", "rev_note": "", "script": "#!/bin/bash\n\n# \n# \n# \n# \n\n# Motd\ncat << EOF > /etc/motd\n _____ _ \n | __ \\ | | \n | |__) |_ _ ___ ___| | ___ _ \n | ___/ _\\` / __/ __| |/ / | | |\n | | | (_| \\__ \\__ \\ <| |_| |\n |_| \\__,_|___/___/_|\\_\\\\__, |\n __/ |\n |___/ \nInstalling...\nPlease logout and come back in few minutes.\nEOF\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\nDEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::options::=\"--force-confdef\" -o DPkg::options::=\"--force-confold\" install grub-pc\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n## Import the Bash StackScript Library\nsource \n\n# Install docker compose\nsystem_install_package docker-compose\n\n#\n# Passky Server\n#\nwget https://github.com/Rabbit-Company/Passky-Server/releases/latest/download/passky-server.tar.xz\ntar -xf passky-server.tar.xz\ncd passky-server\ncp .env.example .env\n\nSERVER_CORES=$(grep -c ^processor /proc/cpuinfo)\nIP_ADDRESS=$(system_primary_ip)\n\nsed -i \"s/SERVER_CORES=1/SERVER_CORES=$SERVER_CORES/g\" .env\nsed -i \"s/ADMIN_USERNAME=admin/ADMIN_USERNAME=$ADMINUSER/g\" .env\nsed -i \"s/ADMIN_PASSWORD=/ADMIN_PASSWORD=$ADMIN_PASSWORD/g\" .env\n\ndocker-compose up -d\n\napache_install\na2enmod proxy && a2enmod proxy_http && systemctl restart apache2\necho \"\" > /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyPreserveHost On\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyRequests Off\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ServerName $WEBSITE\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyPass / http://localhost:8080/\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyPassReverse / http://localhost:8080/\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \"\" >> /etc/apache2/sites-available/$WEBSITE.conf\na2ensite \"$WEBSITE\"\nsystemctl restart apache2\n\n# Install SSL\nsystem_install_package python3-certbot-apache\ncat << EOF > /usr/local/bin/installCert\n#!/bin/bash\nif ! certbot -n --apache --agree-tos --redirect -d $WEBSITE -m $EMAIL; then\n echo \"There was a problem while installing SSL certificate. Make sure your A record for domain: $WEBSITE does redirect to IP: $IP_ADDRESS\"\nelse\n echo \"Certificate installed successfully.\"\nfi\nEOF\nchmod +x /usr/local/bin/installCert\n\n# Configure auto-renewal for the certificate\ncrontab -l > cron\necho \"0 4 * * * /usr/bin/certbot renew\" >> cron\ncrontab cron\nrm cron\n\nstackscript_cleanup\n\n# Motd\ncat << EOF > /etc/motd\n _____ _ \n | __ \\ | | \n | |__) |_ _ ___ ___| | ___ _ \n | ___/ _\\` / __/ __| |/ / | | |\n | | | (_| \\__ \\__ \\ <| |_| |\n |_| \\__,_|___/___/_|\\_\\\\__, |\n __/ |\n |___/ \nAdmin Panel:\n Link: http://$IP_ADDRESS (https://$WEBSITE)\n Username: $ADMINUSER\n Password: $ADMIN_PASSWORD\nTo install SSL certificate please run command: installCert\nEOF", "user_defined_fields": [ { "name": "website", "label": "Website", "example": "passky.domain.com" }, { "name": "email", "label": "Email Address", "example": "info@rabbit-company.com" }, { "name": "adminuser", "label": "Admin Username" }, { "name": "admin_password", "label": "Admin Password" } ] }, { "id": 804143, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Peppermint One-Click", "description": "Peppermint One-Click", "ordinal": 84, "logo_url": "assets/peppermint.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 1862, "deployments_active": 121, "is_public": true, "mine": false, "created": "2021-04-01T12:45:15", "updated": "2023-12-06T21:22:36", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Peppermint setup\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-peppermint\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n \n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" } ] }, { "id": 644908, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Percona (PMM) One-Click", "description": "Percona One-Click", "ordinal": 85, "logo_url": "assets/percona.svg", "images": [ "linode/debian10" ], "deployments_total": 193, "deployments_active": 8, "is_public": true, "mine": false, "created": "2020-04-30T14:49:38", "updated": "2023-12-07T01:51:22", "rev_note": "", "script": "#!/bin/bash\n# \n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Docker\napt -y install docker.io\nsystemctl enable docker.service\n\n#PMM \ndocker pull percona/pmm-server:2\ndocker create -v /srv --name pmm2-data percona/pmm-server:2 /bin/true\ndocker run -d -p 80:80 -p 443:443 \\\n --volumes-from pmm2-data \\\n --name pmm2-server \\\n --restart always percona/pmm-server:2\n\necho \"Waiting for PMM to initialize to set password...\"\n\nuntil [ \"`docker inspect -f {{.State.Health.Status}} pmm2-server`\" = \"healthy\" ]; do sleep 1; done\n\ndocker exec -t pmm2-server bash -c \"ln -s /srv/grafana /usr/share/grafana/data; grafana-cli --homepath /usr/share/grafana admin reset-admin-password $PMMPASSWORD\"\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "pmmpassword", "label": "Admin Password", "example": "Admin User Password for PMM Server" } ] }, { "id": 609018, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "phpMyAdmin One-Click", "description": "phpMyAdmin One-Click", "ordinal": 86, "logo_url": "assets/phpmyadmin.svg", "images": [ "linode/debian11" ], "deployments_total": 2160, "deployments_active": 117, "is_public": true, "mine": false, "created": "2019-11-05T00:28:33", "updated": "2023-12-07T11:50:25", "rev_note": "Initial import", "script": "#!/bin/bash\n#\n#\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname\nset_hostname\n\n# Update system\napt_setup_update\n\n# Install/configure MySQL, Add Admin User\napt-get install -y mariadb-server\nsystemctl enable mariadb --now\nrun_mysql_secure_installation\nmysql -u root -e \"CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DBUSER_PASSWORD'\"\nmysql -u root -e \"GRANT ALL PRIVILEGES ON *.* TO '$DB_USER'@'localhost' WITH GRANT OPTION\"\nmysql -u root -e \"FLUSH PRIVILEGES\"\n\n# Install PHP\necho 'phpmyadmin phpmyadmin/dbconfig-install boolean true' | debconf-set-selections\necho 'phpmyadmin phpmyadmin/mysql/admin-pass password $DBROOT_PASSWORD' | debconf-set-selections\necho 'phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2' | debconf-set-selections\napt-get install -y phpmyadmin libapache2-mod-php7.4\n\n# Configure ufw\nufw_install\nufw allow http\nufw reload\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "db_user", "label": "phpMyAdmin/MySQL Admin User", "example": "admin" }, { "name": "dbuser_password", "label": "phpMyAdmin/MySQL Admin Password" }, { "name": "dbroot_password", "label": "MySQL root Password" } ] }, { "id": 970522, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Pi-hole One-Click", "description": "Pi-hole One-Click", "ordinal": 87, "logo_url": "assets/pihole.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 3898, "deployments_active": 259, "is_public": true, "mine": false, "created": "2022-02-07T16:04:53", "updated": "2023-12-07T06:09:53", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## PIHOLE Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nIPV4=$(ip a | awk '/inet / {print $2}'| sed -n '2 p')\nIPV6=$(ip -6 a | grep inet6 | awk '/global/{print $2}' | cut -d/ -f1)\nGENPIHOLEPASSWD=$(echo -n $PIHOLE_PASSWORD | sha256sum | awk '{printf \"%s\",$1 }' | sha256sum)\nPIHOLE_PASSWD=${GENPIHOLEPASSWD:0:-1}\n\nfunction firewall {\n ufw allow 80\n ufw allow 53\n ufw allow 67\n ufw allow 547\n ufw allow 4711\n}\n\nfunction config_pihole {\n mkdir -p /etc/pihole\n cat < /etc/pihole/setupVars.conf\nPIHOLE_INTERFACE=eth0\nIPV4_ADDRESS=$IPV4\nIPV6_ADDRESS=$IPV6\nPIHOLE_DNS_1=8.8.8.8\nPIHOLE_DNS_2=8.8.4.4\nQUERY_LOGGING=true\nINSTALL_WEB_SERVER=true\nINSTALL_WEB_INTERFACE=true\nLIGHTTPD_ENABLED=true\nCACHE_SIZE=10000\nDNS_FQDN_REQUIRED=true\nDNS_BOGUS_PRIV=true\nDNSMASQ_LISTENING=local\nWEBPASSWORD=$PIHOLE_PASSWD\nBLOCKING_ENABLED=true\nEND\n\ncurl -L https://install.pi-hole.net | bash /dev/stdin --unattended\n}\n\nfunction main {\n config_pihole\n firewall\n}\n\n# Execute script\napt_setup_update\nmain\nstackscript_cleanup", "user_defined_fields": [ { "name": "pihole_password", "label": "PIHOLE USER Password" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "This is the Email address for the SOA record", "default": "" } ] }, { "id": 662119, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Plex One-Click", "description": "Plex One-Click", "ordinal": 88, "logo_url": "assets/plex.svg", "images": [ "linode/debian10" ], "deployments_total": 2929, "deployments_active": 56, "is_public": true, "mine": false, "created": "2020-08-12T15:54:44", "updated": "2023-12-06T20:13:25", "rev_note": "", "script": "#!/bin/bash\n# INPUT VARIABLES:\n# \n# \n# \n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Limited user setup if username is not \"root\"\nif [ \"$USERNAME\" != \"root\" ]; then\n \n# ensure sudo is installed and configure secure user\n apt -y install sudo\n adduser -uid 1000 $USERNAME --disabled-password --gecos \"\"\n echo \"$USERNAME:$PASSWORD\" | chpasswd\n usermod -aG sudo $USERNAME\n \n# Harden SSH Access\n sed -i -e 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config\n \n# set home directory\n HOME=/home/$USERNAME\n \n# configure ssh key for secure user if provided\n if [ \"$SSHKEY\" != \"\" ]; then\n SSHDIR=$HOME/.ssh\n mkdir $SSHDIR && echo \"$SSHKEY\" >> $SSHDIR/authorized_keys\n chmod -R 700 $SSHDIR && chmod 600 $SSHDIR/authorized_keys\n chown -R $USERNAME:$USERNAME $SSHDIR\n fi\n \n# Enable SSH hardening\n systemctl restart sshd\n \n# Create docker group, add limited user, and enable\n groupadd docker\n usermod -aG docker $USERNAME\nfi\n\n# Install and configure UFW for Plex\nufw_install\nufw allow 32400,3005,8324,32469/tcp\nufw allow 1900,32410,32412,32413,32414/udp\n\n# Install the dependencies & add Docker to the APT repository\napt install -y apt-transport-https ca-certificates curl software-properties-common gnupg2\ncurl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable\"\n\n# Update & install Docker-CE\napt_setup_update\napt install -y docker-ce\n\n# Install plex as limited user\ndocker pull plexinc/pms-docker\ndocker run \\\n -d \\\n --name plex \\\n --restart always \\\n -p 32400:32400/tcp \\\n -p 3005:3005/tcp \\\n -p 8324:8324/tcp \\\n -p 32469:32469/tcp \\\n -p 1900:1900/udp \\\n -p 32410:32410/udp \\\n -p 32412:32412/udp \\\n -p 32413:32413/udp \\\n -p 32414:32414/udp \\\n -e ADVERTISE_IP=\"http://$IP:32400/\" \\\n -h \"Linode Plex Server\" \\\n -v $HOME/plex/config:/config \\\n -v $HOME/plex/media:/media \\\n -v $HOME/plex/transcode:/transcode \\\n plexinc/pms-docker\n\n# Recursively update ownership of Plex directories after delay\nsleep 1\nchown -R $USERNAME:$USERNAME $HOME/plex\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "USERNAME", "label": "Limited User Name (not 'root')" }, { "name": "PASSWORD", "label": "Limited User Password" }, { "name": "SSHKEY", "label": "Limited User SSH Key", "default": "", "example": "Usually found in: ./ssh/id_rsa.pub" } ] }, { "id": 611376, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "PostgreSQL One-Click", "description": "PostgreSQL One-Click", "ordinal": 89, "logo_url": "assets/postgresql.svg", "images": [ "linode/debian11" ], "deployments_total": 2847, "deployments_active": 217, "is_public": true, "mine": false, "created": "2019-11-13T06:05:28", "updated": "2023-12-07T14:14:50", "rev_note": "Initial import", "script": "#!/bin/bash\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 22\nufw allow 5432\n\n# Install PostgreSQL\napt install -y postgresql postgresql-contrib\nsystemctl enable postgresql\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 1068726, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "PostgreSQL Cluster One-Click", "description": "PostgreSQL Cluster", "ordinal": 90, "logo_url": "assets/postgresqlmarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 162, "deployments_active": 9, "is_public": true, "mine": false, "created": "2022-10-03T20:11:59", "updated": "2023-12-07T01:41:12", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n\n# set force apt non-interactive\nexport DEBIAN_FRONTEND=noninteractive\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/postgresql-occ.git\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/postgresql-cluster\" ]; then\n rm -rf /tmp/postgresql-cluster\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[info] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[+] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction setup {\n # install dependancies\n export DEBIAN_FRONTEND=non-interactive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n configure_privateip\n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n if [ ! -d ~/.ssh ]; then \n mkdir ~/.ssh\n else \n echo \".ssh directory is already created\"\n fi\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/postgresql-cluster\n cd /tmp/postgresql-cluster\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"", "user_defined_fields": [ { "name": "token_password", "label": "Your Linode API token" }, { "name": "cluster_name", "label": "Domain Name" }, { "name": "sudo_username", "label": "The limited sudo user to be created in the cluster" }, { "name": "add_ssh_keys", "label": "Add Account SSH Keys to All Nodes?", "oneof": "yes,no", "default": "yes" }, { "name": "cluster_size", "label": "PostgeSQL cluster size", "default": "3", "oneof": "3" } ] }, { "id": 985364, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Prometheus & Grafana One-Click", "description": "Prometheus and Grafana", "ordinal": 91, "logo_url": "assets/prometheusgrafana.svg", "images": [ "linode/ubuntu20.04", "linode/ubuntu22.04" ], "deployments_total": 574, "deployments_active": 60, "is_public": true, "mine": false, "created": "2022-03-08T17:03:20", "updated": "2023-12-05T22:31:38", "rev_note": "", "script": "#!/usr/bin/env bash\n## Updated: 01-17-2023\n## Author: n0vabyte, Elvis Segura, esegura@linode.com\n\n#\n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\ncreds=\"/root/credentials.txt\"\nprometheus_htpasswd_file=\"/etc/nginx/.prometheus_htpasswd\"\n\nfunction add_firewalls {\n ufw allow http\n ufw allow https\n}\n\nfunction configure_nginx {\n apt-get install nginx apache2-utils -y\n cat << EOF > /etc/nginx/sites-available/$FQDN.conf\nserver {\n listen 80;\n server_name $FQDN;\n location / {\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header Host \\$http_host;\n proxy_pass http://localhost:3000;\n }\n location /prometheus/ {\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header Host \\$http_host;\n proxy_pass http://localhost:9090;\n auth_basic \"Restricted Area\";\n auth_basic_user_file $prometheus_htpasswd_file;\n }\n# allow let's encrypt\n location ^~ /.well-known {\n allow all;\n auth_basic off;\n alias /var/www/html/.well-known;\n }\n}\nEOF\n\n ln -s /etc/nginx/sites-{available,enabled}/$FQDN.conf\n unlink /etc/nginx/sites-enabled/default\n systemctl reload nginx\n systemctl enable nginx\n}\n\nfunction install_node_exporter {\n groupadd --system prometheus\n useradd -s /sbin/nologin --system -g prometheus prometheus\n curl -s https://api.github.com/repos/prometheus/node_exporter/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '\"' -f 4 | wget -qi - \n tar -xvf node_exporter*.tar.gz\n chmod +x node_exporter-*/node_exporter\n chown prometheus:prometheus node_exporter\n mv node_exporter-*/node_exporter /usr/local/bin\n rm -fr node_exporter-*\n cat < /etc/systemd/system/node_exporter.service\n[Unit]\nDescription=Node Exporter\nWants=network-online.target\nAfter=network-online.target\n[Service]\nUser=prometheus\nExecStart=/usr/local/bin/node_exporter\n[Install]\nWantedBy=default.target\nEOF\n systemctl daemon-reload\n systemctl start node_exporter\n systemctl enable node_exporter\n}\n\nfunction configure_prometheus {\n latest_version=$(curl -s https://raw.githubusercontent.com/prometheus/prometheus/main/VERSION)\n prom_conf=\"/etc/prometheus/prometheus.yml\"\n file_sd_targets=\"/etc/prometheus/file_sd_targets\"\n prometheus_conf_dir=\"/etc/prometheus\"\n prometheus_data_dir=\"/var/lib/prometheus\"\n mkdir $prometheus_conf_dir $prometheus_conf_dir/file_sd_targets \\\n $prometheus_conf_dir/rules $prometheus_data_dir\n\n wget https://github.com/prometheus/prometheus/releases/download/v$latest_version/prometheus-$latest_version.linux-amd64.tar.gz\n tar xvf prometheus-$latest_version.linux-amd64.tar.gz\n mv prometheus-$latest_version.linux-amd64/* $prometheus_conf_dir\n chown -R prometheus:prometheus $prometheus_conf_dir $prometheus_data_dir\n mv $prometheus_conf_dir/{prometheus,promtool} /usr/local/bin\n ## cleanup\n rm prometheus-$latest_version.linux-amd64.tar.gz\n rmdir prometheus-$latest_version.linux-amd64\n\n ## backup config before updating\n cp $prom_conf{,.bak}\n sed -i -e '/- job_name: \"prometheus\"/ s/^/#/' $prom_conf\n sed -i -e '/- targets:/ s/^/#/' $prom_conf\n sed -i -e '/static_configs/ s/^/#/g' $prom_conf\n ## add our config\n cat << EOF >> $prom_conf\n#########################################\n## Local Prometheus Instance - This Box #\n#########################################\n - job_name: local_prometheus\n scrape_interval: 3s\n file_sd_configs:\n - files:\n - file_sd_targets/local_prometheus.yml\n honor_labels: true\n relabel_configs:\n - regex: (.*)\n replacement: \\${1}:9100\n source_labels:\n - __address__\n target_label: __address__\n - regex: (.+)\n replacement: \\${1}\n source_labels:\n - __instance\n target_label: instance\nEOF\n ## add to file_sd_targets\n cat << EOF >> $file_sd_targets/local_prometheus.yml\n- labels:\n __instance: prometheus\n cluster: local\n targets:\n - 127.0.0.1\nEOF\n cat << EOF > /etc/systemd/system/prometheus.service\n[Unit]\nDescription=Prometheus\nDocumentation=https://prometheus.io/docs/introduction/overview/\nWants=network-online.target\nAfter=network-online.target\n[Service]\nUser=prometheus\nGroup=prometheus\nType=simple\nExecStart=/usr/local/bin/prometheus \\\n--config.file /etc/prometheus/prometheus.yml \\\n--storage.tsdb.path $prometheus_data_dir/ \\\n--web.console.templates=$prometheus_conf_dir/consoles \\\n--web.console.libraries=$prometheus_conf_dir/console_libraries \\\n--web.listen-address=127.0.0.1:9090 \\\n--web.external-url=https://$FQDN/prometheus \\\n--storage.tsdb.retention=60d\nRestart=always\nExecReload=/usr/bin/kill -HUP \\$MAINPID\nTimeoutStopSec=20s\nOOMScoreAdjust=-900\nSendSIGKILL=no\n[Install]\nWantedBy=multi-user.target\nEOF\n systemctl daemon-reload\n systemctl start prometheus\n systemctl enable prometheus\n\n ## protect with htpasswd\n prometheus_htpasswd=$(openssl rand -base64 32)\n htpasswd -cb $prometheus_htpasswd_file prometheus $prometheus_htpasswd\n ## log credentials locally\n cat << EOF >> $creds\n#################\n# Prometheus #\n#################\nLocation: https://$FQDN/prometheus\nUsername: prometheus\nPassword: $prometheus_htpasswd\nEOF\n ## sanity check\n function fallback {\n echo \"[FATAL] Creating custom configuration failed. Restoring old configuration\"\n cp $prom_conf{.bak,}\n systemctl restart prometheus\n sleep 2\n systemctl is-active prometheus\n if [ $? -ne 0 ]; then\n echo \"[CRITICAL] Encoutered unexpected error while configuring Prometheus. Please reach out to Support.\"\n exit 2\n fi\n }\n systemctl is-active prometheus\n if [ $? -ne 0 ]; then\n echo \"[ERROR] Prometheus is not running. Falling back to default config..\"\n fallback\n fi\n\n}\n\nfunction configure_grafana {\n echo \"[info] configuring Grafana - Installing Packages\"\n apt-get install -y apt-transport-https \\\n software-properties-common \\\n wget \\\n gnupg2 \\\n sqlite3\n\n wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key\n echo \"deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main\" | sudo tee -a /etc/apt/sources.list.d/grafana.list\n apt-get -y update\n apt-get -y install grafana\n\n ## reset Grafana admin password\n grafana_password=$(openssl rand -base64 32)\n\n echo \"[info] updating grafana config\"\n sed -i -e 's/;admin_user = admin/admin_user = admin/g' /etc/grafana/grafana.ini\n sed -i \"s|;admin_password = admin|admin_password = $grafana_password|g\" /etc/grafana/grafana.ini\n\n echo \"[info] starting grafana-server\"\n systemctl start grafana-server\n systemctl enable grafana-server\n\n ## log credentials locally\n cat << EOF >> $creds\n##############\n# Grafana #\n##############\nLocation: https://$FQDN/\nUsername: admin\nPassword: $grafana_password\nEOF\n}\n\nfunction ssl_grafana {\n apt install -y certbot python3-certbot-nginx\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction main {\n add_firewalls\n configure_nginx\n install_node_exporter\n configure_prometheus\n configure_grafana\n ssl_grafana\n}\n\n## execute script\nmain\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "This email is for the LetsEncrypt SSL certificate" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 607034, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Prometheus One-Click", "description": "Prometheus One Click App", "ordinal": 92, "logo_url": "assets/prometheus.svg", "images": [ "linode/debian10" ], "deployments_total": 355, "deployments_active": 12, "is_public": true, "mine": false, "created": "2019-10-29T20:59:30", "updated": "2023-12-01T08:40:40", "rev_note": "Initial import", "script": "#!/bin/bash\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Prometheus\ngroupadd --system prometheus\nuseradd -s /sbin/nologin --system -g prometheus prometheus\nmkdir /var/lib/prometheus\nfor i in rules rules.d files_sd; do mkdir -p /etc/prometheus/${i}; done\napt-get -y install wget\nmkdir -p /tmp/prometheus && cd /tmp/prometheus\ncurl -s https://api.github.com/repos/prometheus/prometheus/releases/latest \\\n | grep browser_download_url \\\n | grep linux-amd64 \\\n | cut -d '\"' -f 4 \\\n | wget -qi -\ntar xvf prometheus*.tar.gz\ncd prometheus*/\nmv prometheus promtool /usr/local/bin/\nmv prometheus.yml /etc/prometheus/prometheus.yml\nmv consoles/ console_libraries/ /etc/prometheus/\ncd ~/\nrm -rf /tmp/prometheus\n\n# Edit Prometheus config\nsudo tee /etc/prometheus/prometheus.yml</etc/systemd/system/prometheus.service\n[Unit]\nDescription=Prometheus\nDocumentation=https://prometheus.io/docs/introduction/overview/\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nType=simple\nUser=prometheus\nGroup=prometheus\nExecReload=/bin/kill -HUP $MAINPID\nExecStart=/usr/local/bin/prometheus \\\n --config.file=/etc/prometheus/prometheus.yml \\\n --storage.tsdb.path=/var/lib/prometheus \\\n --web.console.templates=/etc/prometheus/consoles \\\n --web.console.libraries=/etc/prometheus/console_libraries \\\n --web.listen-address=0.0.0.0:9090 \\\n --web.external-url=\n\nSyslogIdentifier=prometheus\nRestart=always\nRestartSec=3\n\n[Install]\nWantedBy=multi-user.target\nEND\n\nfor i in rules rules.d files_sd; do chown -R prometheus:prometheus /etc/prometheus/${i}; done\nfor i in rules rules.d files_sd; do chmod -R 775 /etc/prometheus/${i}; done\nchown -R prometheus:prometheus /var/lib/prometheus/\n\n# Add node_exporter & Enable services\ncurl -s https://api.github.com/repos/prometheus/node_exporter/releases/latest \\\n| grep browser_download_url \\\n| grep linux-amd64 \\\n| cut -d '\"' -f 4 \\\n| wget -qi -\n\ntar -xvf node_exporter*.tar.gz\ncd node_exporter*/\ncp node_exporter /usr/local/bin\nnode_exporter --version\n\ncat </etc/systemd/system/node_exporter.service\n[Unit]\nDescription=Node Exporter\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nUser=prometheus\nExecStart=/usr/local/bin/node_exporter\n\n[Install]\nWantedBy=default.target\nEND\n\nsystemctl daemon-reload\nsystemctl start prometheus\nsystemctl enable prometheus\nsystemctl start node_exporter\nsystemctl enable node_exporter\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [] }, { "id": 688890, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "RabbitMQ One-Click", "description": "RabbitMQ One-Click", "ordinal": 93, "logo_url": "assets/rabbitmq.svg", "images": [ "linode/debian10" ], "deployments_total": 392, "deployments_active": 49, "is_public": true, "mine": false, "created": "2020-11-17T20:53:00", "updated": "2023-12-06T00:35:01", "rev_note": "", "script": "#!/bin/bash\n#\n#\n\n# Logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Set hostname, configure apt and perform update/upgrade\napt_setup_update\n\n## Install prerequisites\napt-get install curl gnupg -y\n\n## Get RabbitMQ \n$ curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo apt-key add -\nsudo apt-key adv --keyserver \"hkps://keys.openpgp.org\" --recv-keys \"0x0A9AF2115F4687BD29803A206B73A36E6026DFCA\"\n## Install apt HTTPS transport\napt-get install apt-transport-https\n\n## Add Bintray repositories that provision latest RabbitMQ and Erlang 23.x releases\ntee /etc/apt/sources.list.d/bintray.rabbitmq.list <\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# System Update\nset_hostname\napt_setup_update\n\nfunction install_redis {\n apt install -y redis-server\n systemctl enable redis-server\n}\n\nfunction redis_config {\n sed -ie \"s/supervised no/supervised systemd/g\" /etc/redis/redis.conf\n sed -ie \"s/appendonly no/appendonly yes/g\" /etc/redis/redis.conf\n systemctl restart redis-server\n}\n\nfunction main {\n install_redis\n redis_config\n}\nmain\n\n# cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address for SOA Recorf", "default": "" } ] }, { "id": 1132204, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Marketplace App for Redis® Sentinel Cluster One-Click", "description": "Redis Sentinel One-Click Cluster", "ordinal": 95, "logo_url": "assets/redissentinelmarketplaceocc.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 136, "deployments_active": 8, "is_public": true, "mine": false, "created": "2023-02-27T20:05:44", "updated": "2023-12-06T05:47:35", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/redis-occ.git\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# source script libraries\nsource \n\nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/linode\" ]; then\n rm -rf /tmp/linode\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\n\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\n\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\n\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[warn] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\n\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[info] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\n\nfunction setup {\n # install dependencies\n export DEBIAN_FRONTEND=non-interactive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n configure_privateip \n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n if [ ! -d ~/.ssh ]; then \n mkdir ~/.ssh\n else \n echo \".ssh directory is already created\"\n fi\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/linode\n cd /tmp/linode\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"", "user_defined_fields": [ { "name": "token_password", "label": "Your Linode API token" }, { "name": "sudo_username", "label": "The limited sudo user to be created in the cluster" }, { "name": "sslheader", "label": "SSL Information", "header": "Yes", "default": "Yes", "required": "Yes" }, { "name": "country_name", "label": "Details for self-signed SSL certificates: Country or Region", "oneof": "AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW" }, { "name": "state_or_province_name", "label": "State or Province", "example": "Example: Pennsylvania" }, { "name": "locality_name", "label": "Locality", "example": "Example: Philadelphia" }, { "name": "organization_name", "label": "Organization", "example": "Example: Akamai Technologies" }, { "name": "email_address", "label": "Email Address", "example": "Example: user@domain.tld" }, { "name": "ca_common_name", "label": "CA Common Name", "default": "Redis CA" }, { "name": "common_name", "label": "Common Name", "default": "Redis Server" }, { "name": "clusterheader", "label": "Cluster Settings", "default": "Yes", "header": "Yes" }, { "name": "add_ssh_keys", "label": "Add Account SSH Keys to All Nodes?", "oneof": "yes,no", "default": "yes" }, { "name": "cluster_size", "label": "Redis cluster size", "default": "3", "oneof": "3,5" } ] }, { "id": 923036, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Restyaboard One-Click", "description": "Restyaboard One-Click", "ordinal": 96, "logo_url": "assets/restyaboard.svg", "images": [ "linode/centos7", "linode/debian10", "linode/ubuntu20.04" ], "deployments_total": 209, "deployments_active": 2, "is_public": true, "mine": false, "created": "2021-10-18T01:07:09", "updated": "2023-12-03T04:43:28", "rev_note": "", "script": "#!/bin/bash\n#\n# Install script for Restyaboard\n#\n# Usage: ./restyaboard.sh\n#\n# Copyright (c) 2014-2021 Restya.\n# Dual License (OSL 3.0 & Commercial License)\n{\n\tmain() {\n\t\tif [[ $EUID -ne 0 ]];\n\t\tthen\n\t\t\techo \"This script must be run as root\"\n\t\t\texit 1\n\t\tfi\n\t\tset -x\n\t\twhoami\n\t\t#\n\t\t# Checking the OS name and OS version\n\t\t#\n\t\tfind_release ()\n\t\t{\n\t\t\t# Checking the Ubuntu OS\n\t\t\tif [ -f /etc/lsb-release ]; then\n\t\t\t\tOS_REQUIREMENT=\"`grep DISTRIB_ID /etc/lsb-release`\"\n\t\t\t\tDISTRIB_ID='DISTRIB_ID='\n\t\t\t\tOS_NAME=$OS_REQUIREMENT$DISTRIB_ID\n\t\t\t\tarray=();\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" != \"$DISTRIB_ID\" ])\n\t\t\t\tthen\n\t\t\t\t\twhile [[ $OS_NAME ]]; do\n\t\t\t\t\tarray+=( \"${OS_NAME%%\"$DISTRIB_ID\"*}\" );\n\t\t\t\t\tOS_NAME=${OS_NAME#*\"$DISTRIB_ID\"};\n\t\t\t\t\tdone;\n\t\t\t\t\tOS_REQUIREMENT=${array[1]}\n\t\t\t\tfi\n\t\t\t\tOS_VERSION=\"`grep DISTRIB_RELEASE /etc/lsb-release`\"\n\t\t\t\tDISTRIB_RELEASE='DISTRIB_RELEASE='\n\t\t\t\tOS_Ver=$OS_VERSION$DISTRIB_RELEASE\n\t\t\t\tversion=();\n\t\t\t\tif ([ \"$OS_VERSION\" != \"$DISTRIB_RELEASE\" ])\n\t\t\t\tthen\n\t\t\t\t\twhile [[ $OS_Ver ]]; do\n\t\t\t\t\tversion+=( \"${OS_Ver%%\"$DISTRIB_RELEASE\"*}\" );\n\t\t\t\t\tOS_Ver=${OS_Ver#*\"$DISTRIB_RELEASE\"};\n\t\t\t\t\tdone;\n\t\t\t\t\tOS_VERSION=${version[1]}\n\t\t\t\tfi\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t\t# Checking the Redhat, Fedora, and Centos\n\t\t\tif [ -f /etc/redhat-release ]; then\n\t\t\t\tOS_REQUIREMENT=\"`cat /etc/redhat-release | cut -d ' ' -f 1`\"\n\t\t\t\tOS_VERSION=\"`cat /etc/redhat-release | cut -d ' ' -f 4 | cut -d '.' -f 1`\"\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t\t# Checking the Debian OS\n\t\t\tif [ -f /etc/issue ]; then\n\t\t\t\tOS_REQUIREMENT=\"`cat /etc/issue | cut -d ' ' -f 1`\"\n\t\t\t\tOS_VERSION=\"`cat /etc/issue | cut -d ' ' -f 3`\"\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t\t# Checking the OpenBSD \n\t\t\tif [ -f /etc/motd ]; then\n\t\t\t\tOS_REQUIREMENT=\"`cat /etc/motd | head -1 | cut -d ' ' -f 1`\"\n\t\t\t\tOS_VERSION=\"`cat /etc/motd | head -1 | cut -d ' ' -f 2`\"\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t}\n\t\tfindbin ()\n {\n ret=0\n newpath=`echo $PATH | tr : ' '`\n for i in ${newpath}; do\n\t\t\t\tif [ -x $i/$1 ]; then\n\t\t\t\t\tret=1\n\t\t\t\t\tbreak\n\t\t\t\tfi\n done\n echo $ret\n return \n }\n checkdeps()\n {\n pkginfo=\"dpkg rpm ipkg pkg_info\"\n for i in $pkginfo; do\n ret=`findbin $i`\n if [ $ret -eq 1 ]; then\n\t\t\t\t\tpkginfo=$i\n\t\t\t\t\techo \"Yes, found $i, so we'll use that for listing packages\"\n\t\t\t\t\tbreak\n fi\n done\n\n if [ ${pkginfo} = \"pkg_info\" ]; then\n # BSD needs PKG_PATH set to load anything over the net.\n if [ x${PKG_PATH} = x ]; then\n\t\t\t\t\techo \"Please set the environment variable PKG_PATH and try again.\"\n\t\t\t\t\texit 1\n fi\n fi\n \n \n pkg_name=\"yum apt-get ipkg pkg_add\"\n for i in ${pkg_name}; do\n ret=`findbin $i`\n if [ $ret -eq 1 ]; then\n pkg_name=$i\n\t\t\t\t\techo \"Yes, found $i, so we'll use that to install packages\"\n\t\t\t\t\tbreak\n fi\n done\n \n\n for i in ${genericdeps} ${gtkdeps} ${kdedeps}; do\n case $pkginfo in\n dpkg)\n deps=\"`dpkg -l \"*$i*\" | grep -- \"^ii\" | cut -d ' ' -f 3`\"\n ;;\n rpm)\n deps=\"`rpm -q $i`\"\n ;;\n pkg_info)\n deps=\"`pkg_info | grep \"$i\" | sed -e 's: .*$::'`\"\n ;;\n ipkg)\n deps=\"todo\"\n ;;\n *)\n echo \"ERROR: No package manager found!\"\n exit 1\n ;;\n esac\n found=`echo ${deps} | grep -v 'not installed' | grep -c \"${i}\" 2>&1`\n if [ $found -gt 0 ]; then\n \techo \"Yes, found $i\"\n else\n\t\t\t\t\techo \"Nope, $i appears to not be installed\"\n\t\t\t\t\tmissing=\"${missing} $i\"\n fi\n done\n\n if [ -n \"${missing}\" ]; then\n echo \"package(s)\\\"${missing}\\\" are missing!\"\n echo \"You will need sudo priviledges to install the packages\"\n if [ x$yes = xno ]; then\n \t$debug sudo ${pkgnet} install ${missing}\n else\n \t$debug sudo ${pkgnet} -y install ${missing}\n fi\n fi\n }\n\t\tinstall_nginx() \n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n echo \"Checking nginx...\"\n if ! which nginx > /dev/null 2>&1; then\n echo \"nginx not installed!\"\n echo \"Installing nginx...\"\n apt install -y cron nginx\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"nginx installation failed with error code ${error_code} (nginx installation failed with error code 2)\"\n return 2\n fi\n if [ -f \"/etc/nginx/conf.d/default\" ]; then\n rm -rf /etc/nginx/conf.d/default\n fi\n if [ -f \"/etc/nginx/sites-enabled/default\" ]; then\n rm -rf /etc/nginx/sites-enabled/default\n fi\n if [ -f \"/etc/nginx/sites-available/default\" ]; then\n rm -rf /etc/nginx/sites-available/default\n fi\n service nginx start\n fi\n\t\t\telse\t\t\t\t\n echo \"Checking nginx...\"\n if ! which nginx > /dev/null 2>&1; then\n echo \"nginx not installed!\"\n echo \"Installing nginx...\"\n rpm -Uvh \"http://nginx.org/packages/centos/${OS_VERSION}/noarch/RPMS/nginx-release-centos-${OS_VERSION}-0.el${OS_VERSION}.ngx.noarch.rpm\"\n yum install -y zip cronie nginx\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"cron nginx installation failed with error code ${error_code} cron nginx installation failed with error code 18\"\n return 18\n fi\n if [ -f \"/etc/nginx/conf.d/default.conf\" ]; then\n rm -rf /etc/nginx/conf.d/default.conf\n fi\n if [ -f \"/etc/nginx/sites-enabled/default.conf\" ]; then\n rm -rf /etc/nginx/sites-enabled/default.conf\n fi\n if [ -f \"/etc/nginx/sites-available/default.conf\" ]; then\n rm -rf /etc/nginx/sites-available/default.conf\n fi\n service nginx start\n chkconfig --levels 35 nginx on\n fi\n\t\t\tfi\n\t\t}\n\t\tinstall_php()\n\t\t{\n\t\t\tif ! hash php 2>&-; then\n\t\t\t\techo \"PHP is not installed!\"\n if ([ \"$pkg_name\" = \"apt-get\" ])\n then\t\t\t\t\t\t\t\n echo \"Installing PHP...\"\n apt install -y php7.4 php7.4-common --allow-unauthenticated\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"PHP installation failed with error code ${error_code} (PHP installation failed with error code 3)\"\n return 3\n fi\n else \n if ([ \"$pkg_name\" = \"yum\" ])\n then\n if ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n then\n echo \"Note: For the latest version of PHP, we're going to download https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm and https://rpms.remirepo.net/enterprise/remi-release-8.rpm.\"\n echo \"Installing PHP...\"\n dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm\n dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm\n dnf module enable php:remi-7.4\n dnf -y install php php-cli php-common\n else\n yum install -y epel-release\n echo \"Note: For the latest version of PHP, we're going to download http://rpms.famillecollet.com/enterprise/remi-release-${OS_VERSION}.rpm.\"\n echo \"Installing PHP...\"\n rpm -Uvh \"http://rpms.famillecollet.com/enterprise/remi-release-${OS_VERSION}.rpm\"\n yum --enablerepo=remi-php74 install -y php\n fi\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"php installation failed with error code ${error_code} (php installation failed with error code 20)\"\n return 20\n fi\n fi\n fi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Installing PHP fpm and cli extension...\"\n\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\tthen\n\t\t\t\tapt install -y php7.4-fpm php7.4-cli --allow-unauthenticated\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"php7.4-cli installation failed with error code ${error_code} (php7.4-cli installation failed with error code 4)\"\n\t\t\t\tfi\n\t\t\t\tservice php7.4-fpm start\n\t\t\telse \n\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\tthen\n\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n \t\t\tthen\n\t\t\t\t\t\tdnf -y install php-fpm php-devel php-opcache\n\t\t\t\t\t\tdnf -y install php-json\n\t\t\t\t\telse\n\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-fpm php-devel php-cli php-opcache\n\t\t\t\t\tfi\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php-devel installation failed with error code ${error_code} (php-devel installation failed with error code 21)\"\n\t\t\t\t\t\treturn 21\n\t\t\t\t\tfi\t\t\t\t\t\n\t\t\t\t\tservice php-fpm start\n\t\t\t\tfi\n\t\t\tfi\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \"....\"\n\t\t\telse\n\t\t\t\tchkconfig --levels 35 php-fpm on\t\t\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP curl extension...\"\n\t\t\tphp -m | grep curl\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-curl...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-curl --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-curl installation failed with error code ${error_code} (php7.4-curl installation failed with error code 5)\"\n\t\t\t\t\t\treturn 5\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-curl\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-curl\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-curl installation failed with error code ${error_code} (php-curl installation failed with error code 22)\"\n\t\t\t\t\t\t\treturn 22\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP pgsql extension...\"\n\t\t\tphp -m | grep pgsql\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-pgsql...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install libpq5\n\t\t\t\t\tapt install -y php7.4-pgsql --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-pgsql installation failed with error code ${error_code} (php7.4-pgsql installation failed with error code 6)\"\n\t\t\t\t\t\treturn 6\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-pgsql\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-pgsql\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-pgsql installation failed with error code ${error_code} (php-pgsql installation failed with error code 23)\"\n\t\t\t\t\t\t\treturn 23\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP mbstring extension...\"\n\t\t\tphp -m | grep mbstring\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-mbstring...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-mbstring --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-mbstring installation failed with error code ${error_code} (php7.4-mbstring installation failed with error code 7)\"\n\t\t\t\t\t\treturn 7\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-mbstring\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-mbstring\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-mbstring installation failed with error code ${error_code} (php-mbstring installation failed with error code 24)\"\n\t\t\t\t\t\t\treturn 24\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP ldap extension...\"\n\t\t\tphp -m | grep ldap\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-ldap...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-ldap --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-ldap installation failed with error code ${error_code} (php7.4-ldap installation failed with error code 8)\"\n\t\t\t\t\t\treturn 8\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-ldap\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-ldap\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-ldap installation failed with error code ${error_code} (php-ldap installation failed with error code 25)\"\n\t\t\t\t\t\t\treturn 25\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP imagick extension...\"\n\t\t\tphp -m | grep imagick\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-imagick...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y gcc\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"gcc installation failed with error code ${error_code} (gcc installation failed with error code 9)\"\n\t\t\t\t\t\treturn 9\n\t\t\t\t\tfi\n\t\t\t\t\tapt install -y imagemagick\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"imagemagick installation failed with error code ${error_code} (imagemagick installation failed with error code 9)\"\n\t\t\t\t\t\treturn 9\n\t\t\t\t\tfi\n\t\t\t\t\tapt install -y php7.4-imagick --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-imagick installation failed with error code ${error_code} (php7.4-imagick installation failed with error code 10)\"\n\t\t\t\t\t\treturn 10\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tyum install -y ImageM* netpbm gd gd-* libjpeg libexif gcc coreutils make\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-pear\n\t\t\t\t\t\t\tdnf -y install php-gd\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-pear\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-gd\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"Installing php-imagick failed with error code ${error_code} (Installing php-imagick failed with error code 26)\"\n\t\t\t\t\t\t\treturn 26\n\t\t\t\t\t\tfi\n\n\t\t\t\t\t\tcd /usr/local/src\n\t\t\t\t\t\twget http://pecl.php.net/get/imagick-2.2.2.tgz\n\t\t\t\t\t\ttar zxvf ./imagick-2.2.2.tgz\n\t\t\t\t\t\tcd imagick-2.2.2\n\t\t\t\t\t\tphpize\n\t\t\t\t\t\t./configure\n\t\t\t\t\t\tmake\n\t\t\t\t\t\tmake test\n\t\t\t\t\t\tmake install\n\t\t\t\t\t\techo \"extension=imagick.so\" >> /etc/php.ini\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP imap extension...\"\n\t\t\tphp -m | grep imap\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php7.4-imap...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-imap --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-imap installation failed with error code ${error_code} (php7.4-imap installation failed with error code 11)\"\n\t\t\t\t\t\treturn 11\n\t\t\t\t\tfi\n\t\t\t\telse\n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-imap\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-imap\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-imap installation failed with error code ${error_code} (php-imap installation failed with error code 26)\"\n\t\t\t\t\t\t\treturn 26\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking xml...\"\n\t\t\tphp -m | grep xml\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing xml...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install php7.4-xml --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"xml installation failed with error code ${error_code} (xml installation failed with error code 56)\"\n\t\t\t\t\t\treturn 56\n\t\t\t\t\tfi\n\t\t\t\telse\n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-xml\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-xml\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"xml installation failed with error code ${error_code} (xml installation failed with error code 57)\"\n\t\t\t\t\t\t\treturn 57\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tset_timezone()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\ttimezone=$(cat /etc/timezone)\n\t\t\t\tsed -i -e 's/date.timezone/;date.timezone/g' /etc/php/7.4/fpm/php.ini\n\t\t\t\techo \"date.timezone = $timezone\" >> /etc/php/7.4/fpm/php.ini\n\t\t\telse \n\t\t\t\tPHP_VERSION=$(php -v | grep \"PHP 5\" | sed 's/.*PHP \\([^-]*\\).*/\\1/' | cut -c 1-3)\n\t\t\t\techo \"Installed PHP version: '$PHP_VERSION'\"\n\t\t\t\ttimezone=$(cat /etc/sysconfig/clock | grep ZONE | cut -d\"\\\"\" -f2)\n\t\t\t\tsed -i -e 's/date.timezone/;date.timezone/g' /etc/php.ini\n\t\t\t\techo \"date.timezone = $timezone\" >> /etc/php.ini\n\t\t\tfi\n\t\t}\n\t\tinstall_postgresql()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tid -a postgres\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]; then\n\t\t\t\t\techo \"PostgreSQL not installed!\"\n echo \"Installing PostgreSQL...\"\n sh -c 'echo \"deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main\" > /etc/apt/sources.list.d/pgdg.list'\n apt install wget ca-certificates\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"ca-certificates installation failed with error code ${error_code} (ca-certificates installation failed with error code 12)\"\n fi\n wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc\n apt-key add ACCC4CF8.asc\n apt update\n apt install -y postgresql --allow-unauthenticated\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"postgresql installation failed with error code ${error_code} (postgresql installation failed with error code 13)\"\n return 13\n fi\n\t\t\t\telse\n\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}' | head -1)\n\t\t\t\t\tif [[ ${PSQL_VERSION} == \"\" ]]; then\n\t\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ ${PSQL_VERSION} =~ ^10\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\t\tPSQL_VERSION=10\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ ${PSQL_VERSION} =~ ^11\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\t\tPSQL_VERSION=11\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ ${PSQL_VERSION} =~ ^12\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\t\tPSQL_VERSION=12\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ 1 -eq \"$(echo \"${PSQL_VERSION} < 9.3\" | bc)\" ]]; then\n\t\t\t\t\t\tset +x\n\t\t\t\t\t\techo \"Restyaboard will not work in your PostgreSQL version (i.e. less than 9.3). So script going to update PostgreSQL version 9.6\"\n\t\t\t\t\t\tsh -c 'echo \"deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main\" > /etc/apt/sources.list.d/pgdg.list'\n\t\t\t\t\t\tapt install wget ca-certificates\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"ca-certificates installation failed with error code ${error_code} (ca-certificates installation failed with error code 12)\"\n\t\t\t\t\t\tfi\n\t\t\t\t\t\twget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc\n\t\t\t\t\t\tapt-key add ACCC4CF8.asc\n\t\t\t\t\t\tapt update\n\t\t\t\t\t\tapt upgrade\n\t\t\t\t\t\tapt install -y postgresql --allow-unauthenticated\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"postgresql installation failed with error code ${error_code} (postgresql installation failed with error code 13)\"\n\t\t\t\t\t\t\treturn 13\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}' | head -1)\n\t\t\t\tif [[ ${PSQL_VERSION} == \"\" ]]; then\n\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\tfi\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^10\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=10\n\t\t\t\tfi\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^11\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=11\n\t\t\t\tfi\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^12\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=12\n\t\t\t\tfi\n\t\t\t\tsed -e 's/peer/trust/g' -e 's/ident/trust/g' < /etc/postgresql/${PSQL_VERSION}/main/pg_hba.conf > /etc/postgresql/${PSQL_VERSION}/main/pg_hba.conf.1\n\t\t\t\tcd /etc/postgresql/${PSQL_VERSION}/main || exit\n\t\t\t\tmv pg_hba.conf pg_hba.conf_old\n\t\t\t\tmv pg_hba.conf.1 pg_hba.conf\n\t\t\t\tservice postgresql restart\n\t\t\telse\n\t\t\t\tif ! which psql > /dev/null 2>&1;\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL not installed!\"\n echo \"Installing PostgreSQL...\"\n if [ $(getconf LONG_BIT) = \"64\" ]; then\n if [[ $OS_REQUIREMENT = \"Fedora\" ]]; then\n dnf install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/F-${OS_VERSION}-x86_64/pgdg-fedora-repo-latest.noarch.rpm\"\n else\n if ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" != \"8\" ])\n then\n yum install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm\"\n fi\n fi\n fi\n if ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n then\n dnf module enable postgresql:13\n dnf -y install postgresql-server postgresql-contrib postgresql-libs\n else\n yum install -y postgresql13 postgresql13-server postgresql13-contrib postgresql13-libs\t\n fi\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"postgresql13 installation failed with error code ${error_code} (postgresql13 installation failed with error code 29)\"\n return 29\n fi\n\t\t\t\telse \n\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\t\tif [[ $PSQL_VERSION < 9.3 ]]; then\n\t\t\t\t\t\tset +x\n\t\t\t\t\t\techo \"Restyaboard will not work in your PostgreSQL version (i.e. less than 9.3). So script going to update PostgreSQL version 9.6\"\n\t\t\t\t\t\tif [ $(getconf LONG_BIT) = \"64\" ]; then\n\t\t\t\t\t\t\tif [[ $OS_REQUIREMENT = \"Fedora\" ]]; then\n\t\t\t\t\t\t\t\tdnf install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/F-${OS_VERSION}-x86_64/pgdg-fedora-repo-latest.noarch.rpm\"\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" != \"8\" ])\n\t\t\t\t\t\t\t\tthen\n\t\t\t\t\t\t\t\t\tyum install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm\"\n\t\t\t\t\t\t\t\tfi\n\t\t\t\t\t\t\tfi\n\t\t\t\t\t\tfi\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf module enable postgresql:13\n\t\t\t\t\t\t\tdnf -y install postgresql-server postgresql-contrib postgresql-libs\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum install -y postgresql13 postgresql13-server postgresql13-contrib postgresql13-libs\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"postgresql installation failed with error code ${error_code} (postgresql installation failed with error code 29)\"\n\t\t\t\t\t\t\treturn 29\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^13\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=13\n\t\t\t\tfi\n\t\t\t\tPSQL_FOLDER=$(echo ${PSQL_VERSION} | sed 's/\\.//')\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tpostgresql-setup --initdb\n\t\t\t\telse\n\t\t\t\t\t\"/usr/pgsql-${PSQL_VERSION}/bin/postgresql-${PSQL_VERSION}-setup\" initdb\n\t\t\t\tfi\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tsystemctl enable postgresql\n\t\t\t\t\tsystemctl start postgresql\n\t\t\t\telse\n\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\tsystemctl start \"postgresql-${PSQL_VERSION}.service\"\n\t\t\t\t\t\tsystemctl enable \"postgresql-${PSQL_VERSION}.service\"\n\t\t\t\t\telse\n\t\t\t\t\t\t\"/etc/init.d/postgresql-${PSQL_VERSION}\" start\n\t\t\t\t\t\tchkconfig --levels 35 \"postgresql-${PSQL_VERSION}\" on\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tsed -e 's/peer/trust/g' -e 's/ident/trust/g' < \"/var/lib/pgsql/data/pg_hba.conf\" > \"/var/lib/pgsql/data/pg_hba.conf.1\"\n\t\t\t\t\tcd \"/var/lib/pgsql/data\" || exit\n\t\t\t\telse\n\t\t\t\t\tsed -e 's/peer/trust/g' -e 's/ident/trust/g' < \"/var/lib/pgsql/${PSQL_VERSION}/data/pg_hba.conf\" > \"/var/lib/pgsql/${PSQL_VERSION}/data/pg_hba.conf.1\"\n\t\t\t\t\tcd \"/var/lib/pgsql/${PSQL_VERSION}/data\" || exit\n\t\t\t\tfi\n\t\t\t\tmv pg_hba.conf pg_hba.conf_old\n\t\t\t\tmv pg_hba.conf.1 pg_hba.conf\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tsystemctl restart postgresql\n\t\t\t\telse\n\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\tsystemctl restart \"postgresql-${PSQL_VERSION}.service\"\n\t\t\t\t\telse\n\t\t\t\t\t\t\"/etc/init.d/postgresql-${PSQL_VERSION}\" restart\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tinstall_geoip()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tif ! hash GeoIP-devel 2>&-;\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-geoip php7.4-dev libgeoip-dev\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-geoip php7.4-dev libgeoip-dev installation failed with error code ${error_code} (php7.4-geoip php7.4-dev libgeoip-dev installation failed with error code 50)\"\n\t\t\t\t\tfi\n\t\t\t\tfi\n\n\t\t\t\tif ! hash pecl/geoip 2>&-;\n\t\t\t\tthen\n\t\t\t\t\tpecl install geoip\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"pecl geoip installation failed with error code ${error_code} (pecl geoip installation failed with error code 47)\"\n\t\t\t\t\tfi\n\t\t\t\tfi\n\n\t\t\t\techo \"extension=geoip.so\" >> /etc/php.ini\n\n\t\t\t\tmkdir -v /usr/share/GeoIP\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"GeoIP folder creation failed with error code ${error_code} (GeoIP folder creation failed with error code 52)\"\n\t\t\t\tfi\n\t\t\t\tget_geoip_data\n\t\t\telse\n\t\t\t\tif ! hash pecl/geoip 2>&-;\n\t\t\t\tthen\n\t\t\t\t\tpecl install geoip\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"pecl geoip installation failed with error code ${error_code} (pecl geoip installation failed with error code 47)\"\n\t\t\t\t\t\treturn 47\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tconfigure_restyaboard()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n cp ${DOWNLOAD_DIR}/restyaboard.conf /etc/nginx/conf.d\n echo \"Changing server_name in nginx configuration...\"\n sed -i \"s/server_name.*$/server_name \\\"$IPADDR\\\";/\" /etc/nginx/conf.d/restyaboard.conf\n sed -i \"s|listen 80.*$|listen 80;|\" /etc/nginx/conf.d/restyaboard.conf\n mkdir -p \"$RESTYABOARD_DIR\"\n echo \"Changing root directory in nginx configuration...\"\n sed -i \"s|root.*html|root $RESTYABOARD_DIR|\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\telse\n cp ${DOWNLOAD_DIR}/restyaboard.conf /etc/nginx/conf.d\n sed -i \"s/server_name.*$/server_name \\\"$IPADDR\\\";/\" /etc/nginx/conf.d/restyaboard.conf\n sed -i \"s|listen 80.*$|listen 80;|\" /etc/nginx/conf.d/restyaboard.conf\n mkdir -p \"$RESTYABOARD_DIR\"\n echo \"Changing root directory in nginx configuration...\"\n sed -i \"s|root.*html|root $RESTYABOARD_DIR|\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\tfi\n\t\t}\n\t\tinstall_postfix()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \"Installing postfix...\"\n\t\t\t\techo \"postfix postfix/mailname string $IPADDR\"\\\n\t\t\t\t| debconf-set-selections &&\\\n\t\t\t\techo \"postfix postfix/main_mailer_type string 'Internet Site'\"\\\n\t\t\t\t| debconf-set-selections &&\\\n\t\t\t\tapt install -y postfix\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"postfix installation failed with error code ${error_code} (postfix installation failed with error code 16)\"\n\t\t\t\tfi\n\t\t\t\tPHP_VERSION=$(php --version | head -n 1 | cut -d \" \" -f 2 | grep --only-matching --perl-regexp \"^\\\\d\\.\\\\d+\")\n\t\t\t\tif [ -f \"/etc/php/${PHP_VERSION}/fpm/php.ini\" ] \n\t\t\t\tthen\n\t\t\t\t\tsed -i \"s/;sendmail_path =/sendmail_path = \\\"\\/usr\\/sbin\\/sendmail -t -i\\\"/g\" /etc/php/${PHP_VERSION}/fpm/php.ini\n\t\t\t\tfi\n\t\t\t\tif [ -f \"/etc/php/${PHP_VERSION}/cli/php.ini\" ] \n\t\t\t\tthen\n\t\t\t\t\tsed -i \"s/;sendmail_path =/sendmail_path = \\\"\\/usr\\/sbin\\/sendmail -t -i\\\"/g\" /etc/php/${PHP_VERSION}/cli/php.ini\n\t\t\t\tfi\n\t\t\t\tif [ -f \"/etc/php.ini\" ] \n\t\t\t\tthen\n\t\t\t\t\tsed -i \"s/;sendmail_path =/sendmail_path = \\\"\\/usr\\/sbin\\/sendmail -t -i\\\"/g\" /etc/php.ini\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tchange_permission()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\tthen\n\t\t\t\tchcon -R -t httpd_sys_rw_content_t $RESTYABOARD_DIR/media/ $RESTYABOARD_DIR/tmp/cache/ $RESTYABOARD_DIR/client/img/\n\t\t\t\tchcon -Rv --type=httpd_t $RESTYABOARD_DIR/\n\t\t\tfi\n\t\t}\n\t\tpsql_connect()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tpsql -U postgres -c \"\\q\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL Changing the permission failed with error code ${error_code} (PostgreSQL Changing the permission failed with error code 34)\"\n\t\t\t\t\treturn 34\n\t\t\t\tfi\n\t\t\t\tsleep 1\n\t\t\t\techo \"Creating PostgreSQL user and database...\"\n\t\t\t\tpsql -U postgres -c \"DROP USER IF EXISTS ${POSTGRES_DBUSER};CREATE USER ${POSTGRES_DBUSER} WITH ENCRYPTED PASSWORD '${POSTGRES_DBPASS}'\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL user creation failed with error code ${error_code} (PostgreSQL user creation failed with error code 35)\"\n\t\t\t\t\treturn 35\n\t\t\t\tfi\n\t\t\t\tpsql -U postgres -c \"CREATE DATABASE ${POSTGRES_DBNAME} OWNER ${POSTGRES_DBUSER} ENCODING 'UTF8' TEMPLATE template0\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL database creation failed with error code ${error_code} (PostgreSQL database creation failed with error code 36)\"\n\t\t\t\t\treturn 36\n\t\t\t\tfi\n\t\t\t\tpsql -U postgres -c \"CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL extension creation failed with error code ${error_code} (PostgreSQL extension creation failed with error code 37)\"\n\t\t\t\t\treturn 37\n\t\t\t\tfi\n\t\t\t\tpsql -U postgres -c \"COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} = 0 ];\n\t\t\t\tthen\n\t\t\t\t\techo \"Importing empty SQL...\"\n\t\t\t\t\tpsql -d ${POSTGRES_DBNAME} -f \"$RESTYABOARD_DIR/sql/restyaboard_with_empty_data.sql\" -U ${POSTGRES_DBUSER}\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"PostgreSQL Empty SQL importing failed with error code ${error_code} (PostgreSQL Empty SQL importing failed with error code 39)\"\n\t\t\t\t\t\treturn 39\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\telse\n\t\t\t\tpsql -U postgres -c \"\\q\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL Changing the permission failed with error code ${error_code} (PostgreSQL Changing the permission failed with error code 40)\"\n\t\t\t\t\treturn 40\n\t\t\t\tfi\t\t\t\n\t\t\t\tsleep 1\n\t\t\t\techo \"Creating PostgreSQL user and database...\"\n\t\t\t\tpsql -U postgres -c \"DROP USER IF EXISTS ${POSTGRES_DBUSER};CREATE USER ${POSTGRES_DBUSER} WITH ENCRYPTED PASSWORD '${POSTGRES_DBPASS}'\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL user creation failed with error code ${error_code} (PostgreSQL user creation failed with error code 41)\"\n\t\t\t\t\treturn 41\n\t\t\t\tfi\t\t\t\n\t\t\t\tpsql -U postgres -c \"CREATE DATABASE ${POSTGRES_DBNAME} OWNER ${POSTGRES_DBUSER} ENCODING 'UTF8' TEMPLATE template0\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL database creation failed with error code ${error_code} (PostgreSQL database creation failed with error code 42)\"\n\t\t\t\t\treturn 42\n\t\t\t\tfi\t\t\t\n\t\t\t\tpsql -U postgres -c \"CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL extension creation failed with error code ${error_code} (PostgreSQL extension creation failed with error code 43)\"\n\t\t\t\t\treturn 43\n\t\t\t\tfi\t\t\t\n\t\t\t\tpsql -U postgres -c \"COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';\"\n\t\t\t\tif [ \"$?\" = 0 ];\n\t\t\t\tthen\n\t\t\t\t\techo \"Importing empty SQL...\"\n\t\t\t\t\tpsql -d ${POSTGRES_DBNAME} -f \"$RESTYABOARD_DIR/sql/restyaboard_with_empty_data.sql\" -U ${POSTGRES_DBUSER}\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"PostgreSQL Empty SQL importing failed with error code ${error_code} (PostgreSQL Empty SQL importing failed with error code 45)\"\n\t\t\t\t\t\treturn 45\n\t\t\t\t\tfi\t\n\t\t\t\tfi\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\t\tthen\n\t\t\t\t\tsetsebool -P allow_postfix_local_write_mail_spool 1\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tphp_fpm_reset()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \".........\"\n\t\t\telse\n\t\t\t\techo \"Reset php-fpm (use unix socket mode)...\"\n\t\t\t\tif [ -f \"/run/php/php7.4-fpm.sock\" ]; then\n\t\t\t\t\tsed -i \"s/listen = 127.0.0.1:9000/listen = \\/run\\/php\\/php7.4-fpm.sock/g\" /etc/php-fpm.d/www.conf\n\t\t\t\telif [ -f \"/run/php-fpm/www.sock\" ]; then\n\t\t\t\t\tsed -i \"s/listen = 127.0.0.1:9000/listen = \\/run\\/php-fpm\\/www.sock/g\" /etc/php-fpm.d/www.conf\n\t\t\t\t\tsed -i \"s/unix:\\/run\\/php\\/php7.4-fpm.sock/unix:\\/run\\/php-fpm\\/www.sock/g\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\t\telse\n\t\t\t\t\tsed -i \"s/unix:\\/run\\/php\\/php7.4-fpm.sock/127.0.0.1:9000/g\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tinstall_jq()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tapt install -y jq\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"jq installation failed with error code ${error_code} (jq installation failed with error code 53)\"\n\t\t\t\tfi\n\t\t\telse\n\t\t\t\tyum install -y jq\n\t\t\t\terror_code\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"jq installation failed with error code ${error_code} (jq installation failed with error code 49)\"\n\t\t\t\t\treturn 49\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tset_db_connection()\n\t\t{\t\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \"Starting services...\"\n\t\t\t\tservice cron restart\n\t\t\t\tservice php7.4-fpm restart\n\t\t\t\tservice nginx restart\n\t\t\t\tservice postfix restart\n\t\t\t\tapt install -y python-pip\n\t\t\t\tpip install virtualenv\n\t\t\telse\n\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\techo \"Starting services with systemd...\"\n\t\t\t\t\tsystemctl restart nginx\n\t\t\t\t\tsystemctl restart php-fpm\n\t\t\t\telse\n\t\t\t\t\techo \"Starting services...\"\n\t\t\t\t\t/etc/init.d/php-fpm restart\n\t\t\t\t\t/etc/init.d/nginx restart\n\t\t\t\tfi\n\t\t\t\tyum install -y python-pip\n\t\t\t\tpip install virtualenv\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\t\tthen\n\t\t\t\t\tsetsebool -P httpd_can_network_connect_db=1\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tssl_connectivity()\n\t\t{\n\t\t\tif [[ $IPADDR =~ ^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$ ]]; then\n\t\t\t\techo \"SSL connectivity cannot be set for IP address\"\n\t\t\telse\n\t\t\t\tset +x\n\t\t\t\techo \"Do you want to set up SSL connectivity for your domain and your domain should be publicly accessible Restyaboard instance and your domain should be mappped to this Restyaboard Server, Note: If you're trying to set SSL for Non-publicly accessible instance, then your Restyaboard will not work (y/n)?\"\n\t\t\t\tread -r answer\n\t\t\t\tset -x\n\t\t\t\tcase \"${answer}\" in\n\t\t\t\t\t[Yy])\n\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tapt install certbot python3-certbot-nginx -y\n\t\t\t\t\t\tservice nginx restart\n\t\t\t\t\t\tservice php7.4-fpm restart\n\t\t\t\t\t\tcertbot --nginx\n\t\t\t\t\telse\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install epel-release\n\t\t\t\t\t\t\tdnf -y install certbot python3-certbot-nginx\n\t\t\t\t\t\t\tcertbot --nginx\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum install -y epel-release\n\t\t\t\t\t\t\tyum install certbot-nginx\n\t\t\t\t\t\t\tcertbot --nginx\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"SSL installation failed with error code ${error_code} (php installation failed with error code 20)\"\n\t\t\t\t\t\t\treturn 20\n\t\t\t\t\t\tfi\n\t\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\t\techo \"Starting services with systemd...\"\n\t\t\t\t\t\t\tsystemctl restart nginx\n\t\t\t\t\t\t\tsystemctl restart php-fpm\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\techo \"Starting services...\"\n\t\t\t\t\t\t\t/etc/init.d/php-fpm restart\n\t\t\t\t\t\t\t/etc/init.d/nginx restart\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tesac\n\t\t\tfi\n\t\t}\n\t\tfind_release\n\t\tcheckdeps\n\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n then\n\t\t\tapt update\n apt install -y net-tools\n\t\t\tapt install -y curl unzip\n\t\telse\n\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n \tthen\n yum install -y net-tools\n\t\t\t\tyum install -y curl unzip\n\t\t\tfi\n\t\tfi\n IFCONFIG_PATH=$(which ifconfig)\n IPADDR=$(${IFCONFIG_PATH} eth0 | awk '/inet / { print $2 }' | sed 's/addr://')\n\t\tRESTYABOARD_VERSION=$(curl --silent https://api.github.com/repos/RestyaPlatform/board/releases | grep tag_name -m 1 | awk '{print $2}' | sed -e 's/[^v0-9.]//g')\n\t\tPOSTGRES_DBHOST=localhost\n\t\tPOSTGRES_DBNAME=restyaboard\n\t\tPOSTGRES_DBUSER=restya\n\t\tPOSTGRES_DBPASS=hjVl2!rGd\n\t\tPOSTGRES_DBPORT=5432\n\t\tDOWNLOAD_DIR=/opt/restyaboard\n RESTYABOARD_DIR=/usr/share/nginx/html/restyaboard\n\t\t\n\t\tget_geoip_data () \n\t\t{\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIP.dat.gz\n\t\t\tgunzip GeoIP.dat.gz\n\t\t\tmv GeoIP.dat /usr/share/GeoIP/GeoIP.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz\n\t\t\tgunzip GeoIPv6.dat.gz\n\t\t\tmv GeoIPv6.dat /usr/share/GeoIP/GeoIPv6.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.xz\n\t\t\tunxz GeoLiteCity.dat.xz\n\t\t\tmv GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoLiteCityv6.dat.gz\n\t\t\tgunzip GeoLiteCityv6.dat.gz\n\t\t\tmv GeoLiteCityv6.dat /usr/share/GeoIP/GeoLiteCityv6.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIPASNum.dat.gz\n\t\t\tgunzip GeoIPASNum.dat.gz\n\t\t\tmv GeoIPASNum.dat /usr/share/GeoIP/GeoIPASNum.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIPASNumv6.dat.gz\n\t\t\tgunzip GeoIPASNumv6.dat.gz\n\t\t\tmv GeoIPASNumv6.dat /usr/share/GeoIP/GeoIPASNumv6.dat\n\t\t}\n\n\t\tupgrade-0.3-0.4()\n\t\t{\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/chat_activities.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/0 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/periodic_chat_email_notification.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/indexing_to_elasticsearch.sh//\" /var/spool/cron/crontabs/root\n\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/upgrade_v0.2.1_v0.3.php\n\n\t\t\trm -rf $RESTYABOARD_DIR/client/apps/\n\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/jaxl3/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp-prebind-php/\n\t\t}\n\n\t\tupgrade-0.4-0.4.1()\n\t\t{\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/chat_activities.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/0 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/periodic_chat_email_notification.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/indexing_to_elasticsearch.sh//\" /var/spool/cron/crontabs/root\n\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/upgrade_v0.2.1_v0.3.php\n\n\t\t\trm -rf $RESTYABOARD_DIR/client/apps/\n\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/jaxl3/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp-prebind-php/\n\t\t}\n\n\t\tupgrade-0.5.2-0.6()\n\t\t{\n\t\t\tsed -i \"s/rewrite ^\\/ical\\/.*/rewrite ^\\/ical\\/([0-9]*)\\/([0-9]*)\\/([a-z0-9]*).ics\\$ \\/server\\/php\\/ical.php?board_id=\\$1\\&user_id=\\$2\\&hash=\\$3 last;/\" /etc/nginx/conf.d/restyaboard.conf\n\t\t}\n\n\t\tupgrade-0.6.3-0.6.4()\n\t\t{\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps/r_hide_card_created_date\" ]; then\n\t\t\t\trm -rf $RESTYABOARD_DIR/client/apps/r_hide_card_created_date/\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_hide_card_additional_informations-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_hide_card_additional_informations-v0.1.1.zip\n\t\t\t\tunzip /tmp/r_hide_card_additional_informations-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t}\n\n\t\tupgrade-0.6.4-0.6.5()\n\t\t{\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps/r_hide_card_id\" ]; then\n\t\t\t\trm -rf $RESTYABOARD_DIR/client/apps/r_hide_card_id/\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_hide_card_additional_informations-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_hide_card_additional_informations-v0.1.2.zip\n\t\t\t\tunzip /tmp/r_hide_card_additional_informations-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t}\n\n\t\tupgrade-0.6.5-0.6.6()\n\t\t{\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.1.zip\n\t\t\t\tunzip /tmp/r_codenames-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.1.zip\n\t\t\t\tunzip /tmp/r_codenames-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t}\n\t\t\n\t\tupgrade-0.6.6-0.6.7(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_card_counter-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_card_counter-v0.1.1.zip\n\t\t\tunzip /tmp/r_card_counter-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.2.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n\t\t\tcurl -v -L -G -o /tmp/r_eu_gdpr-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_eu_gdpr-v0.1.2.zip\n\t\t\tunzip /tmp/r_eu_gdpr-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n\t\t\tcurl -v -L -G -o /tmp/r_gmail_addon-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_gmail_addon-v0.1.1.zip\n\t\t\tunzip /tmp/r_gmail_addon-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\t\t\t\n\t\t\t\n\t\t\tcurl -v -L -G -o /tmp/r_hide_card_additional_informations-v0.1.3.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_hide_card_additional_informations-v0.1.3.zip\n\t\t\tunzip /tmp/r_hide_card_additional_informations-v0.1.3.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n find \"$RESTYABOARD_DIR/client/apps\" -type d -exec chmod 755 {} \\;\n find \"$RESTYABOARD_DIR/client/apps\" -type f -exec chmod 644 {} \\;\n chmod 0777 $RESTYABOARD_DIR/client/apps/**/*.json\n\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\t: > /var/spool/cron/crontabs/root\n\t\t\t\techo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/crontabs/root\n\t\t\telse\n\t\t\t\t: > /var/spool/cron/root\n\t\t\t\techo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/root\n\t\t\tfi\n\t\t}\n\n\t\tupgrade-0.6.7-0.6.8(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.3.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.3.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.3.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n find \"$RESTYABOARD_DIR/client/apps\" -type d -exec chmod 755 {} \\;\n find \"$RESTYABOARD_DIR/client/apps\" -type f -exec chmod 644 {} \\;\n chmod 0777 $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t}\n\n\t\tupgrade-0.6.8-0.6.9(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.4.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.4.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.4.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n find \"$RESTYABOARD_DIR/client/apps\" -type d -exec chmod 755 {} \\;\n find \"$RESTYABOARD_DIR/client/apps\" -type f -exec chmod 644 {} \\;\n chmod 0777 $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t}\n\t\tupgrade-0.6.9-1.7(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps/r_togetherjs\" ]; then\n\t\t\t\trm -rf $RESTYABOARD_DIR/client/apps/r_togetherjs/\n\t\t\tfi\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.5.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.5.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.5.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tcurl -v -L -G -o /tmp/r_gmail_addon-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_gmail_addon-v0.1.2.zip\n\t\t\tunzip /tmp/r_gmail_addon-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\n\t\t\techo \"Applying permission...\"\n\t\t\tuseradd restyaboard\n\t\t\tusermod --password 'hjVl2!rGd' restyaboard\n\t\t\tPHP_VERSION=$(php --version | head -n 1 | cut -d \" \" -f 2 | grep --only-matching --perl-regexp \"^\\\\d\\.\\\\d+\")\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tuser www-data;\n\t\t\t\tusermod -a -G restyaboard www-data\n\t\t\t\tsed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php/${PHP_VERSION}/fpm/pool.d/www.conf\n\t\t\t\tsed -i \"s/user\\s*=\\s*www-data/user = restyaboard/g\" /etc/php/${PHP_VERSION}/fpm/pool.d/www.conf\n\t\t\t\tsed -i \"0,/group\\s*=\\s*www-data/s//group = restyaboard/g\" /etc/php/${PHP_VERSION}/fpm/pool.d/www.conf\n\t\t\telse\n\t\t\t\tuser nginx;\n\t\t\t\tusermod -a -G restyaboard nginx\n\t\t\t\tsed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php-fpm.d/www.conf\n\t\t\t\tsed -i \"s/user\\s*=\\s*apache/user = restyaboard/g\" /etc/php-fpm.d/www.conf\n\t\t\t\tsed -i \"0,/group\\s*=\\s*apache/s//group = restyaboard/g\" /etc/php-fpm.d/www.conf\n\t\t\tfi\n\t\t\tchown -R restyaboard:restyaboard $RESTYABOARD_DIR\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/media\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/media;\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/client/img\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/client/img;\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/tmp/cache\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/tmp/cache;\n\t\t\tchmod +x $RESTYABOARD_DIR/server/php/shell/main.sh\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tchmod -R u=rwX,g=rX,o= \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\tthen\n\t\t\t\tchcon -R -t httpd_sys_rw_content_t $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t\tfi\n\t\t}\n\n\t\tupdate_version()\n\t\t{\n\t\t\tset +x\n\t\t\techo -e \"A newer version ${RESTYABOARD_VERSION} of Restyaboard is available.\\n\\nImportant: Please note that upgrading will remove any commercial apps that were free in previous version.\\nFor more details about commercial apps, please visit https://restya.com/board/pricing\\n\\nDo you want to get it now y/n?\"\n\t\t\tread -r answer\n\t\t\tset -x\n\t\t\tcase \"${answer}\" in\n\t\t\t\t[Yy])\n\t\t\t\tset +x\n\t\t\t\tset -x\n\t\t\t\t\n\t\t\t\techo \"Downloading files...\"\n\t\t\t\tcurl -v -L -G -d \"app=board&ver=${RESTYABOARD_VERSION}\" -o /tmp/restyaboard.zip -k https://restya.com/download.php\n\t\t\t\tunzip /tmp/restyaboard.zip -d ${DOWNLOAD_DIR}\n\t\t\t\t\n\t\t\t\techo \"Updating files...\"\n\t\t\t\tcp -r ${DOWNLOAD_DIR}/. \"$RESTYABOARD_DIR\"\n\t\t\t\t\n\t\t\t\techo \"Connecting database to run SQL changes...\"\n\t\t\t\tpsql -U postgres -c \"\\q\"\n\t\t\t\terror_code=$? \n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL database connection failed with error code ${error_code} (PostgreSQL database connection failed with error code 32)\"\n\t\t\t\t\treturn 32\n\t\t\t\tfi\n\t\t\t\tsleep 1\n\t\t\t\t\n\t\t\t\techo \"Changing PostgreSQL database name, user and password...\"\n\t\t\t\tsed -i \"s/^.*'R_DB_NAME'.*$/define('R_DB_NAME', '${POSTGRES_DBNAME}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_USER'.*$/define('R_DB_USER', '${POSTGRES_DBUSER}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_PASSWORD'.*$/define('R_DB_PASSWORD', '${POSTGRES_DBPASS}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_HOST'.*$/define('R_DB_HOST', '${POSTGRES_DBHOST}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_PORT'.*$/define('R_DB_PORT', '${POSTGRES_DBPORT}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tPHP_VERSION=$(php --version | head -n 1 | cut -d \" \" -f 2 | grep --only-matching --perl-regexp \"^\\\\d\\.\\\\d+\")\n\t\t\t\tversion=$(cat ${DOWNLOAD_DIR}/release)\n\t\t\t\tdeclare -a upgrade;\n\t\t\t\tif [[ $version < \"v0.4\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.3-0.4\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.4.1\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.4-0.4.1\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.5\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.4.2-0.5\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.5.2\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.5.1-0.5.2\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.5.2-0.6\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.1\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6-0.6.1\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.2\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.1-0.6.2\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.3\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.2-0.6.3\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.4\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.3-0.6.4\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.5\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.4-0.6.5\")\n\t\t\t\tfi\t\n\t\t\t\tif [[ $version < \"v0.6.6\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.5-0.6.6\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.7\" ]];\n\t\t\t\tthen\n\t\t\t\t\tset +x\n\t\t\t\t\techo \"Before updating make sure to remove duplicate username's and emails used by more than one user, otherwise unique indexing for users will be thrown an error But all other queries will be executed without any issue.\"\n\t\t\t\t\tread -r -s -p $'Press [Enter] key to continue...'\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.6-0.6.7\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.8\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.7-0.6.8\")\n\t\t\t\tfi\t\t \n\t\t\t\tif [[ $version < \"v0.6.9\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.8-0.6.9\")\n\t\t\t\tfi\t\n\t\t\t\tif [[ $version < \"v1.7\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.9-1.7\")\n\t\t\t\tfi\n\t\t\t\t# use for loop to read all values and indexes\n\t\t\t\tfor i in \"${upgrade[@]}\"\n\t\t\t\tdo\n\t\t\t\t\tif [ \"$(type -t ${i})\" = function ];\n\t\t\t\t\tthen\n\t\t\t\t\t\teval ${i}\n\t\t\t\t\tfi\n\t\t\t\t\tif [ -f \"$RESTYABOARD_DIR/sql/${i}.sql\" ];\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"Updating SQL...\"\n\t\t\t\t\t\tpsql -d ${POSTGRES_DBNAME} -f \"$RESTYABOARD_DIR/sql/${i}.sql\" -U ${POSTGRES_DBUSER}\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"PostgreSQL updation of SQL failed with error code ${error_code} (PostgreSQL updation of SQL failed with error code 33)\"\n\t\t\t\t\t\t\treturn 33\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tdone\n\t\t\t\t/bin/echo \"$RESTYABOARD_VERSION\" > ${DOWNLOAD_DIR}/release\n\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\t\tthen\t\t\t\t \n service nginx restart\n\t\t\t\t\tservice php${PHP_VERSION}-fpm restart\n\t\t\t\telse\n\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\techo \"Starting services with systemd...\"\n\t\t\t\t\t\tsystemctl restart nginx\n\t\t\t\t\t\tsystemctl restart php-fpm\n\t\t\t\t\telse\n\t\t\t\t\t\techo \"Starting services...\"\n\t\t\t\t\t\t/etc/init.d/php-fpm restart\n\t\t\t\t\t\t/etc/init.d/nginx restart\n\t\t\t\t\tfi\n\t\t\t\tfi\n\n\t\t\tesac\n\t\t}\n\n\t\tif [ -f \"$DOWNLOAD_DIR/release\" ];\n\t\tthen\n\t\t\tversion=$(cat ${DOWNLOAD_DIR}/release)\n\t\t\tif [[ $version < $RESTYABOARD_VERSION ]];\n\t\t\tthen\n\t\t\t\tupdate_version\n\t\t\t\texit;\n\t\t\telse\n\t\t\t\techo \"No new version available\"\n\t\t\t\texit;\n\t\t\tfi\n\t\telse\n\t\t\tset +x\n\t\t\techo \"Is Restyaboard already installed and configured/working y/n?\"\n\t\t\tread -r answer\n\t\t\tset -x\n\t\t\tcase \"${answer}\" in\n\t\t\t\t[Yy])\n\t\t\t\tupdate_version\n\t\t\t\texit;\n\t\t\tesac\n\t\tfi\n\n if ([ \"$OS_REQUIREMENT\" = \"Debian\" ])\n then\n sed -i -e 's/deb cdrom/#deb cdrom/g' /etc/apt/sources.list\n sh -c 'echo \"deb http://ftp.de.debian.org/debian jessie main\" > /etc/apt/sources.list.d/debjessie.list'\n apt install apt-transport-https lsb-release ca-certificates -y\n wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg\n echo \"deb https://packages.sury.org/php/ $(lsb_release -sc) main\" | tee /etc/apt/sources.list.d/php.list\n fi\n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n apt install debian-keyring debian-archive-keyring -y\n apt update -y\n apt upgrade -y\n apt install python-software-properties -y\n apt install software-properties-common -y\n if ! hash php 2>&-; then\n add-apt-repository -y ppa:ondrej/php\n apt update -y\n apt install libjpeg8 -y --allow-unauthenticated\n fi\n fi\n install_nginx\n \n echo \"Checking PHP...\"\n install_php\n\n echo \"Setting up timezone...\"\n set_timezone\n \n echo \"Checking PostgreSQL...\"\n install_postgresql\n\n install_geoip\n \n echo \"Downloading Restyaboard script...\"\n if ([ \"$pkg_name\" = \"apt-get\" ])\n then\n apt install -y curl\n fi\n mkdir ${DOWNLOAD_DIR}\n curl -v -L -G -d \"app=board&ver=${RESTYABOARD_VERSION}\" -o /tmp/restyaboard.zip -k https://restya.com/download.php\n unzip /tmp/restyaboard.zip -d ${DOWNLOAD_DIR}\n rm /tmp/restyaboard.zip\n\n configure_restyaboard\n \n \n echo \"Copying Restyaboard script to root directory...\"\n cp -r ${DOWNLOAD_DIR}/* \"$RESTYABOARD_DIR\"\n \n install_postfix\n \n echo \"Changing permission...\"\n useradd restyaboard\n usermod --password 'hjVl2!rGd' restyaboard\n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n user www-data;\n usermod -a -G restyaboard www-data\n sed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php/7.4/fpm/pool.d/www.conf\n sed -i \"s/user\\s*=\\s*www-data/user = restyaboard/g\" /etc/php/7.4/fpm/pool.d/www.conf\n sed -i \"0,/group\\s*=\\s*www-data/s//group = restyaboard/g\" /etc/php/7.4/fpm/pool.d/www.conf\n else\n user nginx;\n usermod -a -G restyaboard nginx\n sed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php-fpm.d/www.conf\n sed -i \"s/user\\s*=\\s*apache/user = restyaboard/g\" /etc/php-fpm.d/www.conf\n sed -i \"0,/group\\s*=\\s*apache/s//group = restyaboard/g\" /etc/php-fpm.d/www.conf\n fi\n chown -R restyaboard:restyaboard $RESTYABOARD_DIR\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR\n chown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/media\"\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/media;\n chown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/client/img\"\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/client/img;\n chown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/tmp/cache\"\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/tmp/cache;\n chmod +x $RESTYABOARD_DIR/server/php/shell/main.sh\n change_permission\n\n psql_connect\n \n echo \"Changing PostgreSQL database name, user and password...\"\n sed -i \"s/^.*'R_DB_NAME'.*$/define('R_DB_NAME', '${POSTGRES_DBNAME}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_USER'.*$/define('R_DB_USER', '${POSTGRES_DBUSER}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_PASSWORD'.*$/define('R_DB_PASSWORD', '${POSTGRES_DBPASS}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_HOST'.*$/define('R_DB_HOST', '${POSTGRES_DBHOST}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_PORT'.*$/define('R_DB_PORT', '${POSTGRES_DBPORT}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n \n echo \"Setting up cron for every 5 minutes..\"\n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n echo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/crontabs/root\n else\n echo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/root\n fi\n php_fpm_reset\n \n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n service nginx restart\n service php7.4-fpm restart\n else\n if [ -f \"/bin/systemctl\" ]; then\n echo \"Starting services with systemd...\"\n systemctl restart nginx\n systemctl restart php-fpm\n else\n echo \"Starting services...\"\n /etc/init.d/php-fpm restart\n /etc/init.d/nginx restart\n fi\n fi\n set_db_connection\n\t\t/bin/echo \"$RESTYABOARD_VERSION\" > ${DOWNLOAD_DIR}/release\n\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\tthen\n\t\t\tssl_connectivity\n\t\telse\n\t\t\tssl_connectivity\n\t\tfi\n\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n then\n\t\t\tsemanage permissive -a httpd_t\n\t\tfi\n\t\tset +x\n\t\techo \"Checking Hosting...\"\n\t\tresponse=$(curl -H Metadata:true http://169.254.169.254/metadata/instance?api-version=2017-04-02 --write-out %{http_code} --connect-timeout 10 --max-time 10 --silent --output /dev/null)\n\t\t\n\t\tif [ -f /etc/ImageMagick-6/policy.xml ]; then\n \t\tsed -i -e 's///g' /etc/ImageMagick-6/policy.xml\n\t\tfi\n\n\t\tif [ -f /etc/ImageMagick/policy.xml ]; then\n\t\t\tsed -i -e 's///g' /etc/ImageMagick/policy.xml\n\t\tfi\n\n\t\tif [ ${response} -eq 200 ];then\n\t\t\techo \"Note: PHP Mailer will not work in Azure. Kindly use external SMTP mail server.\"\n\t\tfi\n\t\tset +x\n\t\tcurl -v -L -G -d \"app=board&os=${os}&version=${version}\" -k \"https://restya.com/success_installation.php\"\n\t\techo \"Restyaboard URL : $IPADDR\"\n\n\t\techo \"Login with username admin and password restya\"\n\t\texit 1\n\t}\n\tmain\n\terror=$?\n\tos=$(lsb_release -i -s)\n\tcurl -v -L -G -d \"app=board&os=${os}&error=${error}\" -k \"https://restya.com/error_installation.php\"\n\techo \"If you're finding it difficult to install Restyaboard from your end, we do also offer installation support that you may consider https://restya.com/contact\"\n\texit 1\n} 2>&1 | tee -a /tmp/restyaboard_install.log", "user_defined_fields": [] }, { "id": 912264, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Rocket.Chat One-Click", "description": "Rocket.Chat One-Click", "ordinal": 97, "logo_url": "assets/rocketchat.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 1805, "deployments_active": 93, "is_public": true, "mine": false, "created": "2021-09-29T17:16:16", "updated": "2023-12-07T12:44:21", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 443\nufw allow 80\nufw allow 3000\nfail2ban_install\n\n# Snapd & rocketchat install\napt install snapd -y\nsnap install rocketchat-server\nsnap info rocketchat-server\n\n# Check DNS\ncheck_dns_propagation \"${FQDN}\" \"${IP}\"\n# SSL\nsnap set rocketchat-server siteurl=https://$FQDN\nsystemctl enable --now snap.rocketchat-server.rocketchat-caddy \nsnap restart rocketchat-server\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address for the SOA", "default": "" } ] }, { "id": 609048, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Ruby on Rails One-Click", "description": "Ruby on Rails One-Click", "ordinal": 98, "logo_url": "assets/rubyonrails.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 458, "deployments_active": 20, "is_public": true, "mine": false, "created": "2019-11-05T07:22:54", "updated": "2023-11-23T04:19:22", "rev_note": "Initial import", "script": "#!/bin/bash\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Ruby on Rails\napt install -y ruby rails\n\n# Configure rails Directory\nmkdir /home/railsapp\ncd /home/railsapp\nrails new $RAILSAPP\ncd $RAILSAPP\nrails s -b 0.0.0.0 &\n\n# Start rails app on reboot\ncrontab -l | { cat; echo \"@reboot cd /home/railsapp/app1/ && rails s -b 0.0.0.0 &\"; } | crontab -\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "railsapp", "label": "Rails Application name", "example": "railsapp" } ] }, { "id": 401703, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Rust One-Click", "description": "Rust - Latest One-Click", "ordinal": 99, "logo_url": "assets/Rust.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 2452, "deployments_active": 8, "is_public": true, "mine": false, "created": "2019-03-08T21:09:34", "updated": "2023-12-05T18:23:42", "rev_note": "Remove SSH Pubkey UDF", "script": "#!/bin/bash\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \nsource \n\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\nGAMESERVER=\"rustserver\"\n\nset_hostname\napt_setup_update\n\n\nif [[ \"$RUSTHOSTNAME\" = \"\" ]]; then\n RUSTHOSTNAME=\"Linode Rust Server\"\nfi\n\nif [[ \"$LEVEL\" = \"Procedural Map\" ]]; then\n LEVEL=\"\"\nfi\n\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix curl \\\nwget file bzip2 gzip unzip bsdmainutils python \\\nutil-linux ca-certificates binutils bc jq tmux \\\nlib32gcc1 libstdc++6 libstdc++6:i386 lib32z1\n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install Rust\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\n#Game Config Options\n\ncp /home/rustserver/lgsm/config-lgsm/rustserver/_default.cfg /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\nchown -R rustserver:rustserver /home/rustserver/\n\necho \"server.globalchat $GLOBALCHAT/\" > /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.pve $PVE\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.description \\\"$DESCRIPTION\\\"\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.maxplayers $MAXPLAYERS\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.seed \\\"$SEED\\\"\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.level $LEVEL\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.hostname \\\"$RUSTHOSTNAME\\\"\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.ip $IP\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\nsed -i \"s/rconpassword=\\\"CHANGE_ME\\\"/rconpassword=\\\"$RCONPASSWORD\\\"/\" /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\nsed -i \"s/worldsize=\\\"3000\\\"/worldsize=\\\"$WORLDSIZE\\\"/\" /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\nsed -i \"s/maxplayers=\\\"50\\\"/maxplayers=\\\"$MAXPLAYERS\\\"/\" /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\n\n\n# Start the service and setup firewall\nufw allow 28015\nufw allow 28016\n\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup", "user_defined_fields": [ { "name": "rusthostname", "label": "Server Hostname", "default": "Linode Rust Server" }, { "name": "description", "label": "Server Description", "default": "Powered by Linode!" }, { "name": "rconpassword", "label": "RCON Password" }, { "name": "maxplayers", "label": "Maximum Players", "oneof": "10,25,50,75,100", "default": "50" }, { "name": "level", "label": "World", "oneof": "Procedural Map,Barren,HapisIsland,SavasIsland_koth", "default": "Procedural Map" }, { "name": "worldsize", "label": "World Size", "oneof": "1000,3000,6000", "default": "3000" }, { "name": "seed", "label": "Seed", "default": "50000" }, { "name": "globalchat", "label": "Global Chat Enabled", "oneof": "true,false", "default": "true" }, { "name": "pve", "label": "PvE Enabled", "oneof": "true,false", "default": "false" } ] }, { "id": 971042, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Saltcorn One-Click", "description": "Saltcorn One-Click", "ordinal": 100, "logo_url": "assets/saltcorn.svg", "images": [ "linode/ubuntu20.04", "linode/debian11" ], "deployments_total": 304, "deployments_active": 6, "is_public": true, "mine": false, "created": "2022-02-08T16:21:05", "updated": "2023-12-02T23:13:46", "rev_note": "", "script": "#!/bin/bash\n## Saltcorn Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\nfunction saltcorninstall {\n wget -qO - https://deb.nodesource.com/setup_14.x | sudo bash -\n apt-get install -qqy nodejs\n npx saltcorn-install -y\n systemctl enable saltcorn\n systemctl stop saltcorn\n cat < /lib/systemd/system/saltcorn.service\n[Unit]\nDescription=saltcorn\nDocumentation=https://saltcorn.com\nAfter=network.target\n\n[Service]\nType=notify\nWatchdogSec=5\nUser=saltcorn\nWorkingDirectory=/home/saltcorn\nExecStart=/home/saltcorn/.local/bin/saltcorn serve -p 8080\nRestart=always\nEnvironment=\"NODE_ENV=production\"\n\n[Install]\nWantedBy=multi-user.target\nEND\n systemctl daemon-reload\n systemctl start saltcorn\n}\n\nfunction firewallsaltcorn {\n ufw allow 22\n ufw allow 80\n ufw allow 443\n}\n\nfunction nginxreversesaltcorn {\n apt-get install nginx -y\n cat < /etc/nginx/conf.d/saltcorn.conf\nserver {\n listen 80;\n server_name $FQDN $IP;\n\n location / {\n proxy_set_header X-Forwarded-For \\$remote_addr;\n proxy_set_header Host \\$http_host;\n proxy_pass http://localhost:8080;\n }\n}\nEND\n nginx -t\n unlink /etc/nginx/sites-enabled/default\n systemctl restart nginx\n}\n\nfunction ssl_saltcorn {\napt install certbot python3-certbot-nginx -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction main {\n saltcorninstall\n nginxreversesaltcorn\n firewallsaltcorn\n ssl_saltcorn\n\n}\n# Execute\nmain \nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address for Letsencrypt SSL", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 774829, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "ServerWand One-Click", "description": "ServerWand One-Click", "ordinal": 101, "logo_url": "assets/serverwand.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 1079, "deployments_active": 11, "is_public": true, "mine": false, "created": "2021-02-19T17:28:16", "updated": "2023-12-04T17:45:07", "rev_note": "", "script": "#!/bin/bash\n\n# Logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# serverwand ssh key\nmkdir -p /root/.ssh/\nchmod 700 /root/.ssh/\ncurl https://serverwand.com/api/servers/connect > ~/.ssh/authorized_keys\nchmod 600 /root/.ssh/authorized_keys", "user_defined_fields": [] }, { "id": 1177225, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Seatable One-Click", "description": "Seatable One-Click App", "ordinal": 102, "logo_url": "assets/seatable.svg", "images": [ "linode/debian11" ], "deployments_total": 44, "deployments_active": 1, "is_public": true, "mine": false, "created": "2023-05-16T19:56:00", "updated": "2023-12-04T16:58:01", "rev_note": "", "script": "#!/bin/bash\n\n# \n# \n# \n\nsource \n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION \n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Update and basic installs\nsystem_update\ndebian_upgrade\nenable_fail2ban\nsystem_install_package ufw ca-certificates curl gnupg lsb-release curl pwgen\n\n# Install docker\nmkdir -p /etc/apt/keyrings\ncurl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\necho \\\n \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \\\n $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\nchmod a+r /etc/apt/keyrings/docker.gpg\napt-get -y update\napt-get -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-compose\n\n# Pull current seatable container\ndocker pull seatable/seatable-enterprise:latest\nmkdir /opt/seatable\nwget -O \"/opt/seatable/docker-compose.yml\" \"https://manual.seatable.io/docker/Enterprise-Edition/docker-compose.yml\"\n\n# Prepare SeaTable\nMYSQL_PASSWORD=`pwgen -s 30 1`\nsed -i \"s|DB_ROOT_PASSWD=.*|DB_ROOT_PASSWD=${MYSQL_PASSWORD}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|MYSQL_ROOT_PASSWORD=.*|MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|SEATABLE_SERVER_LETSENCRYPT=.*|SEATABLE_SERVER_LETSENCRYPT=${LE}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|SEATABLE_SERVER_HOSTNAME=.*|SEATABLE_SERVER_HOSTNAME=${URL}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|TIME_ZONE=.*|TIME_ZONE=${TIMEZONE}|\" /opt/seatable/docker-compose.yml\n\n# Add a license\nmkdir -p /opt/seatable/seatable-data/seatable\ntouch /opt/seatable/seatable-data/seatable/seatable-license.txt\ncat << EOF > /opt/seatable/seatable-data/seatable/seatable-license.txt\n#SeaTable server licence\nName = \"Cloud Trial\"\nLicencetype = \"User\"\nLicenceKEY = \"1672935702\"\nProductID = \"SeaTable server\"\nExpiration = \"2024-01-31\"\nMaxUsers = \"3\"\nMode = \"subscription\"\nHash = \"045af708265d7d549cad51fc2b678272a1d15ab8cbfbf05734e371504bb72b388f4441493c7bfeccce7c19ac9c6877cb8f3aecc3beebe685db007832e1c0231728a92772d45dc1c08facbc225d90776f86d34cb4154bafe7c983b6767ffb31a74b133de61edf15c170564fcefb6e457012f63b95ed4aaf6fd2e1e1cfc2ad93a682cfab2fe86f427f7d93ae9b69cbaf02a7565074a95a8c1176402f250d2e815ab206a6b65009c65d94259772ab31a00c11e5c6b57fda0fbb1b22a69734c10214594a5d7b4c88a995eaeb3a65f9aa5d163d9e5c09f73105a4ef760a8421fb66d1982da739c42808fded9a95e456090747e494b0a1aee2a40f388d9f1146051754\"\nEOF\n\n# firewall\nufw limit ssh\nufw allow 80\nufw allow 443\nufw --force enable\n\n# Message of the day\ncat << EOF > /etc/motd\n#############################\n#############################\nSeaTable Enterprise Server\n\nTo finish the installation, change to the directory /opt/seatable and follow our deployment instructions at https://manual.seatable.io/docker/Enterprise-Edition/Deploy%20SeaTable-EE%20with%20Docker/.\nYou can skip the beginning and start directly with the adjustment of the docker-compose.yml file.\n\nPlease visit https://forum.seatable.io for SeaTable community support.\n#############################\n#############################\n\nEOF\n\necho \"Installation complete\"\nall_set\nstackscript_cleanup", "user_defined_fields": [ { "name": "url", "label": "The domain/subdomain for SeaTable Server", "example": "https://seatable.example.org" }, { "name": "le", "label": "Get a Let's Encrypt certificate", "default": "True", "oneof": "True,False" }, { "name": "timezone", "label": "Choose your timezone (e.g Europe/Berlin)", "example": "Choices can be found here: http://en.wikipedia.org/wiki/List_of_tz_zones_by_name", "default": "Etc/UTC" } ] }, { "id": 604068, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Shadowsocks One-Click", "description": "Shadowsocks One-Click", "ordinal": 103, "logo_url": "assets/shadowsocks.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 9210, "deployments_active": 342, "is_public": true, "mine": false, "created": "2019-10-22T16:11:39", "updated": "2023-12-07T13:04:29", "rev_note": "final edit", "script": "#!/usr/bin/env bash\n\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Install & configure shadowsocks\nfunction install_shadowsocks {\n apt-get install shadowsocks-libev -y\n cat </etc/shadowsocks-libev/config.json\n{\n\"server\":\"$IP\",\n\"server_port\":8000,\n\"local_port\":1080,\n\"password\":\"$SHADOWPASSWORD\",\n\"timeout\":60,\n\"method\":\"aes-256-gcm\"\n}\nEND\n systemctl start shadowsocks-libev\n systemctl enable shadowsocks-libev\n systemctl restart shadowsocks-libev\n}\n\nfunction shadowsocks_firewall {\n ufw allow 8000\n}\n\nfunction main {\n install_shadowsocks\n shadowsocks_firewall\n stackscript_cleanup\n}\n\n# Execute function\nmain", "user_defined_fields": [ { "name": "shadowpassword", "label": "Shadowsocks Password", "example": "Password" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address for SOA Recorf", "default": "" } ] }, { "id": 1243780, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "SimpleX Chat One-Click", "description": "SimpleX Chat", "ordinal": 104, "logo_url": "assets/simplexchat.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 57, "deployments_active": 7, "is_public": true, "mine": false, "created": "2023-09-28T15:20:59", "updated": "2023-12-07T10:15:46", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Simplex Settings\n# \n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-simplex-chat\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n # Simplex variables\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n if [[ -n ${DOMAIN} && -n ${SUBDOMAIN} ]]; then\n echo \"addr: ${SUBDOMAIN}.${DOMAIN}\" >> ${group_vars}\n elif [[ -n ${DOMAIN} ]]; then\n echo \"addr: ${DOMAIN}\" >> ${group_vars}\n else\n echo \"addr: $(hostname -I | awk '{print $1}')\" >> ${group_vars}\n fi\n else\n echo \"addr: $(hostname -I | awk '{print $1}')\" >> ${group_vars}\n fi\n\n if [[ -n ${SMP_PASSWORD} ]]; then\n echo \"smp_password: ${SMP_PASSWORD}\" >> ${group_vars};\n fi\n\n if [[ -n ${XFTP_QUOTA} ]]; then\n case ${XFTP_QUOTA} in\n *gb) echo \"xftp_quota: ${XFTP_QUOTA}\" >> ${group_vars} ;;\n *) echo \"xftp_quota: ${XFTP_QUOTA}gb\" >> ${group_vars} ;;\n esac\n fi\n\n # Linode variables\n\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n else echo \"No email entered\";\n fi\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "smp_password", "label": "Set password for smp-server.", "example": "123qwe", "default": "" }, { "name": "xftp_quota", "label": "Set xftp-server file storage quota in GB.", "example": "1/5/10/100gb", "default": "10gb" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "SOA Email", "example": "user@domain.tld", "default": "" } ] }, { "id": 869153, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Splunk One-Click", "description": "Splunk One-Click", "ordinal": 105, "logo_url": "assets/splunk.svg", "images": [ "linode/debian10", "linode/ubuntu20.04" ], "deployments_total": 958, "deployments_active": 96, "is_public": true, "mine": false, "created": "2021-07-20T19:04:43", "updated": "2023-12-07T02:04:33", "rev_note": "", "script": "#!/usr/bin/env bash\n\n### UDF Variables\n\n## Splunk settings\n#\n#\n\n## Domain settings\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n\n## Linode/SSH Settings - Optional\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n# Configure Splunk\nwget https://download.splunk.com/products/splunk/releases/8.2.0/linux/splunk-8.2.0-e053ef3c985f-Linux-x86_64.tgz\nwget \ntar zxvf splunk-8.2.0-e053ef3c985f-Linux-x86_64.tgz -C /opt/\nuseradd splunk --system --shell=/usr/sbin/nologin\nchown -R splunk:splunk /opt/splunk\n\napt install -y expect\n SPLUNK_INSTALL=$(expect -c \"\n set timeout 10\n spawn /opt/splunk/bin/splunk enable boot-start -user splunk -systemd-managed 1 --accept-license\n expect \\\"Please enter an administrator username:\\\"\n send \\\"$SPLUNK_USER\\r\\\"\n expect \\\"Please enter a new password:\\\"\n send \\\"$SPLUNK_PASSWORD\\r\\\"\n expect \\\"Please confirm new password:\\\"\n send \\\"$SPLUNK_PASSWORD\\r\\\"\n expect eof\n \")\n\n# Start daemon\nsystemctl start Splunkd\nsystemctl status Splunkd\n\n# Firewall\nufw allow 22 \nufw allow 8000\nufw allow 8089\nufw allow 9997\n\n# Clean up\nstackscript_cleanup", "user_defined_fields": [ { "name": "splunk_user", "label": "Splunk Admin User" }, { "name": "splunk_password", "label": "Splunk Admin password" }, { "name": "token_password", "label": "Your Linode API token. This is required in order to create DNS records.", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Admin Email for the server", "default": "" }, { "name": "username", "label": "The username for the Linode's admin/SSH user (Please ensure that the username entered does not contain any uppercase characters)", "example": "user1", "default": "" }, { "name": "password", "label": "The password for the Linode's admin/SSH user", "example": "S3cuReP@s$w0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key used to securely access the Linode via SSH", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 1102904, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Superinsight One-Click", "description": "Superinsight One-Click app", "ordinal": 106, "logo_url": "assets/superinsight.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 29, "deployments_active": 1, "is_public": true, "mine": false, "created": "2022-12-20T17:43:01", "updated": "2023-12-03T07:53:56", "rev_note": "", "script": "#!/usr/bin/bash\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Install docker\ncurl -fsSL get.docker.com | sudo sh\n\n# Creating Password\necho \"Superinsight setting up password....\"\nADMIN_PASSWORD=$(openssl rand -hex 12)\nNODE_IP=$(hostname -I | cut -f1 -d' ')\necho \"Downloading and Installing Superinsight instance......\"\n\n# Install Superinsight\ndocker run \\\n--detach \\\n--name superinsight-db-standalone \\\n--restart always \\\n-p 5432:5432 \\\n-v vol-superinsight:/db \\\n-e SUPERINSIGHT_USER=admin \\\n-e SUPERINSIGHT_PASSWORD=\"${ADMIN_PASSWORD}\" \\\nsuperinsight/superinsight-db-standalone:latest\n\n\n# Print instructions\ncat << EOF > /etc/motd\n\n################################################################################################################################################\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSUPERINSIGHT\n################################################################################################################################################\n\nSuperinsight created the user admin with password: ${ADMIN_PASSWORD}\nYou can can connect using a database client with the following connection string postgres://admin:${ADMIN_PASSWORD}@${NODE_IP}:5432/superinsight\nFor complete source code and information, visit: https://github.com/superinsight/superinsight-db\n\n################################################################################################################################################\nEOF", "user_defined_fields": [] }, { "id": 401705, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Terraria One-Click", "description": "Terraria One-Click", "ordinal": 107, "logo_url": "assets/Terraria.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 705, "deployments_active": 6, "is_public": true, "mine": false, "created": "2019-03-08T21:10:49", "updated": "2023-12-06T13:35:55", "rev_note": "Remove SSH Pubkey UDF", "script": "#!/bin/bash\n#\n#\n#\n\n#Game config options\n\n#\n#\n#\n#\n#\n#\n#\n\n\n#Non-MVP config options\n#name=\"autocreate\" label=\"autocreate\" default=\"1\"/>\n#name=\"worldpath\" label=\"worldpath\" default=\"~/.local/share/Terraria/Worlds/\"/>\n#name=\"banlist\" label=\"banlist\" default=\"banlist.txt\"/>\n#name=\"priority\" label=\"priority\" default=\"1\"/>\n#name=\"upnp\" label=\"upnp\" default=\"1\"/>\n#name=\"npcstream\" label=\"npcstream\" default=\"60\"/>\n#name=\"secure\" label=\"secure\" default=\"1\"/>\n#name=\"language\" label=\"language\" default=\"en-US\"/>\n\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -xo pipefail\n\nGAMESERVER=\"terrariaserver\"\n\n### UDF to config\n\nif [[ \"$DIFFICULTY\" = \"Normal\" ]]; then\n DIFFICULTY=\"0\"\nelif [[ \"$DIFFICULTY\" = \"Expert\" ]]; then\n DIFFICULTY=\"1\"\nfi\n\nset_hostname\napt_setup_update\n\n\n# Terraria specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix \\\ncurl wget file bzip2 gzip unzip bsdmainutils \\\npython util-linux ca-certificates binutils bc \\\njq tmux lib32gcc1 libstdc++6 libstdc++6:i386\n\n# Install linuxGSM\nlinuxgsm_install\n\necho Requires Steam username and password to install\nsu - $GAMESERVER -c \"mkdir -p /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER\"\nsu - $GAMESERVER -c \"touch /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER/common.cfg\"\nsu - $GAMESERVER -c \"echo steamuser=\\\"$STEAMUSER\\\" >> /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER/common.cfg\"\nsu - $GAMESERVER -c \"echo steampass=\\''$STEAMPASSWORD'\\' >> /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER/common.cfg\"\n\n# Install Terraria\ngame_install\n\nsed -i s/#seed=AwesomeSeed/seed=\"$SEED\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/worldname=world1/worldname=\"$WORLDNAME\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/difficulty=0/difficulty=\"$DIFFICULTY\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/maxplayers=20/maxplayers=\"$MAXPLAYERS\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/port=7777/port=\"$PORT\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/password=/password=\"$PASSWORD\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/motd=.*/motd=\"$MOTD\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n\n#Non-MVP config options\n# sed -i s/autocreate=1/autocreate=\"$AUTOCREATE\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/worldpath=\\~\\/\\.local\\/share\\/Terraria\\/Worlds\\//worldpath=\"$WORLDPATH\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/banlist=banlist.txt/banlist=\"$BANLIST\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/\\#priority=1/priority=\"$PRIORITY\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/#npcstream=60/npcstream=\"$NPCSTREAM\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/#upnp=1/upnp=\"$UPNP\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/secure=1/secure=\"$SECURE\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/language=en\\-US/language=\"$LANGUAGE\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n\n# Setup crons and create systemd service file\nservice_config\n\n# Start the service and setup firewall\nufw_install\nufw allow \"$PORT\"/tcp\nufw allow \"$PORT\"/udp\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup", "user_defined_fields": [ { "name": "steamuser", "label": "Steam Username", "example": "username" }, { "name": "steampassword", "label": "Steam Password, must have Steam Guard turned off for deployment", "example": "YourSteamPassword" }, { "name": "worldname", "label": "World Name", "default": "world1" }, { "name": "password", "label": "Server Password", "default": "" }, { "name": "motd", "label": "Message of the Day", "default": "Powered by Linode!" }, { "name": "difficulty", "label": "Difficulty Level", "oneof": "Normal,Expert", "default": "Normal" }, { "name": "maxplayers", "label": "Maximum Players", "oneof": "1,10,20,50,100,200,255,", "default": "20" }, { "name": "port", "label": "Port", "default": "7777" }, { "name": "seed", "label": "Seed", "default": "AwesomeSeed" } ] }, { "id": 401704, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "TF2 One-Click", "description": "TF2 One-Click", "ordinal": 108, "logo_url": "assets/TF2.svg", "images": [ "linode/debian11" ], "deployments_total": 353, "deployments_active": 2, "is_public": true, "mine": false, "created": "2019-03-08T21:10:23", "updated": "2023-11-30T21:57:13", "rev_note": "Remove SSH Pubkey UDF", "script": "#!/bin/bash\n#\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nGAMESERVER=\"tf2server\"\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n### UDF to config\n\n#Autoteambalance\nif [[ \"$AUTOTEAMBALANCE\" = \"Enabled\" ]]; then\n AUTOTEAMBALANCE=1\nelif [[ \"$AUTOTEAMBALANCE\" = \"Disabled\" ]]; then\n AUTOTEAMBALANCE=0\nfi\n\nif [[ \"$SERVERNAME\" = \"\" ]]; then\n SERVERNAME=\"Linode TF2 Server\"\nfi\n\n\n# Server config\nset_hostname\napt_setup_update\n\n\n# Teamfortress2 specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\napt -q -y install mailutils postfix curl wget file \\\nbzip2 gzip unzip bsdmainutils python util-linux \\\nca-certificates binutils bc jq tmux lib32gcc-s1 libstdc++6 \\\nlibstdc++6:i386 libcurl4-gnutls-dev:i386 libtcmalloc-minimal4:i386\n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install Teamfortress2\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\ncp /home/tf2server/lgsm/config-lgsm/tf2server/_default.cfg /home/tf2server/lgsm/config-lgsm/tf2server/common.cfg\n\n# Custom game configs\n> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\ncat <> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\nlog on\nsv_logbans 1\nsv_logecho 1\nsv_logfile 1\nsv_log_onefile\nEND\n\necho \"hostname $SERVERNAME\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"mp_autoteambalance $AUTOTEAMBALANCE\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"mp_maxrounds $MAXROUNDS\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"mp_timelimit $TIMELIMIT\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"rcon_password \\\"$RCONPASSWORD\\\"\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"sv_password \\\"$SVPASSWORD\\\"\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"\\\"$MOTD\\\"\" > /home/tf2server/serverfiles/tf/cfg/motd_default.txt\n\n\n# Start the service and setup firewall\nufw_install\nufw allow 27014:27050/tcp\nufw allow 3478:4380/udp\nufw allow 27000:27030/udp\nufw allow 26901\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup", "user_defined_fields": [ { "name": "motd", "label": "Message of the Day", "default": "Powered by Linode!" }, { "name": "servername", "label": "Server Name", "default": "Linode TF2 Server" }, { "name": "svpassword", "label": "Server Password", "default": "" }, { "name": "gslt", "label": "Game Server Login Token", "example": "Steam gameserver token. Needed to list as public server", "default": "" }, { "name": "autoteambalance", "label": "Team Balance Enabled", "oneof": "Enabled,Disabled", "default": "Enabled" }, { "name": "maxrounds", "label": "Maximum Rounds", "oneof": "1,3,5,10,15,20", "default": "5" }, { "name": "timelimit", "label": "Round Time Limit", "oneof": "10,15,35,45,60", "default": "35" }, { "name": "rconpassword", "label": "RCON password" } ] }, { "id": 1051711, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "UniFi Network Application One-Click", "description": "UniFi Network Application One-Click", "ordinal": 109, "logo_url": "assets/unifi.svg", "images": [ "linode/debian10" ], "deployments_total": 493, "deployments_active": 23, "is_public": true, "mine": false, "created": "2022-09-01T15:41:39", "updated": "2023-10-18T12:38:34", "rev_note": "", "script": "#!/bin/bash\n#\n# Script to install UniFi Controller on Linode\n# \n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n## Enable logging\n\nset -x\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Register default rDNS \nexport DEFAULT_RDNS=$(dnsdomainname -A | awk '{print $1}')\n\n#set absolute domain if any, otherwise use DEFAULT_RDNS\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DEFAULT_RDNS\"\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\ncreate_a_record $SUBDOMAIN $IP $DOMAIN\n\n## install depends \nexport DEBIAN_FRONTEND=noninteractive\napt-get install apt-transport-https ca-certificates wget dirmngr gpg software-properties-common multiarch-support libcommons-daemon-java jsvc openjdk-11-jre-headless -y \n\n# install mongodb req libssl1\nwget http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u12_amd64.deb\ndpkg -i libssl1.0.0_1.0.1t-1+deb8u12_amd64.deb\n\n# install mongodb-3.4\nwget -qO - https://www.mongodb.org/static/pgp/server-3.4.asc | apt-key add -\necho \"deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 main\" | tee /etc/apt/sources.list.d/mongodb-org-3.4.list\napt update && apt upgrade -y\napt install mongodb-org -y \n \n# install latest UniFi Controller \necho 'deb https://www.ui.com/downloads/unifi/debian stable ubiquiti' | sudo tee /etc/apt/sources.list.d/100-ubnt-unifi.list\nsudo wget -O /etc/apt/trusted.gpg.d/unifi-repo.gpg https://dl.ui.com/unifi/unifi-repo.gpg \napt update && apt install unifi -yq \n\n## install nginx reverse-proxy \napt install nginx -y \n\n#configure nginx reverse proxy\nrm /etc/nginx/sites-enabled/default\ntouch /etc/nginx/sites-available/reverse-proxy.conf\ncat < /etc/nginx/sites-available/reverse-proxy.conf\nserver {\n listen 80;\n listen [::]:80;\n server_name ${ABS_DOMAIN};\n\n access_log /var/log/nginx/reverse-access.log;\n error_log /var/log/nginx/reverse-error.log;\n location /wss/ {\n proxy_pass https://localhost:8443;\n proxy_http_version 1.1;\n proxy_buffering off;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection \"Upgrade\";\n proxy_read_timeout 86400;\n }\n location / {\n proxy_pass https://localhost:8443;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forward-For \\$proxy_add_x_forwarded_for;\n }\n}\nEND\nln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/reverse-proxy.conf\n\n#enable and start nginx\nsystemctl enable nginx\nsystemctl restart nginx \n\n## UFW rules \nufw allow http\nufw allow https\nufw allow 53\nufw allow 3479/udp\nufw allow 5514/udp\nufw allow 8080/tcp\nufw allow 8443/tcp\nufw allow 8880/tcp\nufw allow 8843/tcp\nufw allow 27117/tcp\nufw allow 5656:5699/udp\nufw allow 10001/udp \nufw allow 1900/udp\nufw allow 123/udp\nufw enable \n\nsleep 60 \n\n## install SSL certs. required \napt install python3-certbot-nginx -y \ncertbot run --non-interactive --nginx --agree-tos --redirect -d ${ABS_DOMAIN} -m ${SOA_EMAIL_ADDRESS} -w /var/www/html/\n \n## add some details \ncat << EOF > /etc/motd\n###################\n\n The installation is now complete, and you can access the UniFi Network Controller GUI from https://${ABS_DOMAIN}\n We recommend using the GUI to complete your configurations of the service\n\n################### \nEOF\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode.", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 970523, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Uptime Kuma One-Click", "description": "Uptime Kuma One-Click", "ordinal": 110, "logo_url": "assets/uptimekuma.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 2271, "deployments_active": 396, "is_public": true, "mine": false, "created": "2022-02-07T16:06:08", "updated": "2023-12-07T12:53:44", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## KUMA Settings \n#\n\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-uptimekuma\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n # Uptimekuma vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" } ] }, { "id": 925530, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "UTunnel VPN One-Click", "description": "UTunnel VPN One-Click", "ordinal": 111, "logo_url": "assets/utunnel.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 1191, "deployments_active": 16, "is_public": true, "mine": false, "created": "2021-10-25T18:55:37", "updated": "2023-12-07T12:38:27", "rev_note": "", "script": "#!/bin/bash\n# Update the packages on the system from the distribution repositories.\t\napt-get update\nDEBIAN_FRONTEND=noninteractive apt-get upgrade -y\n\n# Install pre-requisites for docker-ce\n\nDEBIAN_FRONTEND=noninteractive apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common\n\n#Add Docker official GPG key\n\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -\n\n#Add repository\n\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\"\n\n# Download and install utnservice\n\nmkdir /utunnel\n\ncd /utunnel \n\nwget https://files.utunnel.io/production/deploy/install_bundle_20.tar\n\ntar -xf install_bundle_20.tar\n\nrm -f install_bundle_20.tar", "user_defined_fields": [] }, { "id": 781317, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Valheim One-Click", "description": "Valheim One-Click", "ordinal": 112, "logo_url": "assets/valheim.svg", "images": [ "linode/debian10" ], "deployments_total": 2425, "deployments_active": 51, "is_public": true, "mine": false, "created": "2021-03-01T13:26:36", "updated": "2023-12-07T02:11:35", "rev_note": "", "script": "#!/usr/bin/env bash\n\n### UDF Variables\n\n## Valheim Server Settings - Required\n#\n#\n\n## Linode/SSH Security Settings - Required\n#\n#\n\n## Linode/SSH Settings - Optional\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n[ ! $USERNAME ] && USERNAME='lgsmuser'\nsource \n\n\n# Download and install dependencies\ndpkg --add-architecture i386\nsystem_update\nsystem_install_package curl wget file tar expect bzip2 gzip unzip \\\n bsdmainutils python util-linux ca-certificates \\\n binutils bc jq tmux netcat lib32gcc1 lib32stdc++6 \\\n libc6-dev libsdl2-2.0-0:i386\n\n\n# Open the needed firewall ports\nufw allow 2456:2458/udp\nufw allow 4380/udp\nufw allow 27000:27030/udp\n\n# Install linuxGSM\nGAMESERVER='vhserver'\nv_linuxgsm_oneclick_install \"$GAMESERVER\" \"$USERNAME\"\n\n# Set the Valheim dedicated server's name and password\ncat /home/$USERNAME/lgsm/config-lgsm/vhserver/_default.cfg >> /home/$USERNAME/lgsm/config-lgsm/vhserver/vhserver.cfg\nsed -i \"s/servername=\\\"Valheim Server\\\"/servername=\\\"$SERVER_NAME\\\"/\" /home/$USERNAME/lgsm/config-lgsm/vhserver/vhserver.cfg\nsed -i \"s/serverpassword=\\\"\\\"/serverpassword=\\\"$SERVER_PASSWORD\\\"/\" /home/$USERNAME/lgsm/config-lgsm/vhserver/vhserver.cfg\n\n# Start and enable the Valheim services\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\n\n# Clean up\nstackscript_cleanup", "user_defined_fields": [ { "name": "server_name", "label": "The name of the Valheim dedicated server" }, { "name": "server_password", "label": "The password for the Valheim dedicated server", "example": "S3cuReP@s$w0rd" }, { "name": "username", "label": "The username for the Linode's admin/SSH user (Please ensure that the username entered does not contain any uppercase characters)", "example": "lgsmuser" }, { "name": "password", "label": "The password for the Linode's admin/SSH user", "example": "S3cuReP@s$w0rd" }, { "name": "pubkey", "label": "The SSH Public Key used to securely access the Linode via SSH", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 954759, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "VictoriaMetrics Single One-Click", "description": "VictoriaMetrics Single", "ordinal": 113, "logo_url": "assets/victoriametricssingle.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 39, "deployments_active": 4, "is_public": true, "mine": false, "created": "2022-01-06T18:53:56", "updated": "2023-10-18T12:38:34", "rev_note": "", "script": "#!/bin/bash\n# \nsource \nsystem_set_hostname \"$HOSTNAME\"\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nexport DEBIAN_FRONTEND=noninteractive\napt update && apt upgrade -y && apt install -y curl wget net-tools traceroute jq\n# Generate files\nmkdir -p /etc/victoriametrics/single\nmkdir -p /var/lib/victoria-metrics-data\nmkdir -p /var/lib/cloud/scripts/per-instance\n# Create victoriametrics user\ngroupadd -r victoriametrics\nuseradd -g victoriametrics -d /var/lib/victoria-metrics-data -s /sbin/nologin --system victoriametrics\nchown -R victoriametrics:victoriametrics /var/lib/victoria-metrics-data\n# Install VictoriaMetrics Single\nVM_VERSION=`curl -sg \"https://api.github.com/repos/VictoriaMetrics/VictoriaMetrics/tags\" | jq -r '.[0].name'`\nwget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/${VM_VERSION}/victoria-metrics-linux-amd64-${VM_VERSION}.tar.gz -O /tmp/victoria-metrics.tar.gz\ntar xvf /tmp/victoria-metrics.tar.gz -C /usr/bin\nchmod +x /usr/bin/victoria-metrics-prod\nchown root:root /usr/bin/victoria-metrics-prod\ntouch /etc/victoriametrics/single/scrape.yml\nchown root:root /etc/victoriametrics/single/scrape.yml\ncat </etc/systemd/system/vmsingle.service\n[Unit]\nDescription=VictoriaMetrics is a fast, cost-effective and scalable monitoring solution and time series database.\n# https://docs.victoriametrics.com\nAfter=network.target\n[Service]\nType=simple\nUser=victoriametrics\nGroup=victoriametrics\nWorkingDirectory=/var/lib/victoria-metrics-data\nStartLimitBurst=5\nStartLimitInterval=0\nRestart=on-failure\nRestartSec=5\nEnvironmentFile=-/etc/victoriametrics/single/victoriametrics.conf\nExecStart=/usr/bin/victoria-metrics-prod \\$ARGS\nExecStop=/bin/kill -s SIGTERM \\$MAINPID\nExecReload=/bin/kill -HUP \\$MAINPID\n# See docs https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#tuning\nProtectSystem=full\nLimitNOFILE=1048576\nLimitNPROC=1048576\nLimitCORE=infinity\nStandardOutput=syslog\nStandardError=syslog\nSyslogIdentifier=vmsingle\n[Install]\nWantedBy=multi-user.target\nEND\ncat </etc/victoriametrics/single/victoriametrics.conf\n# See https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#list-of-command-line-flags to get more information about supported command-line flags\n# \n# If you use IPv6 pleas add \"-enableTCP6\" to args line\nARGS=\"-promscrape.config=/etc/victoriametrics/single/scrape.yml -storageDataPath=/var/lib/victoria-metrics-data -retentionPeriod=12 -httpListenAddr=:8428 -graphiteListenAddr=:2003 -opentsdbListenAddr=:4242 -influxListenAddr=:8089 -enableTCP6\"\nEND\ncat < /etc/profile.d/victoriametrics_welcome.sh\n#!/bin/sh\n#\nmyip=$(hostname -I | awk '{print$1}')\n******************************************************************************** \nWelcome to VictoriaMetrics Single.\nTo keep this server secure, the UFW firewall is enabled.\nAll ports are BLOCKED except 22 (SSH), 80 (HTTP), and 443 (HTTPS), 8428 (VictoriaMetrics HTTP), 8089 (VictoriaMetrics Influx),\n4242 (VictoriaMetrics OpenTSDB), 2003 (VictoriaMetrics Graphite)\nIn a web browser, you can view:\n * The VictoriaMetrics Quickstart guide: https://kutt.it/1click-quickstart\nOn the server:\n * The default VictoriaMetrics root is located at /var/lib/victoria-metrics-data\n * VictoriaMetrics is running on ports: 8428, 8089, 4242, 2003 and they are bound to the local interface.\n********************************************************************************\n # This image includes version v1.74.0 of VictoriaMetrics. \n # See Release notes https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.70.0\n # Welcome to VictoriaMetrics droplet!\n # Website: https://victoriametrics.com\n # Documentation: https://docs.victoriametrics.com\n # VictoriaMetrics Github : https://github.com/VictoriaMetrics/VictoriaMetrics\n # VictoriaMetrics Slack Community: https://slack.victoriametrics.com\n # VictoriaMetrics Telegram Community: https://t.me/VictoriaMetrics_en\n # VictoriaMetrics config: /etc/victoriametrics/single/victoriametrics.conf\n # VictoriaMetrics scrape config: /etc/victoriametrics/single/scrape.yml\n # VictoriaMetrics UI accessable on: http://your_droplet_public_ipv4:8428/vmui/\nEND\n# Enable UFW and add some rules to it\nsed -e 's|DEFAULT_FORWARD_POLICY=.*|DEFAULT_FORWARD_POLICY=\"ACCEPT\"|g' \\\n -i /etc/default/ufw\nufw allow ssh comment \"SSH port\"\nufw allow http comment \"HTTP port\"\nufw allow https comment \"HTTPS port\"\nufw allow 8428 comment \"VictoriaMetrics Single HTTP port\"\nufw allow 8089/tcp comment \"TCP Influx Listen port for VictoriaMetrics\"\nufw allow 8089/udp comment \"UDP Influx Listen port for VictoriaMetrics\"\nufw allow 2003/tcp comment \"TCP Graphite Listen port for VictoriaMetrics\"\nufw allow 2003/udp comment \"UDP Graphite Listen port for VictoriaMetrics\"\nufw allow 4242 comment \"OpenTSDB Listen port for VictoriaMetrics\"\nufw --force enable\n# Cleaning up\nrm -rf /tmp/* /var/tmp/*\nhistory -c\ncat /dev/null > /root/.bash_history\nunset HISTFILE\nfind /var/log -mtime -1 -type f ! -name 'stackscript.log' -exec truncate -s 0 {} \\;\n# Start VictoriaMetrics\nsystemctl enable vmsingle.service\nsystemctl start vmsingle.service\necho \"Installation complete!\"", "user_defined_fields": [ { "name": "hostname", "label": "Hostname" } ] }, { "id": 662117, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Virtualmin One-Click", "description": "Virtualmin One-Click", "ordinal": 114, "logo_url": "assets/virtualmin.svg", "images": [ "linode/debian10", "linode/ubuntu22.04" ], "deployments_total": 2203, "deployments_active": 139, "is_public": true, "mine": false, "created": "2020-08-12T15:46:13", "updated": "2023-12-06T13:31:08", "rev_note": "", "script": "#!/usr/bin/env bash\n\n### UDF Variables for the StackScript\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n#\n#\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nIFS=$'\\n\\t'\n\n## Import the Bash StackScript and API/DNS Libraries\nsource \nsource \n\n# Import the OCA Helper Functions\nsource \n\nfunction install_virtualmin {\n if [ $(cat /etc/os-release | grep -i 'ubuntu' )]; then\n if [ ! $(cat /etc/os-release | grep -i 'lts') ]; then\n printf \"Virtualmin only works with LTS versions of Ubuntu\\n\"\n exit 1;\n fi\n else\n wget http://software.virtualmin.com/gpl/scripts/virtualmin-install.sh -O /root/virtualmin-install.sh && {\n chmod +x /root/virtualmin-install.sh\n /bin/sh /root/virtualmin-install.sh -f -v\n }\n fi\n}\n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Configure firewall and install Fail2Ban\nufw_install\nufw allow http\nufw allow https\nufw allow 10000\nfail2ban_install\n\n# Install Webmin and Virtualmin\nsource \ninstall_virtualmin\n\n# Disable SSL so that everything works\nsed -i 's/^ssl=1/ssl=0/g' /etc/webmin/miniserv.conf\n\n# Restart Webmin\nsystemctl restart webmin\n\n# Clean up\nstackscript_cleanup", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "pwless_sudo", "label": "Enable passwordless sudo access for the limited user?", "oneof": "Yes,No", "default": "No" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "auto_updates", "label": "Configure automatic security updates?", "oneof": "Yes,No", "default": "No" }, { "name": "fail2ban", "label": "Use fail2ban to prevent automated intrusion attempts?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your DNS records", "default": "" }, { "name": "subdomain", "label": "The subdomain for your server", "default": "" }, { "name": "domain", "label": "Your domain", "default": "" }, { "name": "soa_email_address", "label": "Admin Email for the server", "default": "" }, { "name": "mx", "label": "Do you need an MX record for this domain? (Yes if sending mail from this Linode)", "oneof": "Yes,No", "default": "No" }, { "name": "spf", "label": "Do you need an SPF record for this domain? (Yes if sending mail from this Linode)", "oneof": "Yes,No", "default": "No" } ] }, { "id": 688903, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "VS Code Server One-Click", "description": "Visual Studio Code One-Click", "ordinal": 115, "logo_url": "assets/vscodeserver.svg", "images": [ "linode/debian10" ], "deployments_total": 5256, "deployments_active": 123, "is_public": true, "mine": false, "created": "2020-11-17T21:10:25", "updated": "2023-12-07T15:40:23", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## VS Code Server OCA Script\n\n### UDF Variables\n\n## VS Code Web Password\n#\n#\n\n## User and SSH Security\n#\n#\n#\n#\n\n## Domain\n#\n#\n#\n#\n\n## Let's Encrypt SSL\n#\n\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n\nfunction get_code_server {\n local -r username=\"$1\" vs_code_ver=\"$2\"\n\n cd \"/home/$username\"\n\n wget \"https://github.com/cdr/code-server/releases/download/v${vs_code_ver}/code-server-${vs_code_ver}-linux-amd64.tar.gz\"\n tar -xf \"code-server-${vs_code_ver}-linux-amd64.tar.gz\"\n mv code-server-*/ bin/\n\n chown -R \"${username}:${username}\" bin/\n chmod +x bin/code-server\n mkdir data/\n chown -R \"${username}:${username}\" data/\n\n cd /root/\n}\n\nfunction enable_code_service {\n local -r vs_code_password=\"$1\" username=\"$2\"\n\n # Set the password in /etc/systemd/system/code-server.service\n cat << EOF > /etc/systemd/system/code-server.service\n[Unit]\nDescription=code-server\nAfter=nginx.service\n[Service]\nUser=$username\nWorkingDirectory=/home/$username\nEnvironment=PASSWORD=$vs_code_password\nExecStart=/home/${username}/bin/code-server --host 127.0.0.1 --user-data-dir /home/${username}/data --auth password\nRestart=always\n[Install]\nWantedBy=multi-user.target\nEOF\n\n # Enable code-server as a service\n systemctl daemon-reload\n systemctl start code-server\n systemctl enable code-server\n}\n\nfunction certbot_standalone {\n local -r email_address=\"$1\" ssl_domain=\"$2\"\n\n # Get an SSL certificate from CertBot\n system_install_package \"certbot\"\n certbot -n certonly --standalone --agree-tos -m \"$email_address\" -d \"$ssl_domain\"\n}\n\nfunction nginx_reverse_proxy {\n local -r ssl_domain=\"$1\"\n\n ## Setup a reverse proxy with Nginx\n system_install_package \"nginx\"\n\n cat << EOF > /etc/nginx/sites-available/code-server\nserver {\n listen 80;\n server_name $ssl_domain;\n # enforce https\n return 301 https://\\$server_name:443\\$request_uri;\n}\nserver {\n listen 443 ssl http2;\n server_name $ssl_domain;\n ssl_certificate /etc/letsencrypt/live/${ssl_domain}/fullchain.pem;\n ssl_certificate_key /etc/letsencrypt/live/${ssl_domain}/privkey.pem;\n location / {\n proxy_pass http://127.0.0.1:8080/;\n proxy_set_header Host \\$host;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection upgrade;\n proxy_set_header Accept-Encoding gzip;\n }\n}\nEOF\n\n ln -s /etc/nginx/sites-available/code-server /etc/nginx/sites-enabled\n nginx -t\n systemctl restart nginx\n}\n\n### Install UFW and open the needed firewall ports\nufw allow 80,443/tcp\n\n### Install and configure VS Code Server\nget_code_server \"$USERNAME\" \"$VS_CODE_VER\"\nenable_code_service \"$VS_CODE_PASSWORD\" \"$USERNAME\"\ncheck_dns_propagation \"$FQDN\" \"$IP\"\ncertbot_standalone \"$SOA_EMAIL_ADDRESS\" \"$FQDN\"\nnginx_reverse_proxy \"$FQDN\"\n\n### Clean up\nstackscript_cleanup", "user_defined_fields": [ { "name": "vs_code_password", "label": "The password to login to the VS Code Web UI" }, { "name": "vs_code_ver", "label": "The version of VS Code Server you'd like installed", "default": "3.10.2" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "disable_root", "label": "Would you like to disable root login over SSH? (Recommended)", "oneof": "Yes,No", "default": "Yes" }, { "name": "token_password", "label": "Your Linode API token - This is required for creating DNS records", "default": "" }, { "name": "domain", "label": "The domain for the Linode's DNS record (Requires API token)", "default": "" }, { "name": "subdomain", "label": "The subdomain for the Linode's DNS record (Requires API token and domain)", "default": "" }, { "name": "soa_email_address", "label": "Your email address for your VirtualHost configuration, DNS records (If Required), and SSL certificates (If Required)." }, { "name": "ssl", "label": "Would you like to use a free Let's Encrypt SSL certificate? (Uses the Linode's default rDNS if no domain is specified above", "oneof": "Yes,No", "default": "No" } ] }, { "id": 923037, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "WarpSpeed One-Click", "description": "WarpSpeed One-Click", "ordinal": 116, "logo_url": "assets/warpspeed.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 880, "deployments_active": 19, "is_public": true, "mine": false, "created": "2021-10-18T01:12:49", "updated": "2023-12-06T00:07:58", "rev_note": "", "script": "#!/bin/bash\nset -o errexit\nset -o nounset\nset -o pipefail\nset -o xtrace\n\n# \n# \n# \n# \n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nexport DEBIAN_FRONTEND=\"noninteractive\"\napt-get \\\n -o 'Acquire::ForceIPv4=true' \\\n --yes \\\n update\n\napt-get \\\n -o 'DPkg::options::=--force-confdef' \\\n -o 'DPkg::options::=--force-confold' \\\n --yes \\\n install grub-pc\n\napt-get \\\n -o Acquire::ForceIPv4=true \\\n --yes \\\n update\n# # END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Handle the arguments.\nWIRESPEED_ADMIN_EMAIL=\"$(echo -e \"${WIRESPEED_ADMIN_EMAIL}\" | tr --delete '[:space:]')\"\nWIRESPEED_HTTP_HOST=\"$(echo -e \"${WIRESPEED_HTTP_HOST}\" | tr --delete '[:space:]')\"\nWIRESPEED_HTTP_HOST=\"${WIRESPEED_HTTP_HOST//\\//}\"\nWIRESPEED_HTTP_HOST=\"${WIRESPEED_HTTP_HOST//https:/}\"\nWIRESPEED_HTTP_HOST=\"${WIRESPEED_HTTP_HOST//http:/}\"\n\nif [[ -z \"${WIRESPEED_ADMIN_EMAIL}\" ]]; then\n echo \"Missing required parameter: admin email\"\n exit 101\nfi\n\nif [[ -z \"${WIRESPEED_HTTP_HOST}\" ]]; then\n echo \"Missing required parameter: http host\"\n exit 102\nfi\n\nif [[ -z \"${WIRESPEED_DATA_DIR}\" ]]; then\n WIRESPEED_DATA_DIR=\"/wirespeed\"\nfi\n\n# Set hostname\nIP=\"$(hostname --all-ip-addresses | awk '{ print $1 }')\"\nhostnamectl set-hostname \"${WIRESPEED_HTTP_HOST}\"\necho \"${IP} ${WIRESPEED_HTTP_HOST}\" >>/etc/hosts\n\nwget https://bunker.services/wirespeed-installer.sh\nchmod +x wirespeed-installer.sh\n./wirespeed-installer.sh \\\n \"${WIRESPEED_HTTP_HOST}\" \\\n \"${WIRESPEED_DATA_DIR}\" \\\n \"${WIRESPEED_ADMIN_EMAIL}\" \\\n \"${WIRESPEED_ADMIN_PASSWORD}\" \\\n --non-interactive\n\n# Force IPv4 and noninteractive upgrade after script runs to prevent breaking nf_conntrack for UFW\necho 'Acquire::ForceIPv4 \"true\";' >/etc/apt/apt.conf.d/99force-ipv4\napt-get upgrade --yes\n\nfor file in /root/StackScript /root/ssinclude* /root/wirespeed-installer.sh; do\n rm \"${file}\"\ndone\n\necho 'WireSpeed Installation complete!'", "user_defined_fields": [ { "name": "wirespeed_admin_email", "label": "Admin Email", "default": "", "example": "it@example.com" }, { "name": "wirespeed_admin_password", "label": "Admin Password", "default": "", "example": "Password" }, { "name": "wirespeed_http_host", "label": "DNS Name", "default": "", "example": "vpn.example.com" }, { "name": "wirespeed_data_dir", "label": "Data Directory", "default": "/wirespeed", "example": "/wirespeed" } ] }, { "id": 913276, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Wazuh One-Click", "description": "Wazuh One-Click", "ordinal": 117, "logo_url": "assets/wazuh.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 5340, "deployments_active": 836, "is_public": true, "mine": false, "created": "2021-09-30T18:27:36", "updated": "2023-12-07T16:02:33", "rev_note": "", "script": "#!/bin/bash\n\n# #\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings \n#\n#\n#\n\n## Enable logging\n# set -o pipefail\nset -x\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# UFW https://documentation.wazuh.com/current/getting-started/architecture.html\nufw allow 1514\nufw allow 1515\nufw allow 1516\nufw allow 514\nufw allow 55000\nufw allow 443\nufw allow 80\nufw allow 9200\nufw allow 9300\n\n# NGINX\napt install git nginx certbot python3-certbot-nginx -y\n\nmkdir -p /var/www/certs/.well-known\nchown -R www-data:www-data /var/www/certs/\ncat < /etc/nginx/sites-available/$FQDN\nserver {\n listen 80;\n listen [::]:80;\n server_name $FQDN;\n root /var/www/certs;\n location / {\n try_files \\$uri \\$uri/ =404;\n }\n# allow .well-known\n location ^~ /.well-known {\n allow all;\n auth_basic off;\n alias /var/www/certs/.well-known;\n }\n}\nEOF\nln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/$FQDN\nunlink /etc/nginx/sites-enabled/default\nsystemctl restart nginx\n\n# SSL Certbot\n#certbot certonly --agree-tos --webroot --webroot-path=/var/www/certs -d $FQDN -m $SOA_EMAIL_ADDRESS\n\nfunction get_cert {\n if [ \"$1\" == \"dry_run\" ]; then\n certbot certonly --dry-run --agree-tos --non-interactive --no-eff-email --webroot --webroot-path=/var/www/certs -d $FQDN -m $SOA_EMAIL_ADDRESS\n return $?\n elif [ \"$1\" == \"run\" ]; then\n certbot certonly --agree-tos --non-interactive --no-eff-email --webroot --webroot-path=/var/www/certs -d $FQDN -m $SOA_EMAIL_ADDRESS\n return $?\n fi\n}\n\nfunction propagate {\n while [[ $count -le $retries ]]; do\n echo \"[Info] Let's Encrypt validation failed. Retrying...\"\n sleep 5\n count=$(( $count + 1 ))\n get_cert dry_run\n\n if [ $? -eq 0 ]; then\n echo \"[Info] Dry run successful..\"\n get_cert run\n return 0\n \n fi\n\n # no more retries left. Exit\n if [[ $count -eq $retries ]]; then\n echo \"[Error] Unable to get Let's Encrypt certificate for $FQDN\"\n return 1\n fi\n done\n}\n\ncount=1\nretries=24\nget_cert dry_run\nif [ $? -eq 0 ]; then\n echo \"[Info] Dry run successful. Getting certificate\"\n get_cert run\nelse\n propagate\nfi\n\n# reorder Wazuh script\ncurl -sO https://packages.wazuh.com/4.4/wazuh-install.sh && sudo bash ./wazuh-install.sh -a \ntar -O -xvf wazuh-install-files.tar wazuh-install-files/wazuh-passwords.txt >> .deployment-secrets.txt\n\n# Set Variables\nexport WAZUH_FULL=/etc/wazuh-dashboard/certs/wazuh-dashboard.pem\nexport WAZUH_PRIVKEY=/etc/wazuh-dashboard/certs/wazuh-dashboard-key.pem\nexport FULLCHAIN=/etc/letsencrypt/live/$FQDN/fullchain.pem\nexport PRIVKEY=/etc/letsencrypt/live/$FQDN/privkey.pem\n\n# Place certificates in /etc/wazuh-dashboard/certs/\ncat $FULLCHAIN > $WAZUH_FULL\ncat $PRIVKEY > $WAZUH_PRIVKEY\n\n# Restart Kibana\nservice wazuh-dashboard restart\n\n# Create Cert renewal cron script\ncat </root/certbot-renewal.sh\n#!/bin/bash\n#\n# Script to handle Certbot renewal & Kibana\n# Debug\n# set -xo pipefail\nexport WAZUH_FULL=/etc/wazuh-dashboard/certs/wazuh-dashboard.pem\nexport WAZUH_PRIVKEY=/etc/wazuh-dashboard/certs/wazuh-dashboard-key.pem\nexport FULLCHAIN=/etc/letsencrypt/live/$FQDN/fullchain.pem\nexport PRIVKEY=/etc/letsencrypt/live/$FQDN/privkey.pem\ncertbot renew\ncat $FULLCHAIN > $WAZUH_FULL\ncat $PRIVKEY > $WAZUH_PRIVKEY\nservice wazuh-dashboard restart\nEND\n\nchmod +x /root/certbot-renewal.sh\n\n# Setup Cron\ncrontab -l > cron\necho \"* 1 * * 1 bash /root/certbot-renewal.sh\" >> cron\ncrontab cron\nrm cron\n\n# Cleanup\nstackscript_cleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your WordPress server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 662116, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Webmin One-Click", "description": "Webmin One-Click", "ordinal": 118, "logo_url": "assets/webmin.svg", "images": [ "linode/debian10" ], "deployments_total": 1189, "deployments_active": 35, "is_public": true, "mine": false, "created": "2020-08-12T15:41:21", "updated": "2023-12-06T16:14:51", "rev_note": "", "script": "#!/usr/bin/env bash\n\n### UDF Variables for the StackScript\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n#\n#\n\n#Check if the script is being sourced by another script\n[[ $_ != $0 ]] && readonly SOURCED=1\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript and API/DNS Libraries\nsource \nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction webmin_install {\n # Install webmin\n echo \"deb http://download.webmin.com/download/repository sarge contrib\" >> /etc/apt/sources.list\n wget -q -O- http://www.webmin.com/jcameron-key.asc | sudo apt-key add\n system_update\n system_install_package \"webmin\"\n}\n\nfunction webmin_configure {\n local -r email_address=\"$1\"\n local -r fqdn=\"$2\"\n\n # Configure the Virtual Host\n cat < /etc/apache2/sites-available/\"${fqdn}.conf\"\n\n ServerAdmin ${email_address}\n ServerName ${fqdn}\n ProxyPass / http://localhost:10000/\n ProxyPassReverse / http://localhost:10000/\n\nEOF\n # Disable SSL in Webmin so Apache can handle it instead\n sed -i 's/^ssl=1/ssl=0/g' /etc/webmin/miniserv.conf\n\n # Add FQDN to the list of allowed domains\n echo \"referers=${fqdn}\" >> /etc/webmin/config\n\n # Restart Webmin\n systemctl restart webmin\n\n # Enable proxy_http module\n a2enmod proxy_http\n systemctl restart apache2\n\n # Enable the Virtual Host\n a2ensite \"${fqdn}\"\n systemctl reload apache2\n}\n\n\n# Open the needed firewall ports\nufw_install\nufw allow http\nufw allow https\nufw allow 10000\n\n# Make sure unzip is installed, or else the webmin install will fail\n[ ! -x /usr/bin/unzip ] && system_install_package \"unzip\"\n\n# \"${package_list[@]}\" contains a list of packages to be installed on the system\npackage_list=(\n \"gnupg1\" \\\n \"python\" \\\n \"apt-show-versions\" \\\n \"libapt-pkg-perl\" \\\n \"libauthen-pam-perl\" \\\n \"libio-pty-perl\" \\\n \"libnet-ssleay-perl\"\n)\n\n# Install all of the packages specified in ${package_list[@]}\nsystem_install_package \"${package_list[@]}\"\n\n# Intall Webmin\nwebmin_install\napache_install\nwebmin_configure \"$SOA_EMAIL_ADDRESS\" \"$FQDN\"\n\n# Install SSL Certificate - NOT READY YET\n#certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\n## Cleanup before exiting\nif [ \"$SOURCED\" -ne 1 ]; then\n stackscript_cleanup\nfi", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "pwless_sudo", "label": "Enable passwordless sudo access for the limited user?", "oneof": "Yes,No", "default": "No" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "auto_updates", "label": "Configure automatic security updates?", "oneof": "Yes,No", "default": "No" }, { "name": "fail2ban", "label": "Use fail2ban to prevent automated instrusion attempts?", "oneof": "Yes,No", "default": "No" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your DNS records", "default": "" }, { "name": "subdomain", "label": "The subdomain for your server", "default": "" }, { "name": "domain", "label": "Your domain", "default": "" }, { "name": "soa_email_address", "label": "Admin Email for the server", "default": "" }, { "name": "mx", "label": "Do you need an MX record for this domain? (Yes if sending mail from this Linode)", "oneof": "Yes,No", "default": "No" }, { "name": "spf", "label": "Do you need an SPF record for this domain? (Yes if sending mail from this Linode)", "oneof": "Yes,No", "default": "No" } ] }, { "id": 688902, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Webuzo One-Click", "description": "Webuzo One-Click", "ordinal": 119, "logo_url": "assets/webuzo.svg", "images": [ "linode/ubuntu20.04" ], "deployments_total": 906, "deployments_active": 22, "is_public": true, "mine": false, "created": "2020-11-17T21:04:21", "updated": "2023-12-06T22:29:24", "rev_note": "", "script": "#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source the Bash StackScript Library & Helpers\nsource \nsource \nsource \nsource \n\n# Logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n# Set hostname, configure apt and perform update/upgrade\napt_setup_update\n\n# Install Prereq's & Services\napt install -y wget\nwget -N http://files.webuzo.com/install.sh\nchmod +x install.sh\n./install.sh\nsleep 2\nsystemctl start webuzo.service\n\n# firewall\nufw allow 25\nufw allow 53\nufw allow 587\nufw allow 2002\nufw allow 2003\nufw allow 2004\nufw allow 2005\n\n# Cleanup \nstackscript_cleanup\nreboot", "user_defined_fields": [ { "name": "username", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "default": "" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" } ] }, { "id": 401706, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "WireGuard® One-Click", "description": "WireGuard One-Click", "ordinal": 120, "logo_url": "assets/Wireguard.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 9370, "deployments_active": 295, "is_public": true, "mine": false, "created": "2019-03-08T21:11:36", "updated": "2023-12-07T10:04:55", "rev_note": "", "script": "#!/bin/bash\n\n# \n# \n# \n# \n# \n\nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n### Set hostname, Apt configuration and update/upgrade\n\nset_hostname\napt_setup_update\n\napt install wireguard wireguard-tools linux-headers-$(uname -r) -y\n\nif [[ \"$PORT\" != \"51820\" ]]; then\n PORT=\"$PORT\"\nfi\n\n# Wireguard\n\nwg genkey | tee ~/wg-private.key | wg pubkey > ~/wg-public.key\n\nPRIVATEKEY=`cat ~/wg-private.key`\n\ncat </etc/wireguard/wg0.conf\n[Interface]\nPrivateKey = $PRIVATEKEY\nAddress = $PRIVATEIP\nListenPort = $PORT\nPostUp = iptables -A FORWARD -i wg0 -j ACCEPT; \\\niptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; \\\nip6tables -A FORWARD -i wg0 -j ACCEPT; \\\nip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\nPostDown = iptables -D FORWARD -i wg0 -j ACCEPT; \\\niptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; \\\nip6tables -D FORWARD -i wg0 -j ACCEPT; \\\nip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE\nSaveConfig = true\n[Peer]\nPublicKey = $PEERPUBKEY\nAllowedIPs = $PRIVATEIP_CLIENT\nEndpoint = $ENDPOINT:$PORT\nEND\n\n### Enable Port Forwarding\nsed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf\nsysctl -p /etc/sysctl.conf\nsysctl --system\n\n### Services\n\n# wg-quick up wg0. #### Removed to let systemctl manage the service\nsystemctl enable wg-quick@wg0\nsystemctl start wg-quick@wg0\nwg show\nufw_install\nufw allow \"$PORT\"/udp\nufw enable\n\nsystemctl restart wg-quick@wg0\n\nstackscript_cleanup", "user_defined_fields": [ { "name": "port", "label": "Port", "example": "51820", "default": "51820" }, { "name": "privateip", "label": "Tunnel IP", "example": "10.0.0.1/24, 172.16.0.1/24, 192.168.1.1/24, etc", "default": "10.0.1.1/24" }, { "name": "peerpubkey", "label": "WireGuard Public Key (Client)", "default": "" }, { "name": "privateip_client", "label": "Tunnel IP (Client)", "example": "10.0.0.2/24, 172.16.0.2/24, 192.168.1.2/24 etc", "default": "10.0.1.2/24" }, { "name": "endpoint", "label": "Endpoint IP (Client)", "default": "" } ] }, { "id": 401708, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "WooCommerce One-Click", "description": "WooCommerce One-Click", "ordinal": 121, "logo_url": "assets/WooCommerce.svg", "images": [ "linode/ubuntu22.04" ], "deployments_total": 4323, "deployments_active": 211, "is_public": true, "mine": false, "created": "2019-03-08T21:12:57", "updated": "2023-12-07T08:00:35", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Wordpress Settings\n#\n#\n\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-woocommerce\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n webserver_stack: ${web_stack}\n site_title: ${SITE_TITLE}\n wp_admin_user: ${WP_ADMIN_USER}\n wp_db_user: ${WP_DB_USER}\n wp_db_name: ${WP_DB_NAME}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "webserver_stack", "label": "The stack you are looking to deploy Wordpress on", "oneof": "LAMP,LEMP" }, { "name": "site_title", "label": "Website title", "example": "My Blog" }, { "name": "wp_admin_user", "label": "Admin username", "example": "admin" }, { "name": "wp_db_user", "label": "Wordpress database user", "example": "wordpress" }, { "name": "wp_db_name", "label": "Wordpress database name", "example": "wordpress" }, { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your Linode's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" } ] }, { "id": 741207, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Yacht One-Click", "description": "Yacht One-Click", "ordinal": 122, "logo_url": "assets/yacht.svg", "images": [ "linode/debian11", "linode/ubuntu22.04" ], "deployments_total": 965, "deployments_active": 15, "is_public": true, "mine": false, "created": "2021-01-26T21:52:26", "updated": "2023-12-06T21:24:29", "rev_note": "", "script": "#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Yacht Settings \n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-yacht\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # yacht vars\n \n if [[ -n ${YEMAIL} ]]; then\n echo \"yemail: ${YEMAIL}\" >> ${group_vars};\n fi\n\n if [[ -n ${COMPOSE_SUPPORT} ]]; then\n echo \"compose_support: ${COMPOSE_SUPPORT}\" >> ${group_vars};\n fi\n\n if [[ -n ${YTHEME} ]]; then\n echo \"yacht_theme: ${YTHEME}\" >> ${group_vars};\n fi\n\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup", "user_defined_fields": [ { "name": "user_name", "label": "The limited sudo user to be created for the Linode", "default": "" }, { "name": "password", "label": "The password for the limited sudo user", "example": "an0th3r_s3cure_p4ssw0rd", "default": "" }, { "name": "disable_root", "label": "Disable root access over SSH?", "oneof": "Yes,No", "default": "No" }, { "name": "pubkey", "label": "The SSH Public Key that will be used to access the Linode (Recommended)", "default": "" }, { "name": "token_password", "label": "Your Linode API token. This is needed to create your server's DNS records", "default": "" }, { "name": "subdomain", "label": "Subdomain", "example": "The subdomain for the DNS record: www (Requires Domain)", "default": "" }, { "name": "domain", "label": "Domain", "example": "The domain for the DNS record: example.com (Requires API token)", "default": "" }, { "name": "soa_email_address", "label": "Email address (for the Let's Encrypt SSL certificate)", "example": "user@domain.tld" }, { "name": "yemail", "label": "Yacht Email", "example": "admin@yacht.local", "default": "admin@yacht.local" }, { "name": "compose_support", "label": "Yacht Compose Support", "example": "Yes", "default": "Yes", "oneof": "Yes,No" }, { "name": "ytheme", "label": "Yacht Theme", "example": "Default", "default": "Default", "oneof": "Default,RED,OMV" } ] }, { "id": 741208, "username": "linode", "user_gravatar_id": "9d4d301385af69ceb7ad658aad09c142", "label": "Zabbix One-Click", "description": "Zabbix One-Click", "ordinal": 123, "logo_url": "assets/zabbix.svg", "images": [ "linode/centos-stream8" ], "deployments_total": 1781, "deployments_active": 77, "is_public": true, "mine": false, "created": "2021-01-26T21:56:54", "updated": "2023-12-07T15:08:57", "rev_note": "", "script": "#!/bin/bash\n\n# \n\nsource \n\nsystem_set_hostname \"$HOSTNAME\"\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Generate files\nmkdir -p /etc/my.cnf.d/\nmkdir -p /etc/nginx/conf.d/\nmkdir -p /etc/php-fpm.d/\nmkdir -p /etc/php.d/\n# mkdir -p /etc/profile.d/\nmkdir -p /etc/motd.d/\nmkdir -p /etc/zabbix/web/\nmkdir -p /var/lib/cloud/scripts/per-instance\n\ncat </etc/my.cnf.d/zabbix.cnf\n[mysqld]\nuser = mysql\nlocal_infile = 0\n\ndatadir = /var/lib/mysql/\n\ndefault-storage-engine = InnoDB\nskip-name-resolve\nkey_buffer_size = 32M\nmax_allowed_packet = 128M\ntable_open_cache = 1024\ntable_definition_cache = 1024\nmax_connections = 2000\njoin_buffer_size = 1M\nsort_buffer_size = 2M\nread_buffer_size = 256K\nread_rnd_buffer_size = 256K\nmyisam_sort_buffer_size = 1M\nthread_cache_size = 512\nopen_files_limit = 10000\nwait_timeout = 86400\n\noptimizer_switch=index_condition_pushdown=off\n\ntmp_table_size = 32M\nmax_heap_table_size = 32M\n\nbinlog_format=mixed\nbinlog_cache_size = 32M\nmax_binlog_size = 256M\nbinlog_expire_logs_seconds = 259200\n\n# innodb_page_size = 32K\ninnodb_buffer_pool_size = 512M\ninnodb_log_file_size = 256M\ninnodb_log_buffer_size = 64M\ninnodb_file_per_table = 1\ninnodb_flush_method = O_DIRECT\ninnodb_buffer_pool_instances = 4\ninnodb_write_io_threads = 4\ninnodb_read_io_threads = 4\ninnodb_adaptive_flushing = 1\ninnodb_lock_wait_timeout = 50\n\ninnodb_flush_log_at_trx_commit = 1\n\ninnodb_io_capacity = 300\ninnodb_io_capacity_max = 400\ninnodb_flush_neighbors = 0\n\ninnodb_doublewrite = 1\ninnodb_thread_concurrency = 0\n\ninnodb_purge_threads = 1\n\nserver_id = 1\nbinlog_checksum = crc32\n\ninnodb_lru_scan_depth = 512\n\ninnodb_stats_on_metadata = 0\n\nEND\n\ncat </etc/nginx/conf.d/zabbix_ssl.conf\nserver {\n listen 0.0.0.0:443 ssl http2;\n # server_name ;\n index index.php;\n\n root \\$webroot;\n charset utf8;\n set \\$webroot '/usr/share/zabbix';\n\n access_log /var/log/nginx/zabbix_access_ssl.log main;\n error_log /var/log/nginx/zabbix_error_ssl.log error;\n\n ssl_stapling on;\n ssl_stapling_verify on;\n\n #resolver 192.168.13.160 192.168.10.24;\n\n ssl_certificate /etc/ssl/certs/zabbix_example.crt;\n ssl_certificate_key /etc/ssl/private/zabbix_example.key;\n\n ssl_dhparam /etc/ssl/private/zabbix_dhparam.pem;\n\n ssl_protocols TLSv1.2 TLSv1.3;\n ssl_verify_depth 3;\n #ssl_ciphers HIGH:!aNULL:!MD5;\n ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;\n #ssl_session_cache shared:SSL:10m;\n ssl_session_cache shared:MozSSL:10m;\n ssl_session_timeout 1d;\n ssl_prefer_server_ciphers off;\n ssl_session_tickets off;\n\n add_header Strict-Transport-Security \"max-age=63072000\" always;\n add_header Content-Security-Policy-Report-Only \"default-src https:; script-src https: 'unsafe-eval' 'unsafe-inline'; style-src https: 'unsafe-inline'; img-src https: data:; font-src https: data:; report-uri /csp-report\";\n\n location = /favicon.ico {\n log_not_found off;\n }\n\n location / {\n index index.php;\n try_files \\$uri \\$uri/ =404;\n }\n\n location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico)$ {\n access_log off;\n expires 10d;\n }\n\n location ~ /\\.ht {\n deny all;\n }\n\n location ~ /(api\\/|conf[^\\.]|include|locale) {\n deny all;\n return 404;\n }\n\n location ~ [^/]\\.php(/|$) {\n fastcgi_pass unix:/run/php-fpm/zabbix.sock;\n fastcgi_split_path_info ^(.+\\.php)(/.+)$;\n fastcgi_index index.php;\n\n fastcgi_param DOCUMENT_ROOT /usr/share/zabbix;\n fastcgi_param SCRIPT_FILENAME /usr/share/zabbix\\$fastcgi_script_name;\n fastcgi_param PATH_TRANSLATED /usr/share/zabbix\\$fastcgi_script_name;\n\n include fastcgi_params;\n fastcgi_param QUERY_STRING \\$query_string;\n fastcgi_param REQUEST_METHOD \\$request_method;\n fastcgi_param CONTENT_TYPE \\$content_type;\n fastcgi_param CONTENT_LENGTH \\$content_length;\n\n fastcgi_intercept_errors on;\n fastcgi_ignore_client_abort off;\n fastcgi_connect_timeout 60;\n fastcgi_send_timeout 180;\n fastcgi_read_timeout 180;\n fastcgi_buffer_size 128k;\n fastcgi_buffers 4 256k;\n fastcgi_busy_buffers_size 256k;\n fastcgi_temp_file_write_size 256k;\n }\n}\n\nEND\n\ncat </etc/nginx/conf.d/zabbix.conf\nserver {\n listen 0.0.0.0:80;\n # server_name zabbix;\n\n return 301 https://\\$host\\$request_uri;\n}\n\nEND\n\ncat </etc/nginx/nginx.conf\n# For more information on configuration, see:\n# * Official English Documentation: http://nginx.org/en/docs/\n# * Official Russian Documentation: http://nginx.org/ru/docs/\n\nuser nginx;\nworker_processes auto;\nworker_priority -5;\nworker_rlimit_nofile 256000;\n\nerror_log /var/log/nginx/error.log;\n\npid /run/nginx.pid;\n\n# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.\ninclude /usr/share/nginx/modules/*.conf;\n\nevents {\n worker_connections 5120;\n use epoll;\n multi_accept on;\n}\n\n\nhttp {\n include /etc/nginx/mime.types;\n default_type application/octet-stream;\n\n log_format main\n '\\$http_x_forwarded_for - \\$remote_user [\\$time_local] '\n '\"\\$request\" \\$status \\$bytes_sent '\n '\"\\$http_referer\" \"\\$http_user_agent\" '\n '\"\\$gzip_ratio\"';\n\n access_log /var/log/nginx/access.log main;\n\n open_file_cache max=200000 inactive=20s;\n open_file_cache_valid 30s;\n open_file_cache_min_uses 2;\n open_file_cache_errors on;\n\n limit_conn_zone \\$binary_remote_addr zone=perip:10m;\n limit_conn_zone \\$server_name zone=perserver:10m;\n\n client_header_timeout 5m;\n client_body_timeout 5m;\n send_timeout 5m;\n\n connection_pool_size 4096;\n client_header_buffer_size 4k;\n large_client_header_buffers 4 4k;\n request_pool_size 4k;\n\n reset_timedout_connection on;\n\n\n gzip on;\n gzip_min_length 100;\n gzip_buffers 4 8k;\n gzip_comp_level 5;\n gzip_types text/plain text/css text/xml application/x-javascript application/xml application/xhtml+xml;\n\n types_hash_max_size 2048;\n\n output_buffers 128 512k;\n postpone_output 1460;\n aio on;\n directio 512;\n\n sendfile on;\n client_max_body_size 8m;\n fastcgi_intercept_errors on;\n\n tcp_nopush on;\n tcp_nodelay on;\n\n keepalive_timeout 75 20;\n\n ignore_invalid_headers on;\n\n index index.php;\n server_tokens off;\n\n # Load modular configuration files from the /etc/nginx/conf.d directory.\n # See http://nginx.org/en/docs/ngx_core_module.html#include\n # for more information.\n include /etc/nginx/conf.d/*.conf;\n}\n\nEND\n\ncat </etc/php-fpm.d/zabbix.conf\n[zabbix]\nuser = apache\ngroup = apache\n\nlisten = /run/php-fpm/zabbix.sock\nlisten.acl_users = apache,nginx\nlisten.allowed_clients = 127.0.0.1\n\npm = dynamic\npm.max_children = 50\npm.start_servers = 5\npm.min_spare_servers = 5\npm.max_spare_servers = 35\n\nphp_value[session.save_handler] = files\nphp_value[session.save_path] = /var/lib/php/session\n\nphp_value[max_execution_time] = 300\nphp_value[memory_limit] = 128M\nphp_value[post_max_size] = 16M\nphp_value[upload_max_filesize] = 2M\nphp_value[max_input_time] = 300\nphp_value[max_input_vars] = 10000\n; php_value[date.timezone] = Europe/Riga\nEND\n\n# cat </etc/php.d/99-zabbix.ini\n# max_execution_time=300\n# memory_limit=128M\n# post_max_size=16M\n# upload_max_filesize=2M\n# max_input_time=300\n# always_populate_raw_post_data=-1\n# max_input_vars=10000\n# date.timezone=UTC\n# session.save_path=/var/lib/php/\n# END\n\n# cat </etc/profile.d/zabbix_welcome.sh\n# #!/bin/sh\n# #\n# myip=\\$(hostname -I | awk '{print\\$1}')\n# cat </etc/motd.d/zabbix\n********************************************************************************\n\nZabbix frontend credentials:\n\nUsername: Admin\n\nPassword: replace_password\n\n\nTo learn about available professional services, including technical suppport and training, please visit https://www.zabbix.com/services\n\nOfficial Zabbix documentation available at https://www.zabbix.com/documentation/current/\n\n\n********************************************************************************\nEND\n\n# cat </etc/systemd/system/zabbix-instance-init.service\n# [Unit]\n# After=mariadb.service\n\n# [Service]\n# ExecStart=/var/lib/cloud/scripts/per-instance/001-zabbix\n\n# [Install]\n# WantedBy=multi-user.target\n# END\n\n# cat </etc/yum.repos.d/MariaDB.repo\n# # MariaDB 10.3 CentOS repository list - created 2019-03-28 10:57 UTC\n# # http://downloads.mariadb.org/mariadb/repositories/\n# [mariadb]\n# name = MariaDB\n# baseurl = http://yum.mariadb.org/10.2/centos7-amd64\n# gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB\n# gpgcheck=1\n# END\n\ncat </etc/yum.repos.d/Nginx.repo\n[nginx-stable]\nname=nginx stable repo\nbaseurl=http://nginx.org/packages/centos/\\$releasever/\\$basearch/\ngpgcheck=1\nenabled=1\ngpgkey=https://nginx.org/keys/nginx_signing.key\nmodule_hotfixes=true\n\n[nginx-mainline]\nname=nginx mainline repo\nbaseurl=http://nginx.org/packages/mainline/centos/\\$releasever/\\$basearch/\ngpgcheck=1\nenabled=0\ngpgkey=https://nginx.org/keys/nginx_signing.key\nmodule_hotfixes=true\nEND\n\ncat </etc/zabbix/web/zabbix.conf.php\n 'http://localhost:9200',\n//\t'text' => 'http://localhost:9200'\n//];\n// Value types stored in Elasticsearch.\n//\\$HISTORY['types'] = ['uint', 'text'];\n\n// Used for SAML authentication.\n// Uncomment to override the default paths to SP private key, SP and IdP X.509 certificates, and to set extra settings.\n//\\$SSO['SP_KEY']\t\t\t= 'conf/certs/sp.key';\n//\\$SSO['SP_CERT']\t\t\t= 'conf/certs/sp.crt';\n//\\$SSO['IDP_CERT']\t\t= 'conf/certs/idp.crt';\n//\\$SSO['SETTINGS']\t\t= [];\nEND\n\ncat </tmp/zabbix_server_custom.te\nmodule zabbix_server_custom 1.2;\nrequire {\n type zabbix_var_run_t;\n type tmp_t;\n type zabbix_t;\n class sock_file { create unlink write };\n class unix_stream_socket connectto;\n class process setrlimit;\n class capability dac_override;\n}\n#============= zabbix_t ==============\n#!!!! This avc is allowed in the current policy\nallow zabbix_t self:process setrlimit;\n#!!!! This avc is allowed in the current policy\nallow zabbix_t self:unix_stream_socket connectto;\n#!!!! This avc is allowed in the current policy\nallow zabbix_t tmp_t:sock_file { create unlink write };\n#!!!! This avc is allowed in the current policy\nallow zabbix_t zabbix_var_run_t:sock_file { create unlink write };\n#!!!! This avc is allowed in the current policy\nallow zabbix_t self:capability dac_override;\nEND\n\n# Installing RPM packages\nyum makecache\nyum -y upgrade\nyum -y install wget\nwget https://dev.mysql.com/get/mysql80-community-release-el8-3.noarch.rpm\ndnf -y install mysql80-community-release-el8-3.noarch.rpm\ndnf -y module disable mysql\ndnf -y install https://repo.zabbix.com/zabbix/6.0/rhel/8/x86_64/zabbix-release-6.0-1.el8.noarch.rpm\ndnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm\ndnf -y install epel-release\ndnf -y module enable php:remi-8.1\nyum -y install cloud-init cloud-utils-growpart firewalld nginx php-fpm mysql-community-client mysql-community-server java-1.8.0-openjdk-headless zabbix-server-mysql zabbix-web-mysql zabbix-nginx-conf zabbix-sql-scripts zabbix-agent zabbix-get zabbix-sender zabbix-java-gateway zabbix-js\n\n\n# Configure firewalld\nsystemctl enable firewalld\nsystemctl start firewalld\nfirewall-cmd --permanent --add-service=ssh --zone=public\nfirewall-cmd --permanent --add-service=http --zone=public\nfirewall-cmd --permanent --add-service=https --zone=public\nfirewall-cmd --permanent --add-port=10051/tcp --zone=public\nfirewall-cmd --reload\n\n# Configure SELinux\nrm -rf /tmp/zabbix_server_custom.mod /tmp/zabbix_server_custom.pp\ncheckmodule -M -m -o /tmp/zabbix_server_custom.mod /tmp/zabbix_server_custom.te\nsemodule_package -o /tmp/zabbix_server_custom.pp -m /tmp/zabbix_server_custom.mod\nsemodule -i /tmp/zabbix_server_custom.pp\n\nsetsebool -P httpd_can_connect_zabbix=1\nsetsebool -P zabbix_can_network=1\n\n# Generate SSL certificate\nmkdir -p /etc/ssl/private\nopenssl dhparam -out /etc/ssl/private/zabbix_dhparam.pem 2048\n\nopenssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/zabbix_example.key \\\n -out /etc/ssl/certs/zabbix_example.crt -subj \"/C=LV/ST=Riga/L=Riga/O=Global Security/OU=IT Department/CN=example.zabbix.com\"\n\n# Configure Zabbix instance\nsystemctl enable mysqld\nsystemctl disable nginx\nsystemctl disable php-fpm\nsystemctl disable zabbix-server\nsystemctl enable zabbix-agent\nsystemctl enable zabbix-java-gateway\n\nsystemctl stop nginx php-fpm\n\necho \"Requires=multi-user.target\" >> /usr/lib/systemd/system/cloud-init.target\n\nsystemctl set-default cloud-init.target\n\nchown -R apache:apache /var/lib/php/\n\nchmod g+r /etc/zabbix/zabbix_server.conf\nchmod o+w /run/zabbix/\n\nchmod 755 /etc/my.cnf\nchmod -R 755 /etc/my.cnf.d/\n\nsed -i 's/^#PrintMotd yes/&\\nPrintMotd no/g' /etc/ssh/sshd_config\n\nsed -i '/^; php_value\\[date.timezone\\] /s/^; //' /etc/php-fpm.d/zabbix.conf\n\nsed -i 's/^# JavaGateway=.*/&\\nJavaGateway=127.0.0.1/g' /etc/zabbix/zabbix_server.conf\nsed -i 's/^# StartJavaPollers=.*/&\\nStartJavaPollers=5/g' /etc/zabbix/zabbix_server.conf\nsed -i 's/^# LISTEN_IP=.*/&\\nLISTEN_IP=\"127.0.0.1\"/g' /etc/zabbix/zabbix_java_gateway.conf\n\nescape_spec_char() {\n local var_value=$1\n\n var_value=\"${var_value//\\\\/\\\\\\\\}\"\n var_value=\"${var_value//[$'\\n']/}\"\n var_value=\"${var_value//\\//\\\\/}\"\n var_value=\"${var_value//./\\\\.}\"\n var_value=\"${var_value//\\*/\\\\*}\"\n var_value=\"${var_value//^/\\\\^}\"\n var_value=\"${var_value//\\$/\\\\$}\"\n var_value=\"${var_value//\\&/\\\\&}\"\n var_value=\"${var_value//\\[/\\\\[}\"\n var_value=\"${var_value//\\]/\\\\]}\"\n\n echo \"$var_value\"\n}\n\nsystemctl start mysqld\nsystemctl enable mysqld\nsystemctl enable nginx\nsystemctl enable php-fpm\nsystemctl enable zabbix-server\n\nDB_ROOT_TMP_PASS=$(grep 'temporary password' /var/log/mysqld.log | awk '{print $13}' | tail -1)\nWEB_PASS=$(openssl rand -base64 14)\nWEB_PASS=${WEB_PASS%?}\nINST_NAME=$(hostname)\n\nrm -f /root/.my.cnf\n\nDB_ROOT_PASS=$(MYSQL_PWD=\"$DB_ROOT_TMP_PASS\" mysql --connect-expired-password -s -N -e \"SET PASSWORD FOR root@localhost TO RANDOM;\" | awk '{print $3}')\nDB_ZBX_PASS=$(MYSQL_PWD=\"$DB_ROOT_PASS\" mysql -s -N -e \"CREATE USER 'zabbix_srv'@'localhost' IDENTIFIED WITH mysql_native_password BY RANDOM PASSWORD\" | awk '{print $3}')\nDB_ZBXWEB_PASS=$(MYSQL_PWD=\"$DB_ROOT_PASS\" mysql -s -N -e \"CREATE USER 'zabbix_web'@'localhost' IDENTIFIED WITH mysql_native_password BY RANDOM PASSWORD\" | awk '{print $3}')\n\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"CREATE DATABASE zabbix CHARACTER SET 'utf8' COLLATE 'utf8_bin'\"\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"GRANT SELECT, UPDATE, DELETE, INSERT, CREATE, DROP, ALTER, INDEX, REFERENCES ON zabbix.* TO 'zabbix_srv'@'localhost'\"\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"GRANT SELECT, UPDATE, DELETE, INSERT, CREATE, DROP ON zabbix.* TO 'zabbix_web'@'localhost'\"\n\ncat > /root/.my.cnf << EOF\n[client]\npassword=\"$DB_ROOT_PASS\"\nEOF\n\nzcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz | MYSQL_PWD=\"$DB_ROOT_PASS\" mysql -uroot zabbix\n\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"UPDATE users SET passwd = MD5('$WEB_PASS') WHERE username = 'Admin'\" zabbix\n\nWEB_PASS=$(escape_spec_char \"$WEB_PASS\")\nsed -i \"s/replace_password/$WEB_PASS/g\" /etc/motd.d/zabbix\n\nsed -i \"s/replace_name/$INST_NAME/g\" /etc/zabbix/web/zabbix.conf.php\n\nDB_ZBX_PASS=$(escape_spec_char \"$DB_ZBX_PASS\")\nDB_ZBXWEB_PASS=$(escape_spec_char \"$DB_ZBXWEB_PASS\")\n\nsed -i \"s/^DBUser=.*/DBUser=zabbix_srv/g\" /etc/zabbix/zabbix_server.conf\nsed -i -e \"/^[#;] DBPassword=/s/.*/&\\nDBPassword=$DB_ZBX_PASS/\" /etc/zabbix/zabbix_server.conf\nsed -i \"s/replace_password/$DB_ZBXWEB_PASS/g\" /etc/zabbix/web/zabbix.conf.php\nsed -i \"s/replace_user/zabbix_web/g\" /etc/zabbix/web/zabbix.conf.php\n\n# Cleaning up remote machine\nrm -rf /etc/nginx/conf.d/default.conf\nrm -rf /tmp/* /var/tmp/*\nhistory -c\ncat /dev/null > /root/.bash_history\nunset HISTFILE\nfind /var/log -mtime -1 -type f ! -name 'stackscript.log' -exec truncate -s 0 {} \\;\n\n\n\nsystemctl start zabbix-server zabbix-agent zabbix-java-gateway\nsystemctl start nginx php-fpm\n\necho \"Installation complete!\"", "user_defined_fields": [ { "name": "hostname", "label": "Hostname" } ] } ], "page": 1, "pages": 1, "results": 129 } \ No newline at end of file +{"data":[{"id":1146319,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MongoDB Cluster Null One-Click","description":"MongoDB Cluster Null One-Click\r\nNull stackscript for 1067004","ordinal":0,"logo_url":"assets/mongodbmarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":38,"deployments_active":0,"is_public":true,"mine":false,"created":"2023-03-23T14:00:01","updated":"2023-10-18T12:38:31","rev_note":"","script":"#!/bin/bash\n\n# Null","user_defined_fields":[]},{"id":1146324,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Galera Cluster Null One-Click","description":"Galera Cluster Null One-Click\r\nNull Stackscript for 1088136","ordinal":0,"logo_url":"assets/galeramarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":148,"deployments_active":15,"is_public":true,"mine":false,"created":"2023-03-23T14:19:14","updated":"2023-12-08T19:36:03","rev_note":"","script":"#!/bin/bash","user_defined_fields":[]},{"id":1142293,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Redis Sentinel Cluster Null One-Click","description":"Redis Sentinel Cluster Null One-Click\r\nNull stackscript for 1132204","ordinal":0,"logo_url":"assets/redissentinelmarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":171,"deployments_active":8,"is_public":true,"mine":false,"created":"2023-03-16T14:20:59","updated":"2023-11-29T17:28:24","rev_note":"","script":"#!/bin/bash","user_defined_fields":[]},{"id":1146322,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"PostgreSQL Cluster Null One-Click","description":"PostgreSQL Cluster Null One-Click\r\nNull Stackscript for 1068726","ordinal":0,"logo_url":"assets/postgresqlmarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":215,"deployments_active":6,"is_public":true,"mine":false,"created":"2023-03-23T14:17:07","updated":"2023-12-12T10:46:19","rev_note":"","script":"#!/bin/bash\n\n# Null","user_defined_fields":[]},{"id":1226546,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"HashiCorp Nomad Cluster Null One-Click","description":"Nomad Cluster Null One-Click","ordinal":0,"logo_url":"assets/nomadocc.svg","images":["linode/ubuntu22.04"],"deployments_total":378,"deployments_active":12,"is_public":true,"mine":false,"created":"2023-08-25T19:08:21","updated":"2023-11-29T10:42:40","rev_note":"","script":"#!/bin/bash/","user_defined_fields":[]},{"id":1226547,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"HashiCorp Nomad Cluster Clients Null One-Click","description":"Nomad Cluster Clients One-Click","ordinal":0,"logo_url":"assets/nomadclientsocc.svg","images":["linode/ubuntu22.04"],"deployments_total":407,"deployments_active":18,"is_public":true,"mine":false,"created":"2023-08-25T19:08:57","updated":"2023-11-29T10:45:14","rev_note":"","script":"#!/bin/bash","user_defined_fields":[]},{"id":401697,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"WordPress One-Click","description":"Wordpress One Click App","ordinal":1,"logo_url":"assets/WordPress.svg","images":["linode/ubuntu22.04"],"deployments_total":65125,"deployments_active":4799,"is_public":true,"mine":false,"created":"2019-03-08T21:04:07","updated":"2023-12-12T15:12:42","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Wordpress Settings\n#\n#\n\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-wordpress\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n webserver_stack: ${web_stack}\n site_title: ${SITE_TITLE}\n wp_admin_user: ${WP_ADMIN_USER}\n wp_db_user: ${WP_DB_USER}\n wp_db_name: ${WP_DB_NAME}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"webserver_stack","label":"The stack you are looking to deploy Wordpress on","oneof":"LAMP,LEMP"},{"name":"site_title","label":"Website title","example":"My Blog"},{"name":"wp_admin_user","label":"Admin username","example":"admin"},{"name":"wp_db_user","label":"Wordpress database user","example":"wordpress"},{"name":"wp_db_name","label":"Wordpress database name","example":"wordpress"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":632758,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Nextcloud One-Click","description":"One Click App - Nextcloud","ordinal":2,"logo_url":"assets/nextcloud.svg","images":["linode/ubuntu22.04"],"deployments_total":19114,"deployments_active":843,"is_public":true,"mine":false,"created":"2020-02-18T16:40:45","updated":"2023-12-12T16:02:03","rev_note":"","script":"#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n\n# Install docker\ncurl -fsSL https://get.docker.com | sudo sh\n\n# Adjust permissions\nsudo mkdir -p /mnt/ncdata\nsudo chown -R 33:0 /mnt/ncdata\n\n# Install Nextcloud\nsudo docker run -d \\\n--init \\\n--name nextcloud-aio-mastercontainer \\\n--restart always \\\n-p 80:80 \\\n-p 8080:8080 \\\n-p 8443:8443 \\\n-e NEXTCLOUD_MOUNT=/mnt/ \\\n-e NEXTCLOUD_DATADIR=/mnt/ncdata \\\n--volume nextcloud_aio_mastercontainer:/mnt/docker-aio-config \\\n--volume /var/run/docker.sock:/var/run/docker.sock:ro \\\nnextcloud/all-in-one:latest\n\n# Some Info\ncat << EOF > /etc/motd\n # # ###### # # ##### #### # #### # # #####\n ## # # # # # # # # # # # # # #\n # # # ##### ## # # # # # # # # #\n # # # # ## # # # # # # # # #\n # ## # # # # # # # # # # # # #\n # # ###### # # # #### ###### #### #### #####\nIf you point a domain to this server ($(hostname -I | cut -f1 -d' ')), you can open the admin interface at https://yourdomain.com:8443\nOtherwise you can open the admin interface at https://$(hostname -I | cut -f1 -d' '):8080\n \nFurther documentation is available here: https://github.com/nextcloud/all-in-one\nEOF\n\n# Install unattended upgrades\nsudo apt-get install unattended-upgrades -y\n\n# firewall\nufw allow 80\nufw allow 443\nufw allow 8080\nufw allow 8443\nufw allow 3478\n\nrm /root/StackScript\nrm /root/ssinclude*\necho \"Installation complete!\"","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is required for creating DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"soa_email_address","label":"SOA email address","default":""}]},{"id":1017300,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Kali Linux One-Click","description":"Kali Linux One-Click","ordinal":3,"logo_url":"assets/kalilinux.svg","images":["linode/kali"],"deployments_total":16968,"deployments_active":485,"is_public":true,"mine":false,"created":"2022-06-21T14:38:37","updated":"2023-12-12T15:23:22","rev_note":"","script":"#!/bin/bash\n## Kali\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\nfunction headlessoreverything {\n if [ $HEADLESS == \"Yes\" ] && [ $EVERYTHING == \"Yes\" ]; then \n DEBIAN_FRONTEND=noninteractive apt-get install kali-linux-everything -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n elif [ $EVERYTHING == \"Yes\" ] && [ $HEADLESS == \"No\" ]; then\n DEBIAN_FRONTEND=noninteractive apt-get install kali-linux-everything -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n elif [ $HEADLESS == \"Yes\" ] && [ $EVERYTHING == \"No\" ]; then \n DEBIAN_FRONTEND=noninteractive apt-get install kali-linux-headless -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n elif [ $HEADLESS == \"No\" ] && [ $EVERYTHING == \"No\" ]; then \n echo \"No Package Selected\"\n fi\n}\n\nfunction vncsetup {\n if [ $VNC == \"Yes\" ]; then \n ## XFCE & VNC Config\n apt-get install xfce4 xfce4-goodies dbus-x11 tigervnc-standalone-server expect -y -yq -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\"\n\n readonly VNCSERVER_SET_PASSWORD=$(expect -c \"\nspawn sudo -u $USERNAME vncserver\nexpect \\\"Password:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Verify:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Would you like to enter a view-only password (y/n)?\\\"\nsend \\\"n\\r\\\"\nexpect eof\n\")\necho \"$VNCSERVER_SET_PASSWORD\"\n sleep 2\n killvncprocess=$(ps aux | grep \"/usr/bin/Xtigervnc :1 -localhost=1 -desktop\" | head -n 1 | awk '{ print $2; }')\n kill $killvncprocess\n touch /etc/systemd/system/vncserver@.service\n cat < /etc/systemd/system/vncserver@.service\n[Unit]\nDescription=a wrapper to launch an X server for VNC\nAfter=syslog.target network.target\n[Service]\nType=forking\nUser=$USERNAME\nGroup=$USERNAME\nWorkingDirectory=/home/$USERNAME\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver -depth 24 -geometry 1280x800 -localhost :%i\nExecStop=/usr/bin/vncserver -kill :%i\n[Install]\nWantedBy=multi-user.target\nEOF\n systemctl daemon-reload\n systemctl start vncserver@1.service\n systemctl enable vncserver@1.service\n\n cat < /etc/motd\n###################################\n# VNC SSH Tunnel Instructions #\n###################################\n\n* Ensure you have a VNC Client installed on your local machine\n* Run the command below to start the SSH tunnel for VNC \n\n ssh -L 61000:localhost:5901 -N -l $USERNAME $FQDN\n\n* For more Detailed documentation please visit the offical Documentation below\n\n https://www.linode.com/docs/products/tools/marketplace/guides/kalilinux\n\n### To remove this message, you can edit the /etc/motd file ###\nEOF\n fi\n}\n\nfunction main {\n headlessoreverything\n vncsetup\n stackscript_cleanup\n}\n\nmain","user_defined_fields":[{"name":"everything","label":"Would you like to Install the Kali Everything Package?","oneof":"Yes,No","default":"Yes"},{"name":"headless","label":"Would you like to Install the Kali Headless Package?","oneof":"Yes,No","default":"No"},{"name":"vnc","label":"Would you like to setup VNC to access Kali XFCE Desktop","oneof":"Yes,No","default":"Yes"},{"name":"username","label":"The VNC user to be created for the Linode. The username accepts only lowercase letters, numbers, dashes (-) and underscores (_)"},{"name":"password","label":"The password for the limited VNC user"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is required for creating DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address for SOA records (Requires API token)","default":""}]},{"id":593835,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Plesk One-Click","description":"Plesk is the leading secure WordPress and website management platform. This Stackscript installs the latest publicly available Plesk, activates a trial license, installs essential extensions, and sets up and configures the firewall. Please allow the script around 15 minutes to finish.","ordinal":4,"logo_url":"assets/plesk.svg","images":["linode/centos7","linode/ubuntu20.04"],"deployments_total":10526,"deployments_active":482,"is_public":true,"mine":false,"created":"2019-09-26T17:34:17","updated":"2023-12-12T10:41:10","rev_note":"updated wording","script":"#!/bin/bash\n# This block defines the variables the user of the script needs to input\n# when deploying using this script.\n#\n## Enable logging\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction pleskautoinstall {\n echo \"Downloading Plesk Auto-Installer\"\n sh <(curl https://autoinstall.plesk.com/one-click-installer || wget -O - https://autoinstall.plesk.com/one-click-installer)\n echo \"turning on http2\"\n /usr/sbin/plesk bin http2_pref --enable\n}\n\nfunction firewall {\n echo \"Setting Firewall to allow proper ports.\"\n if [ \"${detected_distro[distro]}\" = 'centos' ]; then \n iptables -I INPUT -p tcp --dport 21 -j ACCEPT\n iptables -I INPUT -p tcp --dport 22 -j ACCEPT\n iptables -I INPUT -p tcp --dport 25 -j ACCEPT\n iptables -I INPUT -p tcp --dport 80 -j ACCEPT\n iptables -I INPUT -p tcp --dport 110 -j ACCEPT\n iptables -I INPUT -p tcp --dport 143 -j ACCEPT\n iptables -I INPUT -p tcp --dport 443 -j ACCEPT\n iptables -I INPUT -p tcp --dport 465 -j ACCEPT\n iptables -I INPUT -p tcp --dport 993 -j ACCEPT\n iptables -I INPUT -p tcp --dport 995 -j ACCEPT\n iptables -I INPUT -p tcp --dport 8443 -j ACCEPT\n iptables -I INPUT -p tcp --dport 8447 -j ACCEPT\n iptables -I INPUT -p tcp --dport 8880 -j ACCEPT\n elif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\n ufw allow 21\n ufw allow 22\n ufw allow 25\n ufw allow 80\n ufw allow 110\n ufw allow 143\n ufw allow 443\n ufw allow 465\n ufw allow 993\n ufw allow 995\n ufw allow 8443\n ufw allow 8447\n ufw allow 8880\nelse \necho \"Distro Not supported\"\nfi\n}\n\nfunction main {\n pleskautoinstall\n firewall\n}\n\n# Execute script\nsystem_update\nmain\nstackscript_cleanup","user_defined_fields":[]},{"id":595742,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"cPanel One-Click","description":"cPanel One-Click","ordinal":5,"logo_url":"assets/cpanel.svg","images":["linode/ubuntu20.04","linode/almalinux8","linode/rocky8"],"deployments_total":28203,"deployments_active":995,"is_public":true,"mine":false,"created":"2019-09-30T20:17:52","updated":"2023-12-12T13:47:10","rev_note":"","script":"#!/bin/bash\nset -e\n\n# Commit: fde6587e08ea95321ce010e52a9c1b8d02455a97\n# Commit date: 2023-02-13 17:00:46 -0600\n# Generated: 2023-02-17 11:00:28 -0600\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\necho $(date +%Y%m%d%H%M%S) >> /tmp/cpdebug.log\n\n# Linode's Weblish console will truncate lines unless you do this tput smam. This\n# instructs the terminal to wrap your lines, which is especially important so that\n# the WHM login URL that gets printed at the end can be copied.\ntput smam\n\nsource /etc/os-release\n\nis_os_and_version_id_prefix() {\n [[ $ID == $1 ]] && [[ $VERSION_ID =~ ^$2 ]]\n}\n\nis_almalinux8() {\n is_os_and_version_id_prefix almalinux 8\n}\n\nis_centos7() {\n is_os_and_version_id_prefix centos 7\n}\n\nis_cloudlinux7() {\n is_os_and_version_id_prefix cloudlinux 7\n}\n\nis_cloudlinux8() {\n is_os_and_version_id_prefix cloudlinux 8\n}\n\nis_rocky8() {\n is_os_and_version_id_prefix rocky 8\n}\n\nis_ubuntu20() {\n is_os_and_version_id_prefix ubuntu 20.04\n}\n\nis_supported_os() {\n is_almalinux8 || \\\n is_centos7 || \\\n is_cloudlinux7 || \\\n is_cloudlinux8 || \\\n is_rocky8 || \\\n is_ubuntu20\n}\n\nhas_yum() {\n which yum >/dev/null 2>&1\n}\n\nhas_dnf() {\n which dnf >/dev/null 2>&1\n}\n\nhas_apt() {\n which apt >/dev/null 2>&1\n}\n\nis_networkmanager_enabled() {\n systemctl is-enabled NetworkManager.service > /dev/null 2>&1\n}\n\n# cPanel & WHM is incompatible with NetworkManager\nif is_networkmanager_enabled; then\n systemctl stop NetworkManager.service\n systemctl disable NetworkManager.service\n if has_dnf; then\n dnf -y remove NetworkManager\n elif has_yum; then\n yum -y remove NetworkManager\n fi\nfi\n\nhostnamectl set-hostname server.hostname.tld\n\ncd /home && curl -so installer -L https://securedownloads.cpanel.net/latest\n\nif is_supported_os; then\n if is_ubuntu20; then\n apt-get -o Acquire::ForceIPv4=true update -y\n DEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::options::=\"--force-confdef\" -o DPkg::options::=\"--force-confold\" install grub-pc\n sh installer --skiplicensecheck --skip-cloudlinux\n else\n sh installer --skiplicensecheck\n fi\nelse\n echo \"Your distribution is not supported by this StackScript.\"\n install -d -v -m 711 /var/cpanel\n touch /var/cpanel/cpinit.failed\nfi\n\nrm -f /etc/cpupdate.conf\ncat > /root/.bash_profile <<'END_OF_BASH_PROFILE'\n# .bash_profile\n# Get the aliases and functions\nif [ -f ~/.bashrc ]; then\n . ~/.bashrc\nfi\n# User specific environment and startup programs\nPATH=$PATH:$HOME/bin\nexport PATH\nbash /etc/motd.sh\nif [ -t 0 ]; then\n URL=`whmlogin --nowait 2> /dev/null`\n WHMLOGIN_RETURN=$?\n if [ $WHMLOGIN_RETURN == 1 ]; then\n # whmlogin doesn't support --nowait. Output a URL and hope it's accurate.\n echo \"To log in to WHM as the root user, visit the following address in your web browser:\"\n echo \"\"\n whmlogin\n echo \"\"\n echo \"Thank you for using cPanel & WHM!\"\n else\n if [ $WHMLOGIN_RETURN == 2 ]; then\n # whmlogin indicates that cpinit hasn't updated the IP/hostname yet.\n echo \"To log in to WHM as the root user, run the command 'whmlogin' to get a web address for your browser.\"\n echo \"\"\n echo \"Thank you for using cPanel & WHM!\"\n else\n # whmlogin returned a valid URL to use.\n echo \"To log in to WHM as the root user, visit the following address in your web browser:\"\n echo \"\"\n echo \"$URL\"\n echo \"\"\n echo \"Thank you for using cPanel & WHM!\"\n fi\n fi\nfi\nEND_OF_BASH_PROFILE\n\ncat > /etc/motd.sh <<'END_OF_MOTD'\n#!/bin/bash\nsource /etc/os-release\necho \"\n ____ _ ___ __ ___ _ __ __\n ___| _ \\ __ _ _ __ ___| | ( _ ) \\ \\ / / | | | \\/ |\n / __| |_) / _. | ._ \\ / _ \\ | / _ \\/\\ \\ \\ /\\ / /| |_| | |\\/| |\n| (__| __/ (_| | | | | __/ | | (_> < \\ V V / | _ | | | |\n \\___|_| \\__._|_| |_|\\___|_| \\___/\\/ \\_/\\_/ |_| |_|_| |_|\n\"\necho \"Welcome to cPanel & WHM `/usr/local/cpanel/cpanel -V`\"\necho \"\"\necho \"Running $PRETTY_NAME\"\necho \"\"\necho \"For our full cPanel & WHM documentation: https://go.cpanel.net/docs\"\necho \"\"\necho \"For information on how to quickly set up a website in cPanel & WHM: https://go.cpanel.net/buildasite\"\necho \"\" # This new line makes output from bash_profiles easier to read\nEND_OF_MOTD\ntouch /var/cpanel/cpinit.done","user_defined_fields":[]},{"id":691621,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Cloudron One-Click","description":"Cloudron One-Click","ordinal":6,"logo_url":"assets/cloudron.svg","images":["linode/ubuntu20.04"],"deployments_total":13796,"deployments_active":629,"is_public":true,"mine":false,"created":"2020-11-30T21:21:45","updated":"2023-12-12T08:21:34","rev_note":"","script":"#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# apt-get updates\n echo 'Acquire::ForceIPv4 \"true\";' > /etc/apt/apt.conf.d/99force-ipv4\n export DEBIAN_FRONTEND=noninteractive\n apt-get update -y\n\nwget https://cloudron.io/cloudron-setup\nchmod +x cloudron-setup\n./cloudron-setup --provider linode-mp\n\necho All finished! Rebooting...\n(sleep 5; reboot) &","user_defined_fields":[]},{"id":692092,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Secure Your Server One-Click","description":"Secure Your Server One-Click","ordinal":7,"logo_url":"assets/secureyourserver.svg","images":["linode/debian10","linode/ubuntu20.04","linode/debian11","linode/ubuntu22.04"],"deployments_total":4687,"deployments_active":717,"is_public":true,"mine":false,"created":"2020-12-03T10:01:28","updated":"2023-12-12T08:01:50","rev_note":"","script":"#!/usr/bin/env bash\n\n## User and SSH Security\n#\n#\n#\n#\n\n## Domain\n#\n#\n#\n#\n#\n\n## Block Storage\n#\n#\n\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source Linode Helpers\nsource \nsource \nsource \nsource \n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode. (lower case only)"},{"name":"password","label":"The password for the limited sudo user"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode"},{"name":"disable_root","label":"Would you like to disable root login over SSH?","oneof":"Yes,No"},{"name":"token_password","label":"Your Linode API token - This is required for creating DNS records","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token and domain)","default":""},{"name":"soa_email_address","label":"Your email address. This is used for creating DNS records and website VirtualHost configuration.","default":""},{"name":"send_email","label":"Would you like to be able to send email from this domain? (Requires domain)","oneof":"Yes,No","default":"No"},{"name":"volume","label":"To use a Block Storage volume, enter its name here.","default":""},{"name":"volume_size","label":"If creating a new Block Storage volume, enter its size in GB (NOTE: This creates a billable resource at $0.10/month per GB).","default":""}]},{"id":925722,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Pritunl One-Click","description":"Pritunl One-Click","ordinal":8,"logo_url":"assets/pritunl.svg","images":["linode/debian10","linode/ubuntu20.04"],"deployments_total":1170,"deployments_active":81,"is_public":true,"mine":false,"created":"2021-10-26T15:23:37","updated":"2023-12-12T15:30:26","rev_note":"","script":"#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 443\nufw allow 80\nfail2ban_install\n\n# Mongo Install\napt-get install -y wget gnupg dirmngr \nwget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \necho \"deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\necho \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\napt-get update -y\napt-get install -y mongodb-org\nsystemctl enable mongod.service\nsystemctl start mongod.service\n\n# Pritunl\napt-key adv --keyserver hkp://keyserver.ubuntu.com --recv E162F504A20CDF15827F718D4B7C549A058F8B6B\napt-key adv --keyserver hkp://keyserver.ubuntu.com --recv 7568D9BB55FF9E5287D586017AE645C0CF8E292A\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \necho \"deb http://repo.pritunl.com/stable/apt buster main\" | tee /etc/apt/sources.list.d/pritunl.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\necho \"deb http://repo.pritunl.com/stable/apt focal main\" | tee /etc/apt/sources.list.d/pritunl.list\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\n\napt update -y\napt install -y pritunl\n\nsystemctl enable pritunl.service\nsystemctl start pritunl.service\n\n# Performance tune\necho \"* hard nofile 64000\" >> /etc/security/limits.conf\necho \"* soft nofile 64000\" >> /etc/security/limits.conf\necho \"root hard nofile 64000\" >> /etc/security/limits.conf\necho \"root soft nofile 64000\" >> /etc/security/limits.conf\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address for the SOA record","default":""}]},{"id":741206,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"CyberPanel One-Click","description":"CyberPanel One-Click","ordinal":9,"logo_url":"assets/cyberpanel.svg","images":["linode/ubuntu20.04","linode/ubuntu22.04"],"deployments_total":11157,"deployments_active":596,"is_public":true,"mine":false,"created":"2021-01-27T02:46:19","updated":"2023-12-12T14:07:19","rev_note":"","script":"#!/bin/bash\n### linode\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n### Install cyberpanel\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/cybersetup.sh )\n\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )\n\n### Clean up ls tmp folder\nsudo rm -rf /tmp/lshttpd/*","user_defined_fields":[]},{"id":401709,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Minecraft: Java Edition One-Click","description":"Minecraft OCA","ordinal":10,"logo_url":"assets/Minecraft.svg","images":["linode/ubuntu20.04"],"deployments_total":20418,"deployments_active":345,"is_public":true,"mine":false,"created":"2019-03-08T21:13:32","updated":"2023-12-12T16:04:12","rev_note":"remove maxplayers hard coded options [oca-707]","script":"#!/usr/bin/env bash\n# Game config options:\n# https://minecraft.gamepedia.com/Server.properties\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n## Linode/SSH Security Settings - Required\n#\n#\n## Linode/SSH Settings - Optional\n#\n#\n\n# Enable logging for the StackScript\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n[ ! $USERNAME ] && USERNAME='lgsmuser'\nsource \n\n# Difficulty\n[[ \"$DIFFICULTY\" = \"Peaceful\" ]] && DIFFICULTY=0\n[[ \"$DIFFICULTY\" = \"Easy\" ]] && DIFFICULTY=1\n[[ \"$DIFFICULTY\" = \"Normal\" ]] && DIFFICULTY=2\n[[ \"$DIFFICULTY\" = \"Hard\" ]] && DIFFICULTY=3\n\n# Gamemode\n[[ \"$GAMEMODE\" = \"Survival\" ]] && GAMEMODE=0\n[[ \"$GAMEMODE\" = \"Creative\" ]] && GAMEMODE=1\n[[ \"$GAMEMODE\" = \"Adventure\" ]] && GAMEMODE=2\n[[ \"$GAMEMODE\" = \"Spectator\" ]] && GAMEMODE=3\n\n# Player Idle Timeout\n[[ \"$PLAYERIDLETIMEOUT\" = \"Disabled\" ]] && PLAYERIDLETIMEOUT=0\n\n# Minecraft-specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\nsystem_install_package mailutils postfix curl netcat wget file bzip2 \\\n gzip unzip bsdmainutils python util-linux ca-certificates \\\n binutils bc jq tmux openjdk-17-jre dirmngr software-properties-common\n\n# Install LinuxGSM and Minecraft and enable the 'mcserver' service\nreadonly GAMESERVER='mcserver'\nv_linuxgsm_oneclick_install \"$GAMESERVER\" \"$USERNAME\"\n\n# Minecraft configurations\nsed -i s/server-ip=/server-ip=\"$IP\"/ /home/\"$USERNAME\"/serverfiles/server.properties\n\n# Customer config\nsed -i s/allow-flight=false/allow-flight=\"$ALLOWFLIGHT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/allow-nether=true/allow-nether=\"$ALLOWNETHER\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/announce-player-achievements=true/announce-player-achievements=\"$ANNOUNCEPLAYERACHIEVEMENTS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/difficulty=1/difficulty=\"$DIFFICULTY\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/enable-command-block=false/enable-command-block=\"$ENABLECOMMANDBLOCK\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/enable-query=true/enable-query=\"$ENABLEQUERY\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/force-gamemode=false/force-gamemode=\"$FORCEGAMEMODE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/gamemode=0/gamemode=\"$GAMEMODE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/generate-structures=true/generate-structures=\"$GENERATESTRUCTURES\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/hardcore=false/hardcore=\"$HARDCORE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/level-name=world/level-name=\"$LEVELNAME\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/level-seed=/level-seed=\"$LEVELSEED\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/level-type=DEFAULT/level-type=\"$LEVELTYPE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-build-height=256/max-build-height=\"$MAXBUILDHEIGHT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-players=20/max-players=\"$MAXPLAYERS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-tick-time=60000/max-tick-time=\"$MAXTICKTIME\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/max-world-size=29999984/max-world-size=\"$MAXWORLDSIZE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/motd=.*/motd=\"$MOTD\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/network-compression-threshold=256/network-compression-threshold=\"$NETWORKCOMPRESSIONTHRESHOLD\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/op-permission-level=4/op-permission-level=\"$OPPERMISSIONLEVEL\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/player-idle-timeout=0/player-idle-timeout=\"$PLAYERIDLETIMEOUT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/pvp=true/pvp=\"$PVP\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/resource-pack-sha1=/resource-pack-sha1=\"$RESOURCEPACKSHA1\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/server-port=25565/server-port=\"$PORT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/snooper-enabled=true/snooper-enabled=\"$SNOOPERENABLED\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/spawn-animals=true/spawn-animals=\"$SPAWNANIMALS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/spawn-monsters=true/spawn-monsters=\"$SPAWNMONSTERS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/spawn-npcs=true/spawn-npcs=\"$SPAWNNPCS\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/use-native-transport=true/use-native-transport=\"$USENATIVETRANSPORT\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/view-distance=10/view-distance=\"$VIEWDISTANCE\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/rcon.password=*/rcon.password=\"\\\"$RCONPASSWORD\\\"\"/ /home/\"$USERNAME\"/serverfiles/server.properties\nsed -i s/enable-rcon=false/enable-rcon=true/ /home/\"$USERNAME\"/serverfiles/server.properties\n\n# Start the service and setup firewall\nufw allow \"$PORT\"\nufw allow \"25575\"\n\n# Start and enable the Minecraft service\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"levelname","label":"World Name","default":"world"},{"name":"motd","label":"Message of the Day","default":"Powered by Linode!"},{"name":"allowflight","label":"Flight Enabled","oneof":"true,false","default":"false"},{"name":"allownether","label":"Nether World Enabled","oneof":"true,false","default":"true"},{"name":"announceplayerachievements","label":"Player Achievements Enabled","oneof":"true,false","default":"true"},{"name":"maxplayers","label":"Maximum Players","default":"25"},{"name":"playeridletimeout","label":"Player Idle Timeout Limit","oneof":"Disabled,15,30,45,60","default":"Disabled"},{"name":"difficulty","label":"Difficulty Level","oneof":"Peaceful,Easy,Normal,Hard","default":"Easy"},{"name":"hardcore","label":"Hardcore Mode Enabled","oneof":"true,false","default":"false"},{"name":"pvp","label":"PvP Enabled","oneof":"true,false","default":"true"},{"name":"forcegamemode","label":"Force Game Mode Enabled","oneof":"true,false","default":"false"},{"name":"leveltype","label":"World Type","oneof":"DEFAULT,AMPLIFIED,FLAT,LEGACY","default":"DEFAULT"},{"name":"levelseed","label":"World Seed","default":""},{"name":"spawnanimals","label":"Spawn Animals Enabled","oneof":"true,false","default":"true"},{"name":"spawnmonsters","label":"Spawn Monsters Enabled","oneof":"true,false","default":"true"},{"name":"spawnnpcs","label":"Spawn NPCs Enabled","oneof":"true,false","default":"true"},{"name":"gamemode","label":"Game Mode","oneof":"Survival,Creative,Adventure,Spectator","default":"Survival"},{"name":"generatestructures","label":"Structure Generation Enabled","oneof":"true,false","default":"true"},{"name":"maxbuildheight","label":"Maximum Build Height","oneof":"50,100,200,256","default":"256"},{"name":"maxworldsize","label":"Maximum World Size","oneof":"100,1000,10000,100000,1000000,10000000,29999984","default":"29999984"},{"name":"viewdistance","label":"View Distance","oneof":"2,5,10,15,25,32","default":"10"},{"name":"enablecommandblock","label":"Command Block Enabled","oneof":"true,false","default":"false"},{"name":"enablequery","label":"Querying Enabled","oneof":"true,false","default":"true"},{"name":"enablercon","label":"Enable RCON","oneof":"true,false","default":"false"},{"name":"rconpassword","label":"RCON Password","default":""},{"name":"rconport","label":"RCON Port","default":"25575"},{"name":"maxticktime","label":"Maximum Tick Time","default":"60000"},{"name":"networkcompressionthreshold","label":"Network Compression Threshold","default":"256"},{"name":"oppermissionlevel","label":"Op-permission Level","oneof":"1,2,3,4","default":"4"},{"name":"port","label":"Port Number","default":"25565"},{"name":"snooperenabled","label":"Snooper Enabled","oneof":"true,false","default":"true"},{"name":"usenativetransport","label":"Use Native Transport Enabled","oneof":"true,false","default":"true"},{"name":"username","label":"The username for the Linode's non-root admin/SSH user(must be lowercase)","example":"lgsmuser"},{"name":"password","label":"The password for the Linode's non-root admin/SSH user","example":"S3cuReP@s$w0rd"},{"name":"pubkey","label":"The SSH Public Key used to securely access the Linode via SSH","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":869129,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"aaPanel One-Click","description":"aaPanel One-Click","ordinal":11,"logo_url":"assets/aapanel.svg","images":["linode/centos7"],"deployments_total":5389,"deployments_active":320,"is_public":true,"mine":false,"created":"2021-07-20T18:50:46","updated":"2023-12-12T14:34:45","rev_note":"","script":"#!/bin/bash\n\n# Enable logging for the StackScript\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Yum Update\nyum update -y\n\n# Install aapanel\nyum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && echo y|bash install.sh aapanel\n\n# Log aaPanel login information\nbt default > /root/.aapanel_info\n\n# Stackscript Cleanup\nrm /root/StackScript\nrm /root/ssinclude*\necho \"Installation complete!\"","user_defined_fields":[]},{"id":923033,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Akaunting One-Click","description":"Akaunting One-Click","ordinal":12,"logo_url":"assets/akaunting.svg","images":["linode/ubuntu22.04"],"deployments_total":638,"deployments_active":23,"is_public":true,"mine":false,"created":"2021-10-18T01:01:19","updated":"2023-12-09T12:28:31","rev_note":"","script":"#!/bin/bash\n\n# \n# \n# \n# \n\n# \n# \n# \n# \n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nDEBIAN_FRONTEND=noninteractive apt-get update -qq >/dev/null\n\n###########################################################\n# Install NGINX\n###########################################################\napt-get install -y nginx\n\ncat <<'END' >/var/www/html/index.html\n\n \n \n \n \n \n\n Installing Akaunting\n\n \n \n\n \n \n\n \n
\n
\n \n
\n\n
\n \n
\n
\n

Installing...

Get back after 3 minutes!

\n
\n
\n \n\nEND\n\nchown www-data:www-data /var/www/html/index.html\nchmod 644 /var/www/html/index.html\n\n###########################################################\n# MySQL\n###########################################################\napt install -y mariadb-server expect\n\nfunction mysql_secure_install {\n # $1 - required - Root password for the MySQL database\n [ ! -n \"$1\" ] && {\n printf \"mysql_secure_install() requires the MySQL database root password as its only argument\\n\"\n return 1;\n }\n local -r db_root_password=\"$1\"\n local -r secure_mysql=$(\nexpect -c \"\nset timeout 10\nspawn mysql_secure_installation\nexpect \\\"Enter current password for root (enter for none):\\\"\nsend \\\"$db_root_password\\r\\\"\nexpect \\\"Change the root password?\\\"\nsend \\\"n\\r\\\"\nexpect \\\"Remove anonymous users?\\\"\nsend \\\"y\\r\\\"\nexpect \\\"Disallow root login remotely?\\\"\nsend \\\"y\\r\\\"\nexpect \\\"Remove test database and access to it?\\\"\nsend \\\"y\\r\\\"\nexpect \\\"Reload privilege tables now?\\\"\nsend \\\"y\\r\\\"\nexpect eof\n\")\n printf \"$secure_mysql\\n\"\n}\n\n# Set DB root password\necho \"mysql-server mysql-server/root_password password ${DB_PASSWORD}\" | debconf-set-selections\necho \"mysql-server mysql-server/root_password_again password ${DB_PASSWORD}\" | debconf-set-selections\n\nmysql_secure_install \"$DB_PASSWORD\"\n\n# Create DB\necho \"CREATE DATABASE ${DB_NAME};\" | mysql -u root -p\"$DB_PASSWORD\"\n\n# create DB user with password\necho \"CREATE USER '$DBUSER'@'localhost' IDENTIFIED BY '$DBUSER_PASSWORD';\" | mysql -u root -p\"$DB_PASSWORD\"\n\necho \"GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DBUSER'@'localhost';\" | mysql -u root -p\"$DB_PASSWORD\"\necho \"FLUSH PRIVILEGES;\" | mysql -u root -p\"$DB_PASSWORD\"\n\n\n###########################################################\n# Install PHP \n###########################################################\napt-get install -y zip unzip php-mbstring php-zip php-gd php-cli php-curl php-intl php-imap php-xml php-xsl php-tokenizer php-sqlite3 php-pgsql php-opcache php-simplexml php-fpm php-bcmath php-ctype php-json php-pdo php-mysql\n\n###########################################################\n# Akaunting\n###########################################################\nmkdir -p /var/www/akaunting \\\n && curl -Lo /tmp/akaunting.zip 'https://akaunting.com/download.php?version=latest&utm_source=linode&utm_campaign=developers' \\\n && unzip /tmp/akaunting.zip -d /var/www/html \\\n && rm -f /tmp/akaunting.zip\n\ncat </var/www/html/.env\nAPP_NAME=Akaunting\nAPP_ENV=production\nAPP_LOCALE=en-GB\nAPP_INSTALLED=false\nAPP_KEY=\nAPP_DEBUG=false\nAPP_SCHEDULE_TIME=\"09:00\"\nAPP_URL=\n\nDB_CONNECTION=mysql\nDB_HOST=localhost\nDB_PORT=3306\nDB_DATABASE=${DB_NAME}\nDB_USERNAME=${DBUSER}\nDB_PASSWORD=${DBUSER_PASSWORD}\nDB_PREFIX=\n\nBROADCAST_DRIVER=log\nCACHE_DRIVER=file\nSESSION_DRIVER=file\nQUEUE_CONNECTION=sync\nLOG_CHANNEL=stack\n\nMAIL_MAILER=mail\nMAIL_HOST=localhost\nMAIL_PORT=2525\nMAIL_USERNAME=null\nMAIL_PASSWORD=null\nMAIL_ENCRYPTION=null\nMAIL_FROM_NAME=null\nMAIL_FROM_ADDRESS=null\n\nFIREWALL_ENABLED=false\nEND\n\ncd /var/www/html && php artisan key:generate\n\n# Install Akaunting\nphp /var/www/html/artisan install --db-host=\"localhost\" --db-name=\"$DB_NAME\" --db-username=\"$DBUSER\" --db-password=\"$DBUSER_PASSWORD\" --company-name=\"$COMPANY_NAME\" --company-email=\"$COMPANY_EMAIL\" --admin-email=\"$ADMIN_EMAIL\" --admin-password=\"$ADMIN_PASSWORD\"\n\n# Fix permissions\nchown -Rf www-data:www-data /var/www/html\nfind /var/www/html/ -type d -exec chmod 755 {} \\;\nfind /var/www/html/ -type f -exec chmod 644 {} \\;\n\n###########################################################\n# Configure NGINX\n###########################################################\nPHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\ncat << END > /etc/nginx/nginx.conf\n# Generic startup file.\nuser www-data;\n\n#usually equal to number of CPUs you have. run command \"grep processor /proc/cpuinfo | wc -l\" to find it\nworker_processes auto;\nworker_cpu_affinity auto;\n\nerror_log /var/log/nginx/error.log;\npid /var/run/nginx.pid;\n\n# Keeps the logs free of messages about not being able to bind().\n#daemon off;\n\nevents {\nworker_connections 1024;\n}\n\nhttp {\n# rewrite_log on;\n\ninclude mime.types;\ndefault_type application/octet-stream;\naccess_log /var/log/nginx/access.log;\nsendfile on;\n# tcp_nopush on;\nkeepalive_timeout 64;\n# tcp_nodelay on;\n# gzip on;\n #php max upload limit cannot be larger than this \nclient_max_body_size 13m;\nindex index.php index.html index.htm;\n\n# Upstream to abstract backend connection(s) for PHP.\nupstream php {\n #this should match value of \"listen\" directive in php-fpm pool\n server unix:/run/php/php$PHP_VERSION-fpm.sock;\n server 127.0.0.1:9000;\n}\n\nserver {\n listen 80 default_server;\n\n server_name _;\n\n root /var/www/html;\n\n add_header X-Frame-Options \"SAMEORIGIN\";\n add_header X-XSS-Protection \"1; mode=block\";\n add_header X-Content-Type-Options \"nosniff\";\n\n index index.html index.htm index.php;\n\n charset utf-8;\n\n location / {\n try_files \\$uri \\$uri/ /index.php?\\$query_string;\n }\n\n # Prevent Direct Access To Protected Files\n location ~ \\.(env|log) {\n deny all;\n }\n\n # Prevent Direct Access To Protected Folders\n location ~ ^/(^app$|bootstrap|config|database|overrides|resources|routes|storage|tests|artisan) {\n deny all;\n }\n\n # Prevent Direct Access To modules/vendor Folders Except Assets\n location ~ ^/(modules|vendor)\\/(.*)\\.((?!ico|gif|jpg|jpeg|png|js\\b|css|less|sass|font|woff|woff2|eot|ttf|svg).)*$ {\n deny all;\n }\n\n error_page 404 /index.php;\n\n # Pass PHP Scripts To FastCGI Server\n location ~ \\.php$ {\n fastcgi_split_path_info ^(.+\\.php)(/.+)\\$;\n fastcgi_pass php;\n fastcgi_index index.php;\n fastcgi_param SCRIPT_FILENAME \\$document_root\\$fastcgi_script_name;\n include fastcgi_params;\n }\n\n location ~ /\\.(?!well-known).* {\n deny all;\n }\n}\n}\nEND\n\n# Remove installation screen\nrm -f /var/www/html/index.html\n\nservice nginx reload\n\n###########################################################\n# Firewall\n###########################################################\napt-get install ufw -y\nufw limit ssh\nufw allow http\nufw allow https\n\nufw --force enable\n\n###########################################################\n# Stackscript cleanup\n###########################################################\nrm /root/StackScript\nrm /root/ssinclude*\necho \"Installation complete!\"","user_defined_fields":[{"name":"company_name","label":"Company Name","example":"My Company"},{"name":"company_email","label":"Company Email","example":"my@company.com"},{"name":"admin_email","label":"Admin Email","example":"my@company.com"},{"name":"admin_password","label":"Admin Password","example":"s3cur39a55w0r0"},{"name":"db_name","label":"MySQL Database Name","example":"akaunting"},{"name":"db_password","label":"MySQL root Password","example":"s3cur39a55w0r0"},{"name":"dbuser","label":"MySQL Username","example":"akaunting"},{"name":"dbuser_password","label":"MySQL User Password","example":"s3cur39a55w0r0"}]},{"id":985374,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Ant Media Server: Enterprise Edition One-Click","description":"Ant Media Enterprise Edition One-Click","ordinal":13,"logo_url":"assets/antmediaserver.svg","images":["linode/ubuntu20.04"],"deployments_total":1375,"deployments_active":63,"is_public":true,"mine":false,"created":"2022-03-08T17:39:39","updated":"2023-12-11T20:31:23","rev_note":"","script":"#!/usr/bin/env bash\n\nset -x\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\nZIP_FILE=\"https://antmedia.io/linode/antmedia_2.5.3.zip\"\nINSTALL_SCRIPT=\"https://raw.githubusercontent.com/ant-media/Scripts/master/install_ant-media-server.sh\"\n\nwget -q --no-check-certificate $ZIP_FILE -O /tmp/antmedia.zip && wget -q --no-check-certificate $INSTALL_SCRIPT -P /tmp/\n\nif [ $? == \"0\" ]; then\n bash /tmp/install_ant-media-server.sh -i /tmp/antmedia.zip\nelse\n logger \"There is a problem in installing the ant media server. Please send the log of this console to contact@antmedia.io\"\n exit 1\nfi","user_defined_fields":[]},{"id":804144,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Ant Media Server: Community Edition One-Click","description":"Ant Media Server One-Click","ordinal":14,"logo_url":"assets/antmediaserver.svg","images":["linode/ubuntu20.04"],"deployments_total":5639,"deployments_active":466,"is_public":true,"mine":false,"created":"2021-04-01T12:50:57","updated":"2023-12-12T15:11:24","rev_note":"","script":"#!/usr/bin/env bash \n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nZIP_FILE=\"https://github.com/ant-media/Ant-Media-Server/releases/download/ams-v2.5.3/ant-media-server-community-2.5.3.zip\"\n\n\nINSTALL_SCRIPT=\"https://raw.githubusercontent.com/ant-media/Scripts/master/install_ant-media-server.sh\"\n\nwget -q --no-check-certificate $ZIP_FILE -O /tmp/antmedia.zip && wget -q --no-check-certificate $INSTALL_SCRIPT -P /tmp/\n\nif [ $? == \"0\" ]; then\n bash /tmp/install_ant-media-server.sh -i /tmp/antmedia.zip\nelse\n logger \"There is a problem in installing the ant media server. Please send the log of this console to contact@antmedia.io\"\n exit 1\nfi","user_defined_fields":[]},{"id":1102900,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Apache Airflow One-Click","description":"Apache Airflow One-Click App","ordinal":15,"logo_url":"assets/apacheairflow.svg","images":["linode/ubuntu20.04"],"deployments_total":127,"deployments_active":4,"is_public":true,"mine":false,"created":"2022-12-20T17:32:08","updated":"2023-11-28T13:38:46","rev_note":"","script":"#!/bin/bash\n#\n# \n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n## Enable logging\n\nset -x\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Register default rDNS \nexport DEFAULT_RDNS=$(dnsdomainname -A | awk '{print $1}')\n\n#set absolute domain if any, otherwise use DEFAULT_RDNS\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DEFAULT_RDNS\"\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\ncreate_a_record $SUBDOMAIN $IP $DOMAIN\n\n# install depends\nexport DEBIAN_FRONTEND=noninteractive\nsudo apt update\n#sudo apt -y upgrade\nsudo apt install -y python3-pip\nsudo apt install -y build-essential libssl-dev libffi-dev python3-dev\nsudo apt install -y python3-venv # One of the Airflow examples requires virtual environments\n\nexport AIRFLOW_HOME=~/airflow\n\n# Install Airflow using the constraints file\nAIRFLOW_VERSION=2.4.1\nPYTHON_VERSION=\"$(python3 --version | cut -d \" \" -f 2 | cut -d \".\" -f 1-2)\"\n# For example: 3.7\nCONSTRAINT_URL=\"https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt\"\n# For example: https://raw.githubusercontent.com/apache/airflow/constraints-2.4.1/constraints-3.7.txt\npip install \"apache-airflow==${AIRFLOW_VERSION}\" --constraint \"${CONSTRAINT_URL}\"\n\n# The Standalone command will initialise the database, make a user,\n# and start all components for you.\nairflow standalone &\n\n###\n# \n# systemd unit file and per component settings go here\n# \n### \n\n\n## install nginx reverse-proxy \napt install nginx -y \n\n#configure nginx reverse proxy\nrm /etc/nginx/sites-enabled/default\ntouch /etc/nginx/sites-available/reverse-proxy.conf\ncat < /etc/nginx/sites-available/reverse-proxy.conf\nserver {\n listen 80;\n listen [::]:80;\n server_name ${DEFAULT_RDNS};\n\n access_log /var/log/nginx/reverse-access.log;\n error_log /var/log/nginx/reverse-error.log;\n\n location / {\n proxy_pass http://localhost:8080;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forward-For \\$proxy_add_x_forwarded_for;\n }\n}\nEND\nln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/reverse-proxy.conf\n\n#enable and start nginx\nsystemctl enable nginx\nsystemctl restart nginx \n\n## UFW rules \nufw allow http \nufw allow https \nsystemctl enable ufw\n\nsleep 60 \n\n## install SSL certs. required \npip install pyOpenSSL --upgrade\napt install python3-certbot-nginx -y \ncertbot run --non-interactive --nginx --agree-tos --redirect -d ${ABS_DOMAIN} -m ${SOA_EMAIL_ADDRESS} -w /var/www/html/\n\n## write some login details\nexport ADMIN_PASS=$(cat /root/airflow/standalone_admin_password.txt)\ncat < /etc/motd \nThe installation of Apache Airflow is now complete, and the application is running in standalone mode.\n#\nYou can log into the Airflow GUI at ${ABS_DOMAIN}\nWith the credentials: \nUsername: admin\nPassword: ${ADMIN_PASS}\n#\nStandalone mode is not recommended for production.\nEND\n\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode.","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":1160820,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Appwrite One-Click","description":"Appwrite One-Click ","ordinal":16,"logo_url":"assets/appwrite.svg","images":["linode/ubuntu22.04"],"deployments_total":177,"deployments_active":11,"is_public":true,"mine":false,"created":"2023-04-21T13:09:13","updated":"2023-12-10T01:42:24","rev_note":"","script":"#!/bin/bash\n### linode \n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# install docker\ncurl -fsSL https://get.docker.com -o get-docker.sh\nbash ./get-docker.sh\n\n# install haveged\nsudo apt-get install -y haveged\n\n# Install Appwrite\n# Grab latest version\nappversion=$(curl -s https://api.github.com/repos/appwrite/appwrite/releases/latest | grep -oP '\"tag_name\": \"\\K.*?(?=\")')\n\ndocker run --rm \\\n --volume /var/run/docker.sock:/var/run/docker.sock \\\n --volume \"$(pwd)\"/appwrite:/usr/src/code/appwrite:rw \\\n appwrite/appwrite:$appversion sh -c \"install --httpPort=80 --httpsPort=443 --interactive=N\"\n\necho \"Installation complete!\"","user_defined_fields":[]},{"id":401699,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Ark One-Click","description":"Ark - Latest One-Click","ordinal":17,"logo_url":"assets/Ark@1x.svg","images":["linode/debian11"],"deployments_total":1145,"deployments_active":3,"is_public":true,"mine":false,"created":"2019-03-08T21:05:54","updated":"2023-12-05T18:43:30","rev_note":"Remove SSH Pubkey UDF","script":"#!/bin/bash\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\nGAMESERVER=\"arkserver\"\n\nset_hostname\napt_setup_update\n\n\n# ARK specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix \\\ncurl wget file bzip2 gzip unzip bsdmainutils \\\npython util-linux ca-certificates binutils bc \\\njq tmux lib32gcc-s1 libstdc++6 libstdc++6:i386 \n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install ARK\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\n#Game Config Options\n\nsed -i s/XPMultiplier=.*/XPMultiplier=\"$XPMULTIPLIER\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerPassword=.*/ServerPassword=\"$SERVERPASSWORD\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerHardcore=.*/ServerHardcore=\"$SERVERPASSWORD\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerPVE=.*/ServerPVE=\"$SERVERPVE\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/Message=.*/Message=\"$MOTD\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/SessionName=.*/SessionName=\"$SESSIONNAME\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\nsed -i s/ServerAdminPassword=.*/ServerAdminPassword=\"\\\"$RCONPASSWORD\\\"\"/ /home/arkserver/serverfiles/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini\n\n\n# Start the service and setup firewall\nufw_install\nufw allow 27015/udp\nufw allow 7777:7778/udp\nufw allow 27020/tcp\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup","user_defined_fields":[{"name":"rconpassword","label":"RCON password"},{"name":"sessionname","label":"Server Name","default":"Ark Server"},{"name":"motd","label":"Message of the Day","default":"Powered by Linode!"},{"name":"serverpassword","label":"Server Password","default":""},{"name":"hardcore","label":"Hardcore Mode Enabled","oneof":"True,False","default":"False"},{"name":"xpmultiplier","label":"XP Multiplier","oneof":"1,1.5,2,5,10,20","default":"2"},{"name":"serverpve","label":"Server PvE","oneof":"True,False","default":"False"}]},{"id":662118,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Azuracast One-Click","description":"AzuraCast One-Click","ordinal":18,"logo_url":"assets/azuracast.svg","images":["linode/debian10","linode/ubuntu20.04"],"deployments_total":2704,"deployments_active":191,"is_public":true,"mine":false,"created":"2020-08-12T15:50:09","updated":"2023-12-12T06:14:05","rev_note":"","script":"#!/bin/bash\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, apt configuration and update/upgrade\nset_hostname\napt_setup_update\n\n# Install GIT\napt-get update && apt-get install -q -y git\n# Cloning AzuraCast and install\nmkdir -p /var/azuracast\ncd /var/azuracast\ncurl -fsSL https://raw.githubusercontent.com/AzuraCast/AzuraCast/main/docker.sh > docker.sh\nchmod a+x docker.sh\nyes 'Y' | ./docker.sh setup-release\nyes '' | ./docker.sh install\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[]},{"id":913277,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"BeEF One-Click","description":"BeEF One-Click","ordinal":19,"logo_url":"assets/beef.svg","images":["linode/ubuntu22.04"],"deployments_total":30530,"deployments_active":1166,"is_public":true,"mine":false,"created":"2021-09-30T18:28:58","updated":"2023-12-12T15:52:32","rev_note":"","script":"#!/bin/bash\n#\n# Script to install BEEF on Linode\n# \n# \n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \nbeef_config=\"/home/beef/config.yaml\"\nkey=\"privkey.pem\"\ncert=\"fullchain.pem\"\n# System Update\napt_setup_update\n# UFW\nufw allow 80\nufw allow 443\nufw allow 3000\nfunction configure_nginx {\n apt install git nginx ruby-dev -y\n # NGINX\n mkdir -p /var/www/certs/.well-known\n chown -R www-data:www-data /var/www/certs/\n cat < /etc/nginx/sites-available/$FQDN\nserver {\n listen 80;\n listen [::]:80;\n server_name $FQDN;\n root /var/www/certs;\n location / {\n try_files \\$uri \\$uri/ =404;\n }\n# allow .well-known\n location ^~ /.well-known {\n allow all;\n auth_basic off;\n alias /var/www/certs/.well-known;\n }\n}\nEOF\n ln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/$FQDN\n unlink /etc/nginx/sites-enabled/default\n systemctl restart nginx\n}\nfunction configure_ssl {\n apt install certbot python3-certbot-nginx -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\nfunction create_beef_user {\n function create_beef {\n groupadd --system beef\n useradd -s /sbin/nologin --system -g beef beef\n }\n grep beef /etc/passwd\n if [ $? -eq 1 ];then\n create_beef\n else\n echo \"[INFO] beef already on the system. Deleting user\"\n deluser --remove-home beef\n create_beef\n fi\n}\nfunction configure_beef {\n git clone https://github.com/beefproject/beef.git /home/beef\n chown -R beef: /home/beef\n cd /home/beef\n cp /etc/letsencrypt/live/$FQDN/$key .\n cp /etc/letsencrypt/live/$FQDN/$cert .\n # get line number to replace\n get_https_enable=$(grep -n -C 10 \"key:\" $beef_config | grep -v \"#\" | grep \"https:\" -A 5 | grep \"enable:\" | awk -F \"-\" {'print $1'})\n get_https_public_enabled=$(grep -n -C 10 \"key:\" $beef_config | grep -v \"#\" | grep \"https:\" -A 5 | grep \"public_enabled:\" | awk -F \"-\" {'print $1'})\n # replacing line numebr\n sed -i \"\"$get_https_enable\"s/enable: false/enable: true/\" $beef_config\n sed -i \"\"$get_https_public_enabled\"s/public_enabled: false/public_enabled: true/\" $beef_config\n sed -i \"/key:/c\\ key: \\\"$key\\\"\" $beef_config\n sed -i \"/cert:/c\\ cert: \\\"$cert\\\"\" $beef_config\n # creds\n #sed -i \"/user:/c\\ user: \\\"beef\\\"\" $beef_config\n sed -i \"/passwd:/c\\ passwd: \\\"$BEEFPASSWORD\\\"\" $beef_config\n # install local copy of beef\n # install deps\n apt install curl git build-essential openssl libreadline6-dev zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt1-dev autoconf libc6-dev libncurses5-dev automake libtool bison nodejs libcurl4-openssl-dev ruby-dev -y\n su - -s /bin/bash beef\n bundle3.0 config set --local path /home/beef/.gem\n bundle3.0 install\n gem install --user-install xmlrpc\n \n}\nfunction beef_startup {\n cat < /home/beef/start_beef\n#!/bin/bash\nfunction start_beef {\n cd /home/beef\n echo no | ./beef\n}\nstart_beef\nEOF\n chown -R beef:beef /home/beef\n chmod +x /home/beef/start_beef\n}\n \nfunction beef_job {\n cat < /etc/systemd/system/beef.service\n[Unit]\nDescription=Browser Exploitation Framework\nWants=network-online.target\nAfter=network-online.target\n[Service]\nUser=beef\nGroup=beef\nExecStart=/home/beef/start_beef\n[Install]\nWantedBy=default.target\nEOF\n systemctl daemon-reload\n systemctl start beef\n systemctl enable beef\n}\nfunction ssl_renew_cron {\n cat </root/certbot-beef-renewal.sh\n#!/bin/bash\n#\n# Script to handle Certbot renewal & BeEf\n# Debug\n# set -xo pipefail\nexport BEEF_FULL=/home/beef/fullchain.pem\nexport BEEF_PRIVKEY=/home/beef/privkey.pem\nexport FULLCHAIN=/etc/letsencrypt/live/$FQDN/fullchain.pem\nexport PRIVKEY=/etc/letsencrypt/live/$FQDN/privkey.pem\ncertbot renew\ncat \\$FULLCHAIN > \\$BEEF_FULL\ncat \\$PRIVKEY > \\$BEEF_PRIVKEY\nservice beef reload\nEND\n chmod +x /root/certbot-beef-renewal.sh\n# Setup Cron\n crontab -l > cron\n echo \"* 1 * * 1 bash /root/certbot-beef-renewal.sh\" >> cron\n crontab cron\n rm cron\n}\nfunction install_complete {\n cat < /root/beef.info\n##############################\n# BEEF INSTALLATION COMPLETE #\n##############################\nEndpoint: https://$FQDN:3000/ui/panel\nCredentials can be found here:\n/home/beef/config.yaml\nHappy hunting!\nEOF\n}\nfunction main {\n create_beef_user\n configure_nginx\n configure_ssl\n configure_beef\n beef_startup\n beef_job\n ssl_renew_cron\n install_complete\n}\nmain\n# Clean up\nstackscript_cleanup\ncat /root/beef.info","user_defined_fields":[{"name":"beefpassword","label":"BEEF Password"},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode. The username cannot contain any spaces or capitol letters. For this application the username 'beef' is reserved for the application, so please choose an alternative username for this deployment.","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":923034,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"BitNinja One-Click","description":"BitNinja One-Click","ordinal":20,"logo_url":"assets/bitninja.svg","images":["linode/centos7","linode/debian10","linode/ubuntu20.04","linode/debian11"],"deployments_total":35,"deployments_active":0,"is_public":true,"mine":false,"created":"2021-10-18T01:03:02","updated":"2023-11-28T09:18:11","rev_note":"","script":"#!bin/bash\n\n# \n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nwget -qO- https://get.bitninja.io/install.sh | /bin/bash -s - --license_key=\"$license_key\" -y","user_defined_fields":[{"name":"license_key","label":"License Key"}]},{"id":1037036,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Budibase One-Click","description":"Budibase One Click App","ordinal":21,"logo_url":"assets/budibase.svg","images":["linode/debian11","linode/ubuntu22.04"],"deployments_total":438,"deployments_active":26,"is_public":true,"mine":false,"created":"2022-08-02T18:42:41","updated":"2023-12-12T01:21:50","rev_note":"","script":"#!/bin/bash\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install the dependencies & add Docker to the APT repository\napt install -y apt-transport-https ca-certificates curl software-properties-common gnupg2 pwgen ufw\ncurl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable\"\n\n# Update & install Docker-CE\napt_setup_update\napt install -y docker.io\n\n# Check to ensure Docker is running and installed correctly\nsystemctl status docker\ndocker -v\n\n# Install Docker Compose\ncurl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose\nchmod +x /usr/local/bin/docker-compose\ndocker-compose --version\n\necho \"Creating passwords for /opt/budibase/.env\"\nVAR_JWT_SECRET=$(pwgen 16)\nVAR_MINIO_ACCESS_KEY=$(pwgen 16)\nVAR_MINIO_SECRET_KEY=$(pwgen 16)\nVAR_COUCH_DB_PASSWORD=$(pwgen 16)\nVAR_REDIS_PASSWORD=$(pwgen 16)\nVAR_INTERNAL_API_KEY=$(pwgen 16)\nIP=`hostname -I | awk '{print$1}'`\n\nmkdir -p /opt/budibase\ncd /opt/budibase\necho \"Fetch budibase docker compose file\"\ncurl -L https://raw.githubusercontent.com/Budibase/budibase/master/hosting/docker-compose.yaml -o /opt/budibase/docker-compose.yml\necho \"Fetch budibase .env template\"\ncurl -L https://raw.githubusercontent.com/Budibase/budibase/master/hosting/.env -o /opt/budibase/.env\necho \"Set passwords in /opt/budibase/.env\"\nsed -i \"s/JWT_SECRET=testsecret/JWT_SECRET=$VAR_JWT_SECRET/\" /opt/budibase/.env\nsed -i \"s/MINIO_ACCESS_KEY=budibase/MINIO_ACCESS_KEY=$VAR_MINIO_ACCESS_KEY/\" /opt/budibase/.env\nsed -i \"s/MINIO_SECRET_KEY=budibase/MINIO_SECRET_KEY=$VAR_MINIO_SECRET_KEY/\" /opt/budibase/.env\nsed -i \"s/COUCH_DB_PASSWORD=budibase/COUCH_DB_PASSWORD=$VAR_COUCH_DB_PASSWORD/\" /opt/budibase/.env\nsed -i \"s/REDIS_PASSWORD=budibase/REDIS_PASSWORD=$VAR_REDIS_PASSWORD/\" /opt/budibase/.env\nsed -i \"s/INTERNAL_API_KEY=budibase/INTERNAL_API_KEY=$VAR_INTERNAL_API_KEY/\" /opt/budibase/.env\nsed -i \"s/MAIN_PORT=10000/MAIN_PORT=$BBPORT/\" /opt/budibase/.env\ndocker-compose up -d\n\ncat </etc/profile.d/budibase_welcome.sh\n#!/bin/sh\n#\nIP=$(hostname -I | awk '{print$1}')\necho \"\n********************************************************************************\nWelcome to Budibase!\nTo help keep this server secure, the UFW firewall is enabled.\nAll ports are BLOCKED except 22 (SSH) and the Web UI port $BBPORT.\n********************************************************************************\n # Budibase UI: http://$IP:$BBPORT/\n # Website: https://budibase.com\n # Documentation: https://docs.budibase.com\n # Github: https://github.com/Budibase/budibase\n # Community Support: https://github.com/Budibase/budibase/discussions\n # Restart Budibase: cd /opt/budibase; docker-compose down; docker-compose up -d\n # Budibase config: /etc/budibase/.env\n\"\nEND\nchmod +x /etc/profile.d/budibase_welcome.sh\n# Enable UFW and add some rules to it\nufw enable\nufw limit ssh/tcp comment 'Rate limit the SSH port'\nufw allow $BBPORT/tcp comment \"TCP Listen port for Budibase\"\nufw --force enable\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"BBPORT","label":"Budibase Port","example":"Default: 80","default":"80"}]},{"id":869155,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Chevereto One-Click","description":"Chevereto One-Click","ordinal":22,"logo_url":"assets/chevereto.svg","images":["linode/ubuntu20.04"],"deployments_total":236,"deployments_active":6,"is_public":true,"mine":false,"created":"2021-07-20T19:07:56","updated":"2023-10-30T19:52:12","rev_note":"","script":"#!/usr/bin/env bash\n# https://github.com/chevereto/linode-marketplace\n\nset -e\n\nCHEVERETO_INSTALLER_TAG=\"3.1.0\"\nWORKING_DIR=\"/var/www/html\"\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n## 03-force-ssh-logout.sh\ncat >>/etc/ssh/sshd_config </dev/null\napt install -y apache2 libapache2-mod-php\napt install -y mysql-server\napt install -y php\napt install -y php-{common,cli,curl,fileinfo,gd,imagick,intl,json,mbstring,mysql,opcache,pdo,pdo-mysql,xml,xmlrpc,zip}\napt install -y python3-certbot-apache software-properties-common unzip\n\n# 01-fs.sh\ncat >/etc/apache2/sites-available/000-default.conf <\n \n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n \n ServerAdmin webmaster@localhost\n DocumentRoot /var/www/html\n ErrorLog \\${APACHE_LOG_DIR}/error.log\n CustomLog \\${APACHE_LOG_DIR}/access.log combined\n\nEOM\n\ncat >/etc/update-motd.d/99-one-click < certbot --apache -d example.com -d www.example.com\nIMPORTANT:\n * After connecting to the server for the first time, immediately install\n Chevereto at http://\\$myip/installer.php\n * Secure your database by running:\n > mysql_secure_installation\n * Setup email delivery at http://\\$myip/dashboard/settings/email\nFor help and more information visit https://chevereto.com\n********************************************************************************\nTo delete this message of the day: rm -rf \\$(readlink -f \\${0})\nEOF\nEOM\nchmod +x /etc/update-motd.d/99-one-click\n\ncat >/etc/cron.d/chevereto </etc/php/7.4/apache2/conf.d/chevereto.ini <>/var/log/per-instance.log\n\nMYSQL_ROOT_PASS=$(openssl rand -hex 16)\nDEBIAN_SYS_MAINT_MYSQL_PASS=$(openssl rand -hex 16)\n\nCHEVERETO_DB_HOST=localhost\nCHEVERETO_DB_PORT=3306\nCHEVERETO_DB_NAME=chevereto\nCHEVERETO_DB_USER=chevereto\nCHEVERETO_DB_PASS=$(openssl rand -hex 16)\n\ncat >/root/.mysql_password <>/etc/apache2/envvars </etc/mysql/debian.cnf <>/var/log/per-instance.log\n\necho \"[OK] Chevereto Installer $CHEVERETO_INSTALLER_TAG provisioned!\"","user_defined_fields":[]},{"id":869158,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"ClusterControl One-Click","description":"ClusterControl One-Click","ordinal":23,"logo_url":"assets/clustercontrol.svg","images":["linode/ubuntu20.04"],"deployments_total":174,"deployments_active":4,"is_public":true,"mine":false,"created":"2021-07-20T19:13:44","updated":"2023-12-09T22:12:37","rev_note":"","script":"#!/usr/bin/env bash\n\n### UDF Variables\n\n## Severalnines settings\n#\n#\n\n## Domain settings\n#\n#\n#\n#\n\n## Let's Encrypt SSL\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n# System Update\nsystem_update\n\nworkdir=/tmp\nIP=`hostname -I | awk '{print$1}'`\n# if command -v dig &>/dev/null; then\n# echo -e \"\\nDetermining network interfaces.\" \n# ext_ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)\n# [[ ! -z $ext_ip ]] && IP=${ext_ip}\n# fi\nlog_progress() {\n\n echo \"$1\" >> /root/cc_install.log\n}\n\ninstall_cc() {\n export HOME=/root\n export USER=root\n wget --no-check-certificate https://severalnines.com/downloads/cmon/install-cc\n chmod +x install-cc\n echo \"mysql cmon password = $CMONUSER_PASSWORD\" >> /root/.cc_passwords\n echo \"mysql root password = $DBROOT_PASSWORD\" >> /root/.cc_passwords\n SEND_DIAGNOSTICS=0 S9S_CMON_PASSWORD=$CMONUSER_PASSWORD S9S_ROOT_PASSWORD=$DBROOT_PASSWORD INNODB_BUFFER_POOL_SIZE=256 ./install-cc\n}\n\nfirstboot() {\n hostnamectl set-hostname clustercontrol\n\n ssh-keygen -b 2048 -t rsa -f /root/.ssh/id_rsa -q -N \"\"\n ssh-keygen -y -f /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub\n SSH_KEY=$(cat /root/.ssh/id_rsa.pub)\n\n cat < /etc/update-motd.d/99-cc-motd \n#!/bin/sh\necho \"###\"\necho \"\"\necho \"Welcome to Severalnines Database Monitoring and Management Application - ClusterControl\"\necho \"Open your web browser to http://${IP}/clustercontrol to access ClusterControl's web application\"\necho \"\"\necho \"The public SSH key (root) is:\"\necho \"$SSH_KEY\"\necho \"\"\necho \"###\"\nEND\n\n chmod +x /etc/update-motd.d/99-cc-motd\n}\n\nenable_fw() {\n ufw default deny incoming\n ufw default allow outgoing\n ufw allow ssh\n ufw allow http\n ufw allow https\n ufw allow 9999\n ufw allow 9501\n}\n\ncleanup() {\n rm -rf /tmp/* /var/tmp/* /root/scripts\n history -c\n cat /dev/null > /root/.bash_history\n unset HISTFILE\n\n apt-get -y autoremove\n apt-get -y autoclean\n\n cat /dev/null > /var/log/lastlog; cat /dev/null > /var/log/wtmp; cat /dev/null > /var/log/auth.log\n\n ufw enable\n ufw status\n\n touch /.cc-provisioned\n}\n\nlog_progress \"** Installing ClusterControl, this could take several minutes. Please wait ...\"\ninstall_cc\nlog_progress \"** Setting motd ...\"\nfirstboot\nlog_progress \"** Enabling firewall ...\"\nenable_fw\nif [[ \"$SSL\" == \"Yes\" ]]; then\n log_progress \"** Enabling Let's Encrypt SSL ...\"\n python --version | grep -q 3.\n [[ $? -eq 0 ]] && PYTHON3=1\n if [[ -n $PYTHON3 ]]; then\n apt install -y certbot python3-certbot-apache\n else\n apt install -y certbot python-certbot-apache\n fi\n\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\nfi\ncleanup\n\n# Clean up\nlog_progress \"** Stackscript cleanup please wait ...\"\nstackscript_cleanup\n\nlog_progress \"** Installation successful...\"\n/etc/update-motd.d/99-cc-motd | tee -a /root/cc_install.log\n\nsystemctl restart sshd","user_defined_fields":[{"name":"dbroot_password","label":"MySQL Root Password"},{"name":"cmonuser_password","label":"CMON user password"},{"name":"token_password","label":"Your Linode API token. This is required in order to create DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"soa_email_address","label":"E-Mail Address","example":"Your email address"},{"name":"ssl","label":"Would you like to use a free Let's Encrypt SSL certificate? (Uses the Linode's default rDNS if no domain is specified above)","oneof":"Yes,No","default":"Yes"}]},{"id":401700,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"CS:GO One-Click","description":"CS:GO - Latest One-Click","ordinal":24,"logo_url":"assets/CSGO2.svg","images":["linode/debian11","linode/ubuntu22.04"],"deployments_total":2142,"deployments_active":6,"is_public":true,"mine":false,"created":"2019-03-08T21:06:26","updated":"2023-11-02T20:39:58","rev_note":"Remove SSH Pubkey UDF","script":"#!/bin/bash\n#\n\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\nGAMESERVER=\"csgoserver\"\n\n### UDF to config\n\n#Autoteambalance\nif [[ \"$AUTOTEAMBALANCE\" = \"Enabled\" ]]; then\n AUTOTEAMBALANCE=1\nelif [[ \"$AUTOTEAMBALANCE\" = \"Disabled\" ]]; then\n AUTOTEAMBALANCE=0\nfi\n\n#Buyanywhere\nif [[ \"$BUYANYWHERE\" = \"Enabled\" ]]; then\n BUYANYWHERE=1\nelif [[ \"$BUYANYWHERE\" = \"Disabled\" ]]; then\n BUYANYWHERE=0\nelif [[ \"$BUYANYWHERE\" = \"Terrorists Only\" ]]; then\n BUYANYWHERE=2\nelif [[ \"$BUYANYWHERE\" = \"Counter-Terrorists Only\" ]]; then\n BUYANYWHERE=3\nfi\n\n#friendlyfire\n\nif [[ \"$FRIENDLYFIRE\" = \"Enabled\" ]]; then\n FRIENDLYFIRE=1\nelif [[ \"$FRIENDLYFIRE\" = \"Disabled\" ]]; then\n FRIENDLYFIRE=0\nfi\n\nset_hostname\napt_setup_update\n\n\n# CSGO specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix \\\ncurl wget file bzip2 gzip unzip bsdmainutils \\\npython util-linux ca-certificates binutils bc \\\njq tmux lib32gcc1 libstdc++6 libstdc++6:i386\n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install CSGO\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\n#Game Config Options\n\n> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\n\ncat <> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\nsv_contact \"\"\nsv_lan 0\nlog on\nsv_logbans 1\nsv_logecho 1\nsv_logfile 1\nsv_log_onefile 0\nsv_hibernate_when_empty 1\nsv_hibernate_ms 5\nhost_name_store 1\nhost_info_show 1\nhost_players_show 2\nexec banned_user.cfg\nexec banned_ip.cfg\nwriteid\nwriteip\nEND\n\necho \"mp_autoteambalance $AUTOTEAMBALANCE\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"hostname $SERVERNAME\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"mp_roundtime $ROUNDTIME\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"rcon_password \\\"$RCONPASSWORD\\\"\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"sv_password \\\"$SVPASSWORD\\\"\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\nsed -i s/mp_buy_anywhere.*/mp_buy_anywhere\\ \"$BUYANYWHERE\"/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/mp_maxrounds.*/mp_maxrounds\\ \"$MAXROUNDS\"/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/mp_friendlyfire.*/mp_friendlyfire\\ \"$FRIENDLYFIRE\"/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\necho \"$MOTD\" > /home/csgoserver/serverfiles/csgo/motd.txt\n\n\nif [[ \"$FRIENDLYFIRE\" = \"1\" ]]; then\nsed -i s/ff_damage_reduction_bullets.*/ff_damage_reduction_bullets\\ 0\\.85/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/ff_damage_reduction_gernade.*/ff_damage_reduction_gernade\\ 0\\.33/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/ff_damage_reduction_gernade_self.*/ff_damage_reduction_gernade_self\\ 0\\.4/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\nsed -i s/ff_damage_reduction_other.*/ff_damage_reduction_other\\ 1/ /home/csgoserver/serverfiles/csgo/cfg/gamemode_casual.cfg\necho \"sv_kick_ban_duration 0\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\necho \"mp_disable_autokick 0\" >> /home/csgoserver/serverfiles/csgo/cfg/csgoserver.cfg\nfi\n\n# Start the service and setup firewall\nufw_install\nufw allow 27015\nufw allow 27020/udp\nufw allow 27005/udp\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup","user_defined_fields":[{"name":"gslt","label":"Game Server Login Token","example":"Steam gameserver token. Needed to list as public server."},{"name":"motd","label":"Message of the Day","default":"Powered by Linode!"},{"name":"servername","label":"Server Name","default":"Linode CS:GO Server"},{"name":"rconpassword","label":"RCON password"},{"name":"svpassword","label":"CSGO server password","default":""},{"name":"autoteambalance","label":"Team Balance Enabled","oneof":"Enabled,Disabled","default":"Enabled"},{"name":"roundtime","label":"Round Time Limit","oneof":"5,10,15,20,60","default":"5"},{"name":"maxrounds","label":"Maximum Rounds","oneof":"1,5,10,15,20","default":"10"},{"name":"buyanywhere","label":"Buy Anywhere ","oneof":"Disabled,Enabled,Counter-Terrorists Only, Terrorists Only","default":"Disabled"},{"name":"friendlyfire","label":"Friendly Fire Enabled","oneof":"Enabled,Disabled","default":"Disabled"}]},{"id":688891,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Discourse One-Click","description":"Discourse One-Click","ordinal":25,"logo_url":"assets/discourse.svg","images":["linode/ubuntu20.04"],"deployments_total":1214,"deployments_active":59,"is_public":true,"mine":false,"created":"2020-11-17T20:55:26","updated":"2023-12-12T07:15:54","rev_note":"","script":"#!/bin/bash\n\n## Discourse Settings\n\n#\n#\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n# This also sets some useful variables, like $IP and $FQDN\nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -xo pipefail\n\n#Install dependencies needed for Discourse\napt install git apt-transport-https ca-certificates curl software-properties-common net-tools -y\n\n#Clone Discourse Docker repo for install and management\ngit clone https://github.com/discourse/discourse_docker.git /var/discourse\n#UFW Firewall Rules\nufw allow http\nufw allow https\nufw allow 25\nufw allow 465\nufw allow 587\nufw enable <\n#\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Python & Django\napt-get install -y python3 python3-pip\npip3 install Django\n\n# Create & Setup Django APP\nmkdir /var/www/\ncd /var/www/\ndjango-admin startproject DjangoApp\ncd DjangoApp\npython3 manage.py migrate\necho \"from django.contrib.auth.models import User; User.objects.create_superuser('$DJANGOUSER', '$DJANGOUSEREMAIL', '$DJANGOUSERPASSWORD')\" | python3 manage.py shell\nsed -i \"s/ALLOWED_HOSTS = \\[\\]/ALLOWED_HOSTS = \\['$IP'\\]/g\" DjangoApp/settings.py\npython3 manage.py runserver 0.0.0.0:8000 &\n\n# Start Django app on reboot\ncrontab -l | { cat; echo \"@reboot cd /var/www/DjangoApp && python3 manage.py runserver 0.0.0.0:8000 &\"; } | crontab -\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"djangouser","label":"Django USER","example":"user1"},{"name":"djangouserpassword","label":"Django Password","example":"s3cure_p4ssw0rd"},{"name":"djangouseremail","label":"Django USER email","example":"user@email.tld"}]},{"id":607433,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Docker One-Click","description":"Docker One Click App","ordinal":27,"logo_url":"assets/docker.svg","images":["linode/ubuntu22.04"],"deployments_total":36066,"deployments_active":1839,"is_public":true,"mine":false,"created":"2019-10-31T20:14:04","updated":"2023-12-12T15:57:24","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Docker Settings\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-docker\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n else echo \"No email entered\";\n fi\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"SOA Email","example":"user@domain.tld","default":""}]},{"id":401698,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Drupal One-Click","description":"Drupal One-Click","ordinal":28,"logo_url":"assets/Drupal.svg","images":["linode/ubuntu22.04"],"deployments_total":1850,"deployments_active":79,"is_public":true,"mine":false,"created":"2019-03-08T21:04:47","updated":"2023-12-11T03:05:01","rev_note":"","script":"#!/usr/bin/env bash\n## Drupal Settings\n# \n# \n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Set hostname, apt configuration and update/upgrade\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Install/configure UFW\nufw allow http\nufw allow https\n\n# Install/configure MySQL\napt-get install mariadb-server -y\nsystemctl start mariadb\nsystemctl enable mariadb\nmysql_root_preinstall\nrun_mysql_secure_installation\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"CREATE DATABASE drupaldb\"\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"GRANT ALL ON drupaldb.* TO 'drupal'@'localhost' IDENTIFIED BY '$DB_PASSWORD'\";\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"FLUSH PRIVILEGES\";\n\n# Install & Configure Apache\napt-get install -y apache2\ntouch /var/log/apache2/drupal-error_log /var/log/apache2/drupal-access_log\ncp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/drupal.conf\ncat < /etc/apache2/sites-available/drupal.conf\n\n DocumentRoot /var/www/drupal\n ServerName $FQDN\n ServerAlias www.$FQDN\n \n Options FollowSymLinks\n AllowOverride All\n Order allow,deny\n allow from all\n RewriteEngine on\n RewriteBase /\n RewriteCond %{REQUEST_FILENAME} !-f\n RewriteCond %{REQUEST_FILENAME} !-d\n RewriteCond %{REQUEST_URI} !=/favicon.ico\n RewriteRule ^ index.php [L]\n\n ErrorLog /var/log/apache2/drupal-error_log\n CustomLog /var/log/apache2/drupal-access_log common\n\nEND\na2enmod rewrite\na2dissite 000-default.conf\na2ensite drupal.conf\nsed -ie \"s/KeepAlive Off/KeepAlive On/g\" /etc/apache2/apache2.conf\nsystemctl restart apache2\nsystemctl enable apache2\n\n# Install PHP 8.1\napt-get install php libapache2-mod-php php-mysql php-curl php-cgi php-gd php-mbstring php-xml php-xmlrpc -y\nPHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\ncat < /etc/php/$PHP_VERSION/apache2/php.ini\nerror_reporting = E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR\nerror_log = /var/log/php/error.log\nmax_input_time = 30\nEND\nmkdir /var/log/php\nchown www-data /var/log/php\n\n# Install Drupal\nrm -r /var/www/html\ncd ~; wget -4 https://www.drupal.org/download-latest/tar.gz\ntar -xf tar.gz -C /var/www/ && mv /var/www/drupal* /var/www/drupal\nrm tar.gz\nmkdir /var/www/drupal/sites/default/files\nchmod a+w /var/www/drupal/sites/default/files\ncp /var/www/drupal/sites/default/default.settings.php /var/www/drupal/sites/default/settings.php\nchmod a+w /var/www/drupal/sites/default/settings.php\ncat <> /var/www/drupal/sites/default/settings.php\n\\$settings['trusted_host_patterns'] = [\n '^$FQDN\\$',\n];\nEND\n\n# Cleanup\nsystemctl restart apache2\nsystemctl restart mysql\n\n# SSL\napt install certbot python3-certbot-apache -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"E-Mail Address","example":"Your email address"},{"name":"dbroot_password","label":"MySQL root Password","example":"an0th3r_s3cure_p4ssw0rd"},{"name":"db_password","label":"Database Password","example":"an0th3r_s3cure_p4ssw0rd"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your Drupal server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":1008125,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Easypanel One-Click","description":"Easypanel One-Click","ordinal":29,"logo_url":"assets/easypanel.svg","images":["linode/ubuntu22.04"],"deployments_total":1424,"deployments_active":79,"is_public":true,"mine":false,"created":"2022-05-18T16:43:00","updated":"2023-12-11T07:40:49","rev_note":"","script":"#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# install docker\ncurl -fsSL https://get.docker.com -o get-docker.sh\nsh get-docker.sh\n\n# setup easypanel\ndocker run --rm \\\n -v /etc/easypanel:/etc/easypanel \\\n -v /var/run/docker.sock:/var/run/docker.sock:ro \\\n easypanel/easypanel setup","user_defined_fields":[]},{"id":691620,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"FileCloud One-Click","description":"FileCloud One-Click","ordinal":30,"logo_url":"assets/filecloud.svg","images":["linode/ubuntu20.04"],"deployments_total":790,"deployments_active":14,"is_public":true,"mine":false,"created":"2020-11-30T21:16:19","updated":"2023-12-12T10:31:20","rev_note":"","script":"#!/bin/bash \n\n## Domain Settings\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source and run the New Linode Setup script for DNS configuration\n# This also sets some useful variables, like $IP and $FQDN\n\nsource \n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nset pipefail -o\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Allow traffic on ports 80 and 443\nufw allow 80\nufw allow 443\n\n# Installing Filecloud and Prequisites\nwget -qO - https://repo.filecloudlabs.com/static/pgp/filecloud.asc | sudo apt-key add -\nwget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -\necho \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list\necho \"deb [ arch=amd64 ] https://repo.filecloudlabs.com/apt/ubuntu focal/filecloud/22.1 main\" | sudo tee /etc/apt/sources.list.d/filecloud.list\napt-get update -y\napt-get install apache2 mongodb-org -y\napt install -y --no-install-recommends php8.1*\nACCEPT_EULA=Y apt-get install filecloud -y\n\nif [[ \"$SSL\" == \"Yes\" ]]; then\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\nfi\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"token_password","label":"Your Linode API token. This is required in order to create DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"ssl","label":"Would you like to use a free CertBot SSL certificate?","oneof":"Yes,No","default":"No"},{"name":"soa_email_address","label":"Email Address for Lets' Encrypt Certificate","default":""},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":609392,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Flask One-Click","description":"Flask One-Click","ordinal":31,"logo_url":"assets/flask.svg","images":["linode/debian10"],"deployments_total":2171,"deployments_active":136,"is_public":true,"mine":false,"created":"2019-11-07T06:24:17","updated":"2023-12-11T05:42:53","rev_note":"Initial import","script":"#!/bin/bash\n\n## Enable logging\nexec > /var/log/stackscript.log 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\nufw_install\nufw allow http\n\n# Install Prereq's & Flask APP\napt install -y git\ncd /home\ngit clone https://github.com/abalarin/Flask-on-Linode.git flask_app_project\n\n# Install & configure Nginx\napt install -y nginx\ncat < /etc/nginx/sites-enabled/flask_app\nserver {\n listen 80;\n server_name $IP;\n location / {\n proxy_pass http://127.0.0.1:8000;\n proxy_set_header Host \\$host;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n }\n}\nEND\n\nunlink /etc/nginx/sites-enabled/default\nnginx -s reload\n\n# Install python & Packages\napt install -y python3 python3-pip\ncd /home/flask_app_project\npip3 install -r flask_app/requirements.txt\n\n# Configure Flask\ncat < /etc/config.json\n{\n \"SECRET_KEY\": \"$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)\",\n \"SQLALCHEMY_DATABASE_URI\": \"sqlite:///site.db\"\n}\nEND\n\ncat < /home/flask_app_project/flask_app/__init__.py\nfrom flask import Flask\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_login import LoginManager\nimport json\nimport urllib3\napp = Flask(__name__)\nwith open('/etc/config.json') as config_file:\n config = json.load(config_file)\napp.config['SECRET_KEY'] = config.get('SECRET_KEY')\napp.config['SQLALCHEMY_DATABASE_URI'] = config.get('SQLALCHEMY_DATABASE_URI')\ndb = SQLAlchemy(app)\nlogin_manager = LoginManager()\nlogin_manager.init_app(app)\nfrom flask_app import routes\nEND\n\n# Install and Configure Gunicorn\napt install -y gunicorn3\ngunicorn3 --workers=3 flask_app:app &\n\n# Install and Configure Supervisor\napt install -y supervisor\ncat < /etc/supervisor/conf.d/flask_app.conf\n[program:flask_app]\ndirectory=/home/flask_app_project\ncommand=gunicorn3 --workers=3 flask_app:app\nautostart=true\nautorestart=true\nstopasgroup=true\nkillasgroup=true\nstderr_logfile=/var/log/flask_app/flask_app.err.log\nstdout_logfile=/var/log/flask_app/flask_app.out.log\nEND\n\nmkdir /var/log/flask_app\ntouch /var/log/flask_app/flask_app.out.log\ntouch /var/log/flask_app/flask_app.err.log\nsupervisorctl reload\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[]},{"id":971045,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Focalboard One-Click","description":"Focalboard One-Click","ordinal":32,"logo_url":"assets/focalboard.svg","images":["linode/ubuntu22.04"],"deployments_total":480,"deployments_active":21,"is_public":true,"mine":false,"created":"2022-02-08T16:23:08","updated":"2023-12-09T17:50:19","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Focalboard Settings \n#\n\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-focalboard\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n #Focalboard vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"}]},{"id":1088136,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Galera Cluster One-Click","description":"Galera Cluster One-Click","ordinal":33,"logo_url":"assets/galeramarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":130,"deployments_active":9,"is_public":true,"mine":false,"created":"2022-11-15T20:41:27","updated":"2023-12-08T19:32:12","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/galera-occ\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/galera-occ\" ]; then\n rm -rf /tmp/galera-occ\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[+] Linode private IP present\"\n else\n echo \"[!] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[+] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction setup {\n export DEBIAN_FRONTEND=non-interactive\n # install dependancies\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n if [ ! -d ~/.ssh ]; then \n mkdir ~/.ssh\n else \n echo \".ssh directory is already created\"\n fi\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # add private IP address\n rename_provisioner\n configure_privateip \n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/galera-occ\n cd /tmp/galera-occ/\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip3 install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"","user_defined_fields":[{"name":"cluster_name","label":"Cluster Name"},{"name":"token_password","label":"Your Linode API token"},{"name":"add_ssh_keys","label":"Add Account SSH Keys to All Nodes?","oneof":"yes,no"},{"name":"sslheader","label":"SSL Information","header":"Yes","default":"Yes","required":"Yes"},{"name":"country_name","label":"Details for self-signed SSL certificates: Country or Region","oneof":"AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW"},{"name":"state_or_province_name","label":"State or Province","example":"Example: Pennsylvania"},{"name":"locality_name","label":"Locality","example":"Example: Philadelphia"},{"name":"organization_name","label":"Organization","example":"Example: Akamai Technologies"},{"name":"email_address","label":"Email Address","example":"Example: user@domain.tld"},{"name":"ca_common_name","label":"CA Common Name","default":"Galera CA"},{"name":"common_name","label":"Common Name","default":"Galera Server"},{"name":"cluster_size","label":"Galera cluster size","default":"3","oneof":"3"}]},{"id":688911,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Gitea One-Click","description":"Gitea One-Click","ordinal":34,"logo_url":"assets/gitea.svg","images":["linode/debian10"],"deployments_total":1016,"deployments_active":69,"is_public":true,"mine":false,"created":"2020-11-17T21:16:09","updated":"2023-12-12T13:07:22","rev_note":"","script":"#! /bin/bash\n\n## Database Settings\n#\n#\n\n## User and SSH Security\n#\n#\n#\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n#assigns var for IP address\nreadonly ip=$(hostname -I | awk '{print$1}')\n\n#intall git\napt install -y git\n\n#install nginx\napt install -y nginx\n\n#install mysql and secure\nmysql_root_preinstall\napt-get install -y mariadb-server\nsystemctl start mariadb\nsystemctl enable mariadb\nrun_mysql_secure_installation\n\n#create mysql db and user\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"CREATE DATABASE gitea;\"\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"CREATE USER 'gitea'@'localhost' IDENTIFIED BY '$(printf '%q' \"$DB_PASSWORD\")';\"\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'localhost' WITH GRANT OPTION;\"\nmysql -u root --password=\"$DBROOT_PASSWORD\" -e \"FLUSH PRIVILEGES;\"\n\n#create user for gitea\nadduser --system --disabled-password --group --shell /bin/bash --gecos 'Git Version Control' --home /home/git git\n\n#create directories for gitea\nmkdir -p /var/lib/gitea/{custom,data,log}\nchown -R git:git /var/lib/gitea/\nchmod -R 750 /var/lib/gitea/\nmkdir /etc/gitea\nchown root:git /etc/gitea\nchmod 770 /etc/gitea\n\n#pull down gitea binary\nwget -O gitea https://dl.gitea.io/gitea/1.13.0/gitea-1.13.0-linux-amd64\nchmod +x gitea\n\n#validate gpg\napt install gnupg -y\ngpg --keyserver keys.openpgp.org --recv 7C9E68152594688862D62AF62D9AE806EC1592E2\ngpg --verify gitea-1.13.0-linux-amd64.asc gitea-1.13.0-linux-amd64\n\n#copy gitea to global location\ncp gitea /usr/local/bin/gitea\n\n#download systemd file from gitea\nwget https://raw.githubusercontent.com/go-gitea/gitea/master/contrib/systemd/gitea.service -P /etc/systemd/system/\n\n#add requires mysql to the systemd file\nsed -i 's/#Requires=mariadb.service/Requires=mariadb.service/' /etc/systemd/system/gitea.service\n\n#start gitea as systemd service\nsystemctl daemon-reload\nsystemctl start gitea\nsystemctl enable gitea\n\n#configures ufw rules before nginx\nsystemctl start ufw\nufw allow http\nufw allow https\nufw enable\n\n#set absolute domain if any, otherwise use localhost\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=localhost\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\n#configure nginx reverse proxy\nrm /etc/nginx/sites-enabled/default\ntouch /etc/nginx/sites-available/reverse-proxy.conf\ncat < /etc/nginx/sites-available/reverse-proxy.conf\nserver {\n listen 80;\n listen [::]:80;\n server_name ${ABS_DOMAIN};\n\n access_log /var/log/nginx/reverse-access.log;\n error_log /var/log/nginx/reverse-error.log;\n\n location / {\n proxy_pass http://localhost:3000;\n }\n}\nEND\nln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/reverse-proxy.conf\n\n#enable and start nginx\nsystemctl enable nginx\nsystemctl restart nginx\n\nsleep 60\n\n#sets certbot ssl\nif [[ $SSL = \"Yes\" ]]; then\n check_dns_propagation ${ABS_DOMAIN} ${ip}\n apt install python3-certbot-nginx -y\n certbot run --non-interactive --nginx --agree-tos --redirect -d ${ABS_DOMAIN} -m ${EMAIL_ADDRESS} -w /var/www/html/\nfi\n\nstackscript_cleanup","user_defined_fields":[{"name":"dbroot_password","label":"MySQL root Password"},{"name":"db_password","label":"gitea Database Password"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"pwless_sudo","label":"Enable passwordless sudo access for the limited user?","oneof":"Yes,No","default":"No"},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"auto_updates","label":"Configure automatic security updates?","oneof":"Yes,No","default":"No"},{"name":"fail2ban","label":"Use fail2ban to prevent automated instrusion attempts?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your DNS records.","default":""},{"name":"subdomain","label":"The subdomain for your server (Domain required)","default":""},{"name":"domain","label":"Your domain (API Token required)","default":""},{"name":"soa_email_address","label":"SOA Email for your domain (Required for new domains)","default":""},{"name":"mx","label":"Do you need an MX record for this domain? (Yes if sending mail from this Linode)","oneof":"Yes,No","default":"No"},{"name":"spf","label":"Do you need an SPF record for this domain? (Yes if sending mail from this Linode)","oneof":"Yes,No","default":"No"},{"name":"ssl","label":"Would you like to use a free Let's Encrypt SSL certificate for your domain?","oneof":"Yes,No","default":"No"},{"name":"email_address","label":"Admin Email for Let's Encrypt certificate","default":""}]},{"id":401707,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"GitLab One-Click","description":"GitLab One-Click","ordinal":35,"logo_url":"assets/GitLab.svg","images":["linode/ubuntu20.04","linode/debian11"],"deployments_total":3270,"deployments_active":139,"is_public":true,"mine":false,"created":"2019-03-08T21:12:21","updated":"2023-12-09T12:02:06","rev_note":"Remove SSH Pubkey UDF","script":"#!/usr/bin/env bash\n\n## Gitlab Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction gitlab {\n # Install dependencies\n apt-get install curl ca-certificates apt-transport-https gnupg2 -y\n\n curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | bash\n apt-get update -y\n EXTERNAL_URL=\"https://$FQDN\" apt-get install gitlab-ce -y\n\n}\n\nfunction sslgitlab {\n # Taking advantage of Gitlab's Let's Encrypt cert capabilities\n sed -i \"s/# letsencrypt\\['enable'\\] = nil/letsencrypt\\['enable'\\] = true/g\" /etc/gitlab/gitlab.rb\n sed -i -E \"s/(# )(letsencrypt\\['auto_renew*)/\\2/g\" /etc/gitlab/gitlab.rb\n sed -i \"s/letsencrypt['auto_renew_minute'] = nil/letsencrypt['auto_renew_minute'] = 0/g\" /etc/gitlab/gitlab.rb\n sed -i \"s/# letsencrypt\\['contact_emails'\\] = \\[\\]/letsencrypt\\['contact_emails'\\] = \\['$SOA_EMAIL_ADDRESS']/g\" /etc/gitlab/gitlab.rb\n\n gitlab-ctl reconfigure\n}\n\nfunction firewallgitlab {\n ufw allow http\n ufw allow https\n}\n\nfunction main {\n gitlab\n firewallgitlab\n sslgitlab\n}\n\n# Execute Script\nmain\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"This is the Email address for the LetsEncrypt SSL Certificate","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your Gitlab server's DNS records","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""}]},{"id":1102905,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Gopaddle One-Click","description":"Gopaddle One-Click app","ordinal":36,"logo_url":"assets/gopaddle.svg","images":["linode/ubuntu22.04"],"deployments_total":46,"deployments_active":2,"is_public":true,"mine":false,"created":"2022-12-20T17:44:47","updated":"2023-12-09T22:36:44","rev_note":"","script":"#!/bin/bash\nexec >/var/log/stackscript.log 2>&1\n# Install Docker\napt-get update -y\napt-get install -y ca-certificates curl gnupg lsb-release\nmkdir -p /etc/apt/keyrings\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\necho \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\napt-get update -y\nchmod a+r /etc/apt/keyrings/docker.gpg\napt-get update -y\napt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin\n\n# Install microk8s\napt-get install snapd -y \nsudo snap install core\nexport PATH=$PATH:/snap/bin\nsnap install microk8s --classic --channel=1.25\nsnap refresh microk8s --channel=1.25\nmicrok8s status --wait-ready\n\n\n# Install gopaddle\nmicrok8s addons repo add gp-lite https://github.com/gopaddle-io/microk8s-community-addons-gplite.git\nmicrok8s enable gopaddle-lite\n\necho Waiting for gopaddle services to move to running state ...\nmicrok8s.kubectl wait --for=condition=ready pod -l released-by=gopaddle -n gp-lite --timeout=15m\n\nRDNS=$(dnsdomainname -A | awk '{print $1}')\n\necho gopaddle-lite installation is complete ! You can now access the gopaddle dashboard @ http://$RDNS:30003/","user_defined_fields":[]},{"id":607256,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Grafana One-Click","description":"Grafana One Click App","ordinal":37,"logo_url":"assets/grafana.svg","images":["linode/debian11"],"deployments_total":835,"deployments_active":55,"is_public":true,"mine":false,"created":"2019-10-30T20:43:07","updated":"2023-12-10T22:50:48","rev_note":"","script":"#!/usr/bin/env bash\n\n### Grafana OCA\n\n## Grafana Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n# Source the Bash StackScript Library\nsource \n\n# Source and run the New Linode Setup script for SSH configuration\nsource \n\n# Install PreReqs\napt-get install -y apt-transport-https \\\nsoftware-properties-common \\\nwget \\\ngnupg2 \\\nsqlite3\n\nwget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key\necho \"deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main\" | sudo tee -a /etc/apt/sources.list.d/grafana.list\napt-get -y update\napt-get -y install grafana\nsystemctl start grafana-server\nsystemctl enable grafana-server\n\n## reset Grafana admin password\n#grafana-cli --homepath \"/usr/share/grafana\" admin reset-admin-password $grafana_password. --not working -hmorris\necho \"Initializing DB.....\" && sleep 25\nsqlite3 /var/lib/grafana/grafana.db <\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction grav {\n apt-get install -y apache2 php libapache2-mod-php php-mysql mysql-server composer php-curl php-common php-gd php-json php-mbstring php-xml php-zip\n run_mysql_secure_installation_ubuntu20\n cd /var/www/html\n git clone https://github.com/getgrav/grav.git\n cd grav\n chown www-data:www-data -R .\n su -l www-data -s /bin/bash -c \"cd /var/www/html/grav && composer install --no-dev -o && bin/grav install && bin/gpm install admin\"\n chown www-data:www-data -R .\n}\n\nfunction apache_conf {\n cat < /etc/apache2/sites-available/grav.conf\n\nServerAdmin $SOA_EMAIL_ADDRESS\nDocumentRoot /var/www/html/grav/\nServerName $FQDN\nServerAlias www.$FQDN\n\nOptions FollowSymLinks\nAllowOverride All\nOrder allow,deny\nallow from all\n\nErrorLog /var/log/apache2/$FQDN-error_log\nCustomLog /var/log/apache2/$FQDN-access_log common\n\n\nEND\n a2enmod rewrite\n a2ensite grav.conf\n a2dissite 000-default.conf\n service apache2 restart\n}\n\nfunction ssl {\n apt install certbot python3-certbot-apache -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n}\nfunction firewall {\n ufw allow http\n ufw allow https\n}\n\nfunction main {\n firewall\n grav\n apache_conf\n ssl\n\n}\n\n\n# execute script\nmain\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"This is the Email address for the LetsEncrypt SSL Certificate","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":688914,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Guacamole One-Click","description":"Guacamole One-Click","ordinal":39,"logo_url":"assets/guacamole.svg","images":["linode/ubuntu22.04"],"deployments_total":4459,"deployments_active":63,"is_public":true,"mine":false,"created":"2020-11-17T21:28:05","updated":"2023-12-12T02:07:58","rev_note":"","script":"#!/usr/bin/env bash\n### Apache Guacamole OCA\n### Required UDFs\n## Guacamole Settings\n#\n#\n#\n#\n#\n### Optional UDFs\n## Linode/SSH Security Settings\n#\n#\n## Domain Settings\n#\n#\n#\n## Logging and other debugging helpers\n# Put bash into verbose mode\nset -o pipefail\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Imports\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n### Main Script\n## Open the needed firewall ports\nufw allow http\nufw allow https\n# Install dependencies\nsystem_install_package build-essential libcairo2-dev libpng-dev libtool-bin libossp-uuid-dev libvncserver-dev freerdp2-dev libssh2-1-dev \\\nlibtelnet-dev libwebsockets-dev libpulse-dev libvorbis-dev libwebp-dev \\\nlibssl-dev libpango1.0-dev libswscale-dev libavcodec-dev libavutil-dev \\\nlibavformat-dev\n# Download the Guacamole Server source code\n# Fetch the latest release page\nlatest_release_page=$(curl -sL https://guacamole.apache.org/releases/ | grep -m 1 -o 'href=\"/releases/[0-9.]\\+/\"')\n# Extract the version number from the release page URL\nlatest_version=$(echo $latest_release_page | grep -Eo '[0-9]\\.[0-9]+.[0-9]+')\n# Download the server component\nwget https://downloads.apache.org/guacamole/$latest_version/source/guacamole-server-$latest_version.tar.gz\ntar -xvf guacamole-server-$latest_version.tar.gz\ncd guacamole-server-$latest_version\n# Build Guacamole Server using the downloaded source code\n./configure --with-init-dir=/etc/init.d --enable-allow-freerdp-snapshots\nmake\nmake install\n# Update installed library cache and reload systemd\nldconfig\nsystemctl daemon-reload\n# Start guacd\nsystemctl enable guacd\n## Install Guacamole Web App\n# Install Apache Tomcat\nsystem_install_package tomcat9 tomcat9-admin tomcat9-common tomcat9-user\n# Download and install the Guacamole Client\nwget https://downloads.apache.org/guacamole/$latest_version/binary/guacamole-$latest_version.war\nmv guacamole-$latest_version.war /var/lib/tomcat9/webapps/guacamole.war\nsystemctl restart tomcat9 guacd\n## Guacamole configs\nmkdir /etc/guacamole\nreadonly ENCRYPTED_GUACAMOLE_PASSWORD=\"$(echo -n \"$GUACAMOLE_PASSWORD\" | openssl md5 | awk '{print $2}')\"\ncat <> /etc/guacamole/user-mapping.xml\n\n \n \n \n \n vnc\n localhost\n 5901\n ${PASSWORD}\n \n \n\nEOF\ncat <> /etc/guacamole/guacd.conf\n[daemon]\npid_file = /var/run/guacd.pid\n#log_level = debug\n[server]\nbind_host = 127.0.0.1\nbind_port = 4822\nEOF\ncat <> /etc/guacamole/guacamole.properties\n# Hostname and port of guacamole proxy\nguacd-hostname: localhost\nguacd-port: 4822\nEOF\nsystemctl restart tomcat9 guacd\n## Install a desktop environment (XFCE) and VNC Server\n# Install XFCE & NVC\nsystem_install_package xfce4 xfce4-goodies tigervnc-standalone-server expect\n# Set the VNC Server password\nreadonly VNCSERVER_SET_PASSWORD=$(expect -c \"\nspawn sudo -u $USERNAME vncserver\nexpect \\\"Password:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Verify:\\\"\nsend \\\"$PASSWORD\\r\\\"\nexpect \\\"Would you like to enter a view-only password (y/n)?\\\"\nsend \\\"n\\r\\\"\nexpect eof\n\")\necho \"$VNCSERVER_SET_PASSWORD\"\nsystemctl restart tomcat9 guacd\nkillvncprocess=$(ps aux | grep \"/usr/bin/Xtigervnc :1 -localhost=1 -desktop\" | head -n 1 | awk '{ print $2; }')\nkill $killvncprocess\n# Create a systemd service for Tiger VNC\ntouch /etc/systemd/system/vncserver@.service\ncat < /etc/systemd/system/vncserver@.service\n[Unit]\nDescription=a wrapper to launch an X server for VNC\nAfter=syslog.target network.target\n[Service]\nType=forking\nUser=$USERNAME\nGroup=$USERNAME\nWorkingDirectory=/home/$USERNAME\nExecStartPre=-/usr/bin/vncserver -kill :%i > /dev/null 2>&1\nExecStart=/usr/bin/vncserver -depth 24 -geometry 1280x800 -localhost :%i\nExecStop=/usr/bin/vncserver -kill :%i\n[Install]\nWantedBy=multi-user.target\nEOF\n# Start and enable the systemd service\nsystemctl start vncserver@1.service\nsystemctl enable vncserver@1.service\n## Reverse proxy for the Guacamole client\n# Install Apache\napache_install\na2enmod proxy proxy_http headers proxy_wstunnel\n# Create the VirtualHost for Guacamole\ncat < /etc/apache2/sites-available/guacamole.conf\n\n ServerName $FQDN\n ErrorLog ${APACHE_LOG_DIR}/guacamole_error.log\n CustomLog ${APACHE_LOG_DIR}/guacamole_access.log combined\n \n Require all granted\n ProxyPass http://localhost:8080/guacamole/ flushpackets=on\n ProxyPassReverse http://localhost:8080/guacamole/\n \n \n Require all granted\n ProxyPass ws://localhost:8080/guacamole/websocket-tunnel\n ProxyPassReverse ws://localhost:8080/guacamole/websocket-tunnel\n \n Header always unset X-Frame-Options\n\nEOF\n# Enable the VirtualHost\na2ensite guacamole.conf\nsystemctl restart apache2\n## HTTPS\nsystem_install_package python3-certbot-apache\ncertbot -n --apache --agree-tos --redirect --hsts --staple-ocsp --email \"$SOA_EMAIL_ADDRESS\" -d \"$FQDN\" \n## Cleanup after ourselves\nstackscript_cleanup\nreboot","user_defined_fields":[{"name":"username","label":"The limited sudo/VNC user to be created for the Linode"},{"name":"password","label":"The password for the limited sudo/VNC user"},{"name":"guacamole_user","label":"The username to be used with Guacamole"},{"name":"guacamole_password","label":"The password to be used with Guacamole"},{"name":"soa_email_address","label":"Email for SSL certificate"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is required if filling out any of the domain-related fields.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record","default":""},{"name":"domain","label":"The domain for the Linode's DNS record","default":""}]},{"id":1102902,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"HaltDOS Community WAF One-Click","description":"HaltDOS Community WAF One-Click app","ordinal":40,"logo_url":"assets/haltdos.svg","images":["linode/debian11","linode/ubuntu22.04"],"deployments_total":174,"deployments_active":8,"is_public":true,"mine":false,"created":"2022-12-20T17:34:20","updated":"2023-12-07T12:34:52","rev_note":"","script":"#!/bin/bash\n\nset -x\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\necho -e \"\\n---------------HALTDOS COMMUNITY WAF SETUP---------------\"\n\nexport NEEDRESTART_SUSPEND=1\nip=`ip route get 8.8.8.8 | awk -F\"src \" 'NR==1{split($2,a,\" \");print a[1]}'`\necho -e \"Checking OS ...\"\nsource /etc/os-release > /dev/null 2>&1\narch=`uname -m`\nif [[ \"$ID\" == \"ubuntu\" || \"$ID\" == \"debian\" ]]; then\n if [[ \"$VERSION_ID\" == \"18.04\" || \"$VERSION_ID\" == \"20.04\" || \"$VERSION_ID\" == \"22.04\" || \"$VERSION_ID\" == \"11\" ]]; then\n if [ \"$arch\" != \"x86_64\" ]; then\n echo -e \"\\e[1;31m$arch is not yet supported. Supported System Architecture - x86_64 \\e[0m\"\n fi\n else\n echo -e \"\\e[1;31mThis OS is not yet supported. Supported OS - Ubuntu 18.04, 20.04, 22.04 and Debian 11 \\e[0m\"\n exit 1\n fi\nelse\n echo -e \"\\e[1;31mThis OS is not yet supported. Supported Versions - Ubuntu 18.04, 20.04, 22.04 and Debian 11 \\e[0m\"\n exit 1\nfi\n\necho -e \"Downloading dependencies ...\"\n\napt-get update &> /dev/null\n\napt-get install -y default-jdk default-jre &> /dev/null\necho \"JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/\" >> /etc/environment\nsource /etc/environment\n\necho -e \"Downloading latest binaries ...\"\n\nsource /etc/os-release > /dev/null 2>&1\nif [ \"$VERSION_ID\" == \"18.04\" ]; then\n apt-get install -y libmaxminddb-dev python-dev python &> /dev/null \n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/ubuntu-18/hd-community-waf-x86_64.deb &> /dev/null\nelif [ \"$VERSION_ID\" == \"20.04\" ]; then\n apt-get install -y libmaxminddb-dev python-dev python &> /dev/null\n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/ubuntu-20/hd-community-waf-x86_64.deb &> /dev/null\nelif [ \"$VERSION_ID\" == \"22.04\" ]; then\n apt-get install -y libmaxminddb-dev libmaxminddb0 mmdb-bin python2-dev python2 &> /dev/null\n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/ubuntu-22/hd-community-waf-x86_64.deb &> /dev/null\nelif [[ \"$ID\" == \"debian\" && \"$VERSION_ID\" == \"11\" ]]; then\n apt-get install -y sudo libmaxminddb-dev python-dev python &> /dev/null\n curl -s -k -o hd-community-waf.deb https://binary.haltdos.com/community/waf/deb/debian-11/hd-community-waf-x86_64.deb &> /dev/null\nfi\n\napt-get install -y ./hd-community-waf.deb &> /dev/null\nrm hd-community-waf.deb\necho -e \"Haltdos Community WAF Installed\"\n\n\ncurl -s -k -o hd-community-controller.deb https://binary.haltdos.com/community/waf/gui/hd-community-controller-x86_64.deb &> /dev/null\napt-get install -y ./hd-community-controller.deb &> /dev/null\nrm hd-community-controller.deb\necho -e \"Haltdos Community Controller Installed\"\n\n\necho -e \"Haltdos Community WAF Setup Done\\n\"\necho -e \"Configure your WAF on https://$ip:9000\\n\"\nexport NEEDRESTART_SUSPEND=0","user_defined_fields":[]},{"id":912262,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Harbor One-Click","description":"Harbor One-Click","ordinal":41,"logo_url":"assets/harbor.svg","images":["linode/ubuntu22.04"],"deployments_total":290,"deployments_active":13,"is_public":true,"mine":false,"created":"2021-09-29T17:06:13","updated":"2023-12-12T10:54:07","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## harbor Settings \n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-harbor\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # harbor vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Admin Email for the Harbor server and Let's Encrypt SSL certificate"}]},{"id":1037037,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"HashiCorp Nomad One-Click","description":"HashiCorp Nomad One Click App","ordinal":42,"logo_url":"assets/nomad.svg","images":["linode/debian11","linode/ubuntu22.04"],"deployments_total":105,"deployments_active":3,"is_public":true,"mine":false,"created":"2022-08-02T18:46:19","updated":"2023-12-09T07:05:18","rev_note":"","script":"#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## set some variables\nexport NOMAD_DIR=/usr/bin\nexport NOMAD_PATH=${NOMAD_DIR}/nomad\nexport NOMAD_CONFIG_DIR=/etc/nomad.d\nexport NOMAD_DATA_DIR=/opt/nomad/data\nexport NOMAD_TLS_DIR=/opt/nomad/tls\nexport NOMAD_ENV_VARS=${NOMAD_CONFIG_DIR}/nomad.conf\nexport IP=$(hostname -I | awk '{print$1}')\n\n\n## install gpg\napt-get install -y gpg\n\n## Install Nomad\nwget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg\necho \"deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/hashicorp.list\nsudo apt update -y && sudo apt install -y nomad\n\n#echo \"Start Nomad in -server mode\"\nsudo tee ${NOMAD_ENV_VARS} > /dev/null < ${NOMAD_ENV_VARS}\n[Unit]\nDescription=Nomad Agent\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nRestart=on-failure\nEnvironmentFile=/etc/nomad.d/nomad.conf\nExecStart=/usr/local/bin/nomad agent -config /etc/nomad.d $FLAGS\nExecReload=/bin/kill -HUP $MAINPID\nKillSignal=SIGTERM\nUser=root\nGroup=root\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\n## enable and start nomad\nsystemctl enable nomad\nsystemctl start nomad\n\n## Install Docker\ncurl -fsSL get.docker.com | sudo sh\n\n## Configure nginx container\ncat << EOF > /root/nginx.conf\nevents {}\n\nhttp {\n server {\n location / {\n proxy_pass http://nomad-ws;\n proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;\n\n # Nomad blocking queries will remain open for a default of 5 minutes.\n # Increase the proxy timeout to accommodate this timeout with an\n # additional grace period.\n proxy_read_timeout 310s;\n\n # Nomad log streaming uses streaming HTTP requests. In order to\n # synchronously stream logs from Nomad to NGINX to the browser\n # proxy buffering needs to be turned off.\n proxy_buffering off;\n\n # The Upgrade and Connection headers are used to establish\n # a WebSockets connection.\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection \"upgrade\";\n\n # The default Origin header will be the proxy address, which\n # will be rejected by Nomad. It must be rewritten to be the\n # host address instead.\n proxy_set_header Origin \"\\${scheme}://\\${proxy_host}\";\n }\n }\n\n # Since WebSockets are stateful connections but Nomad has multiple\n # server nodes, an upstream with ip_hash declared is required to ensure\n # that connections are always proxied to the same server node when possible.\n upstream nomad-ws {\n ip_hash;\n server host.docker.internal:4646;\n }\n}\nEOF\n\n## start docker container\ndocker run -d --publish=8080:80 --add-host=host.docker.internal:host-gateway \\\n --mount type=bind,source=$PWD/nginx.conf,target=/etc/nginx/nginx.conf \\\n nginx:latest\n\n## firewall\nufw allow 22\nufw allow 80\nufw allow 443\nufw allow 4646\nufw allow 8080\n\ncat << EOF > /etc/motd\n#################################\n The Nomad GUI is now available at HTTP://${IP}:8080\n\n This is a minimal installation with limited configurations.\n Please review configurations before using this application in production.\n\n Information on Nomad configurations at https://www.nomadproject.io/docs/configuration\n#################################\nEOF\n\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":1226544,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"HashiCorp Nomad Cluster One-Click","description":"Nomad Cluster One-Click","ordinal":43,"logo_url":"assets/nomadocc.svg","images":["linode/ubuntu22.04"],"deployments_total":97,"deployments_active":5,"is_public":true,"mine":false,"created":"2023-08-25T19:05:25","updated":"2023-12-03T16:18:47","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\ngit_username=\"akamai-compute-marketplace\"\nexport GIT_REPO_1=\"https://github.com/$git_username/nomad-occ.git\"\nexport GIT_REPO_2=\"https://github.com/$git_username/nomad-client-occ.git\"\nexport DEBIAN_FRONTEND=non-interactive\nexport UUID=$(uuidgen | awk -F - '{print $1}')\nexport CLUSTER_MODE='cluster'\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \n\nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n cd ${HOME}\n if [ -d \"/tmp/linode\" ]; then\n rm -rf /tmp/linode\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[warn] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[info] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}-server-1-${UUID}\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\n\nfunction tag_provisioner {\n echo \"[info] tagging the provisioner\"\n REGION=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .region)\n export REGION=\"${REGION}\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" -X PUT \\\n -d \"{\\\"tags\\\": [\\\"${UUID}-${REGION}\\\"]}\" \\ \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID} \n}\n\nfunction setup {\n # install dependencies\n export DEBIAN_FRONTEND=non-interactive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n tag_provisioner\n configure_privateip \n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO_1} /tmp/linode\n git clone ${GIT_REPO_2} /tmp/linode/nomad-client-occ\n # clone one branch to test \n # git clone -b develop ${GIT_REPO_1} /tmp/linode\n # git clone -b develop ${GIT_REPO_2} /tmp/linode/nomad-client-occ\n cd /tmp/linode\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"","user_defined_fields":[{"name":"token_password","label":"Your Linode API token"},{"name":"sudo_username","label":"The limited sudo user to be created in the cluster"},{"name":"email_address","label":"Email Address","example":"Example: user@domain.tld"},{"name":"clusterheader","label":"Cluster Settings","default":"Yes","header":"Yes"},{"name":"add_ssh_keys","label":"Add Account SSH Keys to All Nodes?","oneof":"yes,no","default":"yes"},{"name":"cluster_size","label":"Total instance count","default":"6","oneof":"6"},{"name":"servers","label":"Nomad Server count","default":"3","oneof":"3"},{"name":"clients","label":"Nomad client size","default":"3","oneof":"3"}]},{"id":1226545,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"HashiCorp Nomad Clients Cluster One-Click","description":"Nomad Cluster Clients One-Click","ordinal":44,"logo_url":"assets/nomadclientsocc.svg","images":["linode/ubuntu22.04"],"deployments_total":3,"deployments_active":0,"is_public":true,"mine":false,"created":"2023-08-25T19:07:27","updated":"2023-11-14T15:53:47","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n cd ${HOME}\n if [ -d \"/tmp/linode\" ]; then\n rm -rf /tmp/linode\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[warn] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[info] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}-client-1-${UUID}\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction tag_provisioner {\n echo \"[info] tagging the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" -X PUT \\\n -d \"{\\\"tags\\\": [\\\"${CLUSTER_UUID}\\\"]}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID} \n}\n\nfunction setup {\n # install dependencies\n export DEBIAN_FRONTEND=noninteractive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n tag_provisioner\n configure_privateip \n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/linode\n # clone one branch to test \n # git clone -b develop ${GIT_REPO} /tmp/linode\n cd /tmp/linode\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"","user_defined_fields":[{"name":"token_password","label":"Your Linode API token"},{"name":"sudo_username","label":"The limited sudo user to be created in the cluster"},{"name":"clusterheader","label":"Cluster Settings","default":"Yes","header":"Yes"},{"name":"add_ssh_keys","label":"Add Account SSH Keys to All Nodes?","oneof":"yes,no","default":"yes"},{"name":"cluster_size","label":"Nomad Client Count","default":"3","oneof":"3,5,7"},{"name":"consul_nomad_autojoin_token_password","label":"consul_nomad_autojoin_token generated by Nomad Server OCC"},{"name":"cluster_uuid","label":"cluster_uuid tag for the Nomad Server OCC being joined to.","# git repogit_username":"akamai-compute-marketplace","export git_repo":"https://github.com/$git_username/nomad-client-occ.git"}]},{"id":1037038,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"HashiCorp Vault One-Click","description":"HashiCorp Vault One Click App","ordinal":45,"logo_url":"assets/vault.svg","images":["linode/debian11","linode/ubuntu22.04"],"deployments_total":217,"deployments_active":17,"is_public":true,"mine":false,"created":"2022-08-02T18:47:32","updated":"2023-12-12T08:52:30","rev_note":"","script":"#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nexport IP=$(hostname -I | awk '{print$1}')\nexport VAULT_ADDR=\"http://${IP}:8200\"\n\n## install gpg\napt install -y gpg\n\n## add hashicorp gpg key and repo\nwget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor | sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg >/dev/null\necho \"deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/hashicorp.list\n\n## install vault\napt update && apt install -y vault\n\n## basic vault configs\nmkdir -p /vault/data\nchown -R vault:vault /vault\ncat << EOF > /etc/vault.d/vault.hcl\nstorage \"raft\" {\n path = \"/vault/data\"\n node_id = \"node1\"\n}\n\nlistener \"tcp\" {\n address = \"${IP}:8200\"\n tls_disable = \"true\"\n}\n\ndisable_mlock = true\n\napi_addr = \"http://127.0.0.1:8200\"\ncluster_addr = \"https://127.0.0.1:8201\"\nui = true\nEOF\n\n## systemd for vault\nsystemctl enable vault.service\n\n## Start vault server and stash the tokens\nsystemctl start vault.service\ntouch /root/.vault_tokens.txt\nsleep 20\nvault operator init | grep 'Token\\|Unseal' >> /root/.vault_tokens.txt\n\n## firewall\nufw allow 22\nufw allow 8200\n\n## config info and recommendations\ncat << EOF > /etc/motd\n#####################################\n The Vault server GUI is now available at ${VAULT_ADDR}\n The randomly generate Unseal Tokens and Initial Root Token are listed in /root/.vault_tokens.txt\n ** STORE THESE VALUES SOMEWHERE SAFE AND SECURE **\n\n This is a minimal installation with limited configurations.\n Please review configurations before using this application in production.\n\n Information on Vault configurations at https://www.vaultproject.io/docs/configuration\n######################################\nEOF\n\nsleep 20\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":1177605,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Illa Builder One-Click","description":"Illa Builder One-Click App","ordinal":46,"logo_url":"assets/illabuilder.svg","images":["linode/ubuntu22.04"],"deployments_total":99,"deployments_active":3,"is_public":true,"mine":false,"created":"2023-05-17T14:22:00","updated":"2023-12-11T08:04:06","rev_note":"","script":"#!/bin/bash\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Sources OCA helpers\nsource \nsource \nsource \nsource \n# Apt update/upgrade\nexport DEBIAN_FRONTEND=non-interactive\napt update && apt upgrade -y\n\n# Install the dependencies & add Docker to the APT repository\napt install -y apt-transport-https ca-certificates curl software-properties-common gnupg2 pwgen ufw\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable\"\n\n# Update & install Docker-CE\napt_setup_update\napt install -y docker-ce\n\n# Check to ensure Docker is running and installed correctly\nsystemctl status docker\ndocker -v\n\n# Env config\nILLA_HOME_DIR=~/illa\nPG_VOLUMN=${ILLA_HOME_DIR}/database\nDRIVE_VOLUMN=${ILLA_HOME_DIR}/drive\n\n\n# Init\nmkdir -p ${ILLA_HOME_DIR}\nmkdir -p ${PG_VOLUMN}\nmkdir -p ${DRIVE_VOLUMN}\n\n# Run\ndocker run -d \\\n --name illa_builder \\\n -v $PG_VOLUMN:/opt/illa/database \\\n -v $DRIVE_VOLUMN:/opt/illa/drive \\\n -p 80:2022 \\\n illasoft/illa-builder:latest\n\necho \"\n********************************************************************************\nWelcome to ILLA Builder!\n********************************************************************************\n # ILLA Builder: http://\"$FQDN\"\n # Website: https://www.illacloud.com\n # Documentation: https://www.illacloud.com/docs/about-illa\n # Github: https://github.com/illacloud\n # Community Support: https://github.com/orgs/illacloud/discussions\n\"","user_defined_fields":[]},{"id":607401,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Jenkins One-Click","description":"Jenkins One-Click App","ordinal":47,"logo_url":"assets/jenkins.svg","images":["linode/debian11"],"deployments_total":2001,"deployments_active":133,"is_public":true,"mine":false,"created":"2019-10-31T15:29:54","updated":"2023-12-11T20:27:48","rev_note":"Initial import","script":"#!/bin/bash\n\nsource \nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Prereq's & Jenkins\napt install -y default-jre wget gnupg2\nwget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | apt-key add -\nsh -c 'echo deb http://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'\napt_setup_update\napt install -y jenkins\nsystemctl enable --now jenkins\n\n# Cleanup \nstackscript_cleanup","user_defined_fields":[]},{"id":869623,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"JetBackup One-Click","description":"JetBackup One-Click","ordinal":48,"logo_url":"assets/jetbackup.svg","images":["linode/centos7","linode/almalinux8"],"deployments_total":102,"deployments_active":1,"is_public":true,"mine":false,"created":"2021-07-21T12:45:59","updated":"2023-11-21T02:29:13","rev_note":"","script":"#!/bin/bash\n\n# JetBackup StackScript UDF Variables\n# \n# \n#\n# The next line makes the Official cPanel StackScript available if cPanel/WHM is selected as the control panel. Do not remove this line.\n# source \n#\n# Log File Paths:\n# StackScript Log: /var/log/stackscript.log\n# cPanel/WHM installation: /var/log/stackscript-595742.log\n# Debugging: /var/log/stackscript-debug.log\n#\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>/var/log/stackscript-debug.log\necho \"PID: $$\"\nCONTROLPANEL=${CONTROLPANEL}\nRELEASE=${RELEASETIER}\nJBDIR=\"/usr/local/jetapps/etc/jetbackup5\"\n\nif [[ -z ${CONTROLPANEL} ]]; then\necho \"Error: No panel selected. Please select a panel to deploy JetBackup.\"\nexit 1\nelif [[ -d ${JBDIR} ]]; then\necho \"Error: JetBackup already installed. Aborting StackScript.\"\nexit 0\nfi\n\necho \"Installing JetApps Repository\"\nrpm --import http://repo.jetlicense.com/centOS/RPM-GPG-KEY-JETAPPS\nyum -y -q install http://repo.jetlicense.com/centOS/jetapps-repo-latest.rpm\nyum -y -q install jetapps --disablerepo=* --enablerepo=jetapps\necho \"JetApps Repository Successfully Installed.\"\n\ncpanelinstall() {\n\necho \"Running cPanel/WHM Marketplace StackScript. You can track the progress of cPanel/WHM with: tail -f /var/log/stackscript-595742.log \"\n(source /root/ssinclude-595742 >>/var/log/stackscript-595742.log 2>&1)\n\n}\n\n# JETBACKUP 5 FOR LINUX - STANDALONE INSTALLATION\n\nif [ \"${CONTROLPANEL}\" = \"Linux\" ]; then\necho \"Installing JetBackup 5.\"\npackage='jetbackup5-linux'\njetapps --install $package $RELEASE\njbhostname=$(hostname)\njbhostname=\"https://${jbhostname}:3035\"\necho \"Adding a Firewall rule to open port 3035. Port 3035 must be open for access to the JetBackup 5 Linux UI.\"\nfirewall-cmd --permanent --add-port=3035/tcp\nfirewall-cmd --reload\necho \"To go to JetBackup and Accept the User Agreement, go to ${jbhostname} and enter your root login credentials.\"\necho \"To generate a one-time JetBackup 5 login URL after installation and acceptance of the EULA type the following command in the terminal:\"\necho \"jb5login\"\nfi\n\n# JETBACKUP 5 FOR CPANEL/WHM INSTALLATION\n\nif [ \"${CONTROLPANEL}\" = \"cPanel/WHM\" ]; then\n\npackage='jetbackup5-cpanel'\ncpanelinstall\nsleep 2\necho \"Installing JetBackup 5.\"\njetapps --install $package $RELEASE\necho \"To log in to cPanel/WHM as root user, please enter the following command to generate a one-time login token:\"\necho \"\"\necho \"whmlogin\"\nfi\n\necho \"Review the JetBackup 5 Getting Started Guide at https://docs.jetbackup.com/v5.1/adminpanel/gettingStarted.html\"\ninstallVersion=\"$(jetbackup5 --version | cut -d ' ' -f 1,3,4 | sed \"2 d\")\"\necho \"${installVersion} Successfully Installed!\"\nrm /root/ssinclude-595742\nrm /root/StackScript\nexit 0","user_defined_fields":[{"name":"CONTROLPANEL","label":"Choose a Control Panel to use with JetBackup 5. cPanel/WHM or Linux (No Control Panel)","default":"cPanel/WHM","oneof":"cPanel/WHM,Linux"},{"name":"RELEASETIER","label":"Choose a JetBackup Release Tier.","default":"stable","oneof":"stable,beta,edge"}]},{"id":662121,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Jitsi One-Click","description":"Jitsi One-Click","ordinal":49,"logo_url":"assets/jitsi.svg","images":["linode/ubuntu20.04","linode/ubuntu22.04"],"deployments_total":4521,"deployments_active":131,"is_public":true,"mine":false,"created":"2020-08-12T16:08:51","updated":"2023-12-12T15:23:16","rev_note":"","script":"#!/bin/bash\n\n## Jitsi Settings\n#\n\n## Domain Settings\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n\n# This also sets some useful variables, like $IP and $FQDN\nsource \nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# dependencies\nexport DEBIAN_FRONTEND=noninteractive\napt install apt-transport-https gnupg2 curl wget -y\napt-add-repository universe\napt update -y\n\n#Install Jitisi dep Prosody\necho deb http://packages.prosody.im/debian $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list\nwget https://prosody.im/files/prosody-debian-packages.key -O- | sudo apt-key add -\napt install lua5.2\n\n#Install Nginx\napt install -y nginx\nsystemctl start nginx\nsystemctl enable nginx\n\n#Install Jitsi Meet\ncurl https://download.jitsi.org/jitsi-key.gpg.key | sudo sh -c 'gpg --dearmor > /usr/share/keyrings/jitsi-keyring.gpg'\necho 'deb [signed-by=/usr/share/keyrings/jitsi-keyring.gpg] https://download.jitsi.org stable/' | sudo tee /etc/apt/sources.list.d/jitsi-stable.list > /dev/null\n\n# update all package sources\napt update -y\necho \"jitsi-videobridge jitsi-videobridge/jvb-hostname string $FQDN\" | debconf-set-selections\necho \"jitsi-meet-web-config jitsi-meet/cert-choice select 'Generate a new self-signed certificate (You will later get a chance to obtain a Let's encrypt certificate)'\" | debconf-set-selections\napt --option=Dpkg::Options::=--force-confold --option=Dpkg::options::=--force-unsafe-io --assume-yes install jitsi-meet\n\n# Firewall\nsudo ufw allow 80/tcp\nsudo ufw allow 443/tcp\nsudo ufw allow 10000/udp\nsudo ufw allow 22\nsudo ufw allow 3478/udp\nsudo ufw allow 5349/tcp\nsudo ufw enable\n\n# SSL \ncheck_dns_propagation \"${FQDN}\" \"${IP}\"\n/usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh <\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -xo pipefail\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\nfunction lampjoomla {\n apt-get install apache2 mariadb-server php php-common libapache2-mod-php php-cli php-fpm php-mysql php-json php-opcache php-gmp php-curl php-intl php-mbstring php-xmlrpc php-gd php-xml php-zip -y\n PHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\n cat < /etc/php/$PHP_VERSION/apache2/php.ini\nmemory_limit = 512M\nupload_max_filesize = 256M\npost_max_size = 256M \nmax_execution_time = 300\noutput_buffering = off\ndisplay_errors = off\nupload_tmp_dir = \"/var/www/html/joomla/tmp\"\nEND\n}\n\nfunction databaseconf {\n run_mysql_secure_installation\n mysql -uroot -p$DBROOT_PASSWORD -e \"CREATE DATABASE joomla_db;\"\n mysql -uroot -p$DBROOT_PASSWORD -e \"CREATE USER 'joomla'@'localhost' IDENTIFIED BY '$DBUSER_PASSWORD';\"\n mysql -uroot -p$DBROOT_PASSWORD -e \"GRANT ALL PRIVILEGES ON joomla_db.* TO 'joomla'@'localhost';\"\n}\n\nfunction apachejoomla {\n apt-get install wget unzip -y\n mkdir -p /var/www/html/joomla\n cd /tmp && wget https://downloads.joomla.org/cms/joomla4/4-1-0/Joomla_4-1-0-Stable-Full_Package.zip?format=zip\n unzip Joomla_4* -d /var/www/html/joomla\n chown -R www-data:www-data /var/www/html/joomla \n chmod -R 755 /var/www/html/joomla\n cat < /etc/apache2/sites-available/joomla.conf\n\n ServerAdmin $SOA_EMAIL_ADDRESS\n DocumentRoot /var/www/html/joomla\n ServerName $FQDN\n\n \n Options FollowSymlinks\n AllowOverride All\n Require all granted\n \n\n ErrorLog ${APACHE_LOG_DIR}/$FQDN_error.log\n CustomLog ${APACHE_LOG_DIR}/$FQDN_access.log combined\n\n\nEND\n a2ensite joomla.conf\n a2enmod rewrite\n a2enmod php$PHP_VERSION\n a2dissite 000-default.conf\n systemctl restart apache2\n\n ufw allow http\n ufw allow https\n}\nfunction ssljoomla {\n apt install certbot python3-certbot-apache -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n}\n\nfunction main {\n lampjoomla\n databaseconf\n apachejoomla\n ssljoomla\n stackscript_cleanup\n}\n# Execute script\nmain","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"dbroot_password","label":"MySQL Root Password","example":"s3cur3_9a55w04d"},{"name":"dbuser_password","label":"MySQL User Password","example":"s3cur3_9a55w04d"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":985380,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Joplin One-Click","description":"Joplin One-Click","ordinal":51,"logo_url":"assets/joplin.svg","images":["linode/ubuntu20.04"],"deployments_total":424,"deployments_active":31,"is_public":true,"mine":false,"created":"2022-03-08T18:14:30","updated":"2023-12-09T22:04:54","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Joplin setup\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-joplin\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n}\n\nfunction udf {\n \n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n \n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # Joplin vars\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n \n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"}]},{"id":688912,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Kepler Builder One-Click","description":"Kepler Builder One-Click","ordinal":52,"logo_url":"assets/keplerbuilder.svg","images":["linode/ubuntu22.04"],"deployments_total":264,"deployments_active":4,"is_public":true,"mine":false,"created":"2020-11-17T21:17:33","updated":"2023-12-06T21:13:24","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Wordpress Settings\n#\n#\n\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-keplerbuilder\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n webserver_stack: ${web_stack}\n site_title: ${SITE_TITLE}\n wp_admin_user: ${WP_ADMIN_USER}\n wp_db_user: ${WP_DB_USER}\n wp_db_name: ${WP_DB_NAME}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"webserver_stack","label":"The stack you are looking to deploy Wordpress on","oneof":"LAMP,LEMP"},{"name":"site_title","label":"Website title","example":"My Blog"},{"name":"wp_admin_user","label":"Admin username","example":"admin"},{"name":"wp_db_user","label":"Wordpress database user","example":"wordpress"},{"name":"wp_db_name","label":"Wordpress database name","example":"wordpress"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":401701,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"LAMP One-Click","description":"LAMP One-Click","ordinal":53,"logo_url":"assets/LAMP.svg","images":["linode/ubuntu22.04"],"deployments_total":13746,"deployments_active":1111,"is_public":true,"mine":false,"created":"2019-03-09T02:07:09","updated":"2023-12-12T15:27:55","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## LAMP Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-lamp\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n webserver_stack: lamp\n soa_email_address: ${SOA_EMAIL_ADDRESS}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":606691,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"LEMP One-Click","description":"LEMP Stack","ordinal":54,"logo_url":"assets/LEMP.svg","images":["linode/ubuntu22.04"],"deployments_total":4161,"deployments_active":314,"is_public":true,"mine":false,"created":"2019-10-27T15:29:04","updated":"2023-12-12T02:47:42","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## LEMP Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-lemp\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n webserver_stack: lemp\n soa_email_address: ${SOA_EMAIL_ADDRESS}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":923032,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"LiteSpeed cPanel One-Click","description":"LiteSpeed cPanel One-Click","ordinal":55,"logo_url":"assets/litespeedcpanel.svg","images":["linode/almalinux8"],"deployments_total":1017,"deployments_active":21,"is_public":true,"mine":false,"created":"2021-10-18T00:57:12","updated":"2023-12-08T17:46:01","rev_note":"","script":"#!/bin/bash\n## Logging\nexec > /var/log/stackscript.log 2>&1\n## Install cPanel\nyum install -y kernel grub2\nsed -i -e \"s/GRUB_TIMEOUT=5/GRUB_TIMEOUT=10/\" /etc/default/grub\nsed -i -e \"s/crashkernel=auto rhgb console=ttyS0,19200n8/console=ttyS0,19200n8/\" /etc/default/grub\nmkdir /boot/grub\ngrub2-mkconfig -o /boot/grub/grub.cfg\nsystemctl stop firewalld.service\nsystemctl disable firewalld.service\nsystemctl stop NetworkManager\nsystemctl disable NetworkManager\nsystemctl enable network\nsystemctl start network\nyum remove NetworkManager -y\ncd /home \ncurl -o latest -L https://securedownloads.cpanel.net/latest && sh latest\nyum remove ea-apache24-mod_ruid2 -y\n## Install LSWS on cPanel\nADMIN_PASS=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16 ; echo '')\ncat <>/home/lsws.options\n## 1 = enable, 0 = disable, 2 = user home directory\nphp_suexec=\"2\"\nport_offset=\"0\"\nadmin_user=\"admin\"\nadmin_pass=\"${ADMIN_PASS}\"\nadmin_email=\"root@localhost\"\neasyapache_integration=\"1\"\nauto_switch_to_lsws=\"1\"\ndeploy_lscwp=\"1\"\nEOT\nbash <( curl https://get.litespeed.sh ) TRIAL","user_defined_fields":[]},{"id":1008123,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"LiveSwitch One-Click","description":"LiveSwitch One-Click","ordinal":56,"logo_url":"assets/liveswitch.svg","images":["linode/ubuntu20.04"],"deployments_total":195,"deployments_active":1,"is_public":true,"mine":false,"created":"2022-05-18T16:41:37","updated":"2023-12-09T04:23:19","rev_note":"","script":"#!/bin/bash\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n## Import the Bash StackScript Library\nsource \n\nsudo dpkg --configure -a\n\n# kill any background updater jobs\nsudo killall apt apt-get\n\n# helpers\nsudo apt-get install dialog apt-utils -y -q\n\nsudo DEBIAN_FRONTEND=noninteractive apt-get update -y\nsudo DEBIAN_FRONTEND=noninteractive apt-get upgrade -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef -y\n\n# firewall\n# normal defaults\nsudo ufw default deny incoming\nsudo ufw default allow outgoing\n# ssh on\nsudo ufw allow ssh\n# dynamic inbound traffic\nsudo ufw allow 49152:65535/udp\n# TURN\nsudo ufw allow 3478/udp\n# TURN TCP\nsudo ufw allow 80/tcp\n# TURNS\nsudo ufw allow 443/tcp\n# admin (only really should do this for a demo system where it's all on one box)\nsudo ufw allow 9090/tcp\nsudo ufw allow 9443/tcp\n# gateway (only really should do this for a demo system where it's all on one box)\nsudo ufw allow 8080/tcp\nsudo ufw allow 8443/tcp\n\n# sip\n# sudo ufw allow 5061/udp\n# sudo ufw allow 5061/tcp\n\n# we will turn on the firewall at the end because it disconnects us\n\n# install docker\nsudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -\nsudo add-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable\"\napt-cache policy docker-ce\nsudo apt-get install -y docker-ce\n\n# entropy fix for docker\nsudo apt-get install -y haveged\n\n# install docker compose\nsudo curl -L \"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\nsudo chmod +x /usr/local/bin/docker-compose\n\n# retrieve docker compose files\nmkdir -p /opt/liveswitch\nsudo curl -L \"https://raw.githubusercontent.com/jvenema/liveswitch-docker-compose/main/docker-compose-liveswitch.service\" -o /opt/liveswitch/docker-compose-liveswitch.service\nsudo curl -L \"https://raw.githubusercontent.com/jvenema/liveswitch-docker-compose/main/docker-compose.yml\" -o /opt/liveswitch/docker-compose.yml\n\n# install liveswitch docker compose\nsudo cp /opt/liveswitch/docker-compose-liveswitch.service /etc/systemd/system/\nsudo systemctl enable docker\nsudo systemctl enable docker-compose-liveswitch\nsudo systemctl start docker-compose-liveswitch\n\n# clean up some logs\nsudo rm -f /var/log/cloud-init-output.log\nsudo rm -f /var/log/dpkg.log\nsudo rm -f /var/log/kern.log\nsudo rm -f /var/log/ufw.log\n\n# turn on the firewall\nsudo ufw --force enable\nsudo reboot","user_defined_fields":[]},{"id":869159,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MagicSpam One-Click","description":"MagicSpam One-Click","ordinal":57,"logo_url":"assets/magicspam.svg","images":["linode/centos7"],"deployments_total":6,"deployments_active":0,"is_public":true,"mine":false,"created":"2021-07-20T19:13:52","updated":"2023-12-11T15:26:23","rev_note":"","script":"#!/bin/bash\n\n# \n# \n# \n\n# source the stackscript for the selected control panel\nif [ \"$CONTROL_PANEL\" == \"cPanel\" ]; then\n # redirect ALL output to the stackscript log for future troubleshooting\n exec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n # cPanel Marketplace App install\n source \n\n # set the hostname to replicate Plesk stackscript for consistent behavior\n IPADDR=$(/sbin/ifconfig eth0 | awk '/inet / { print $2 }' | sed 's/addr://')\n echo $HOSTNAME > /etc/hostname\n hostname -F /etc/hostname\n echo $IPADDR $HOSTNAME >> /etc/hosts\nelif [ \"$CONTROL_PANEL\" == \"Plesk\" ]; then\n # Plesk Marketplace App install\n # NOTE: do not redirect output to the stackscript log to avoid duplicate log\n # lines as the Plesk stackscript already redirects to it\n source \nelse\n echo \"Invalid control panel option detected. Aborting...\"\n exit 1\nfi\n\n# install MagicSpam via the installer script\nwget https://www.magicspam.com/download/magicspam-installer.sh -O /root/magicspam-installer\nchmod +x /root/magicspam-installer\n/root/magicspam-installer -l \"$MS_LICENSE_KEY\"","user_defined_fields":[{"name":"control_panel","label":"The Control Panel to deploy alongside with MagicSpam. Make sure to select an Image supported by the selected Control Panel. For more information, please refer to the MagicSpam App Information Sidebar.","oneof":"cPanel,Plesk"},{"name":"ms_license_key","label":"The MagicSpam license key. Please make sure to use the appropriate license key for the selected Control Panel. For more information, please refer to the MagicSpam App information sidebar."},{"name":"hostname","label":"The server's hostname."}]},{"id":1243759,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MainConcept FFmpeg Plugins Demo One-Click","description":"MainConcept FFmpeg Plugins","ordinal":58,"logo_url":"assets/mainconcept.svg","images":["linode/debian11"],"deployments_total":6,"deployments_active":1,"is_public":true,"mine":false,"created":"2023-09-28T15:02:48","updated":"2023-12-06T21:14:38","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\n\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-ffmpeg-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""}]},{"id":1243760,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MainConcept Live Encoder Demo One-Click","description":"MainConcept Live Encoder\r\n\r\n","ordinal":59,"logo_url":"assets/mainconcept.svg","images":["linode/centos-stream9"],"deployments_total":20,"deployments_active":1,"is_public":true,"mine":false,"created":"2023-09-28T15:04:08","updated":"2023-12-06T15:19:44","rev_note":"","script":"#!/bin/bash\n\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-live-encoder-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(dnsdomainname -A | awk '{print $1}')\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n yum install dnf -y\n dnf update -y\n dnf upgrade -y\n dnf install -y git python3 python3-pip\n\n dnf makecache\n dnf install epel-release -y\n dnf makecache\n dnf install ansible -y\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone --single-branch --branch ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -vvvv $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address for SSL Generation","default":""}]},{"id":1243762,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MainConcept P2 AVC ULTRA Transcoder Demo One-Click","description":"MainConcept P2 AVC ULTRA Transcoder","ordinal":60,"logo_url":"assets/mainconcept.svg","images":["linode/ubuntu22.04"],"deployments_total":1,"deployments_active":0,"is_public":true,"mine":false,"created":"2023-09-28T15:05:01","updated":"2023-12-07T16:54:44","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## MainConcept P2 AVC Ultra Transcoder Demo Settings\n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-p2-avc-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n mc_port: ${MC_PORT}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"No domain entered\";\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"mc_port","label":"MainConcept P2 AVC Ultra Transcoder API Port","example":"Default: 8080","default":"8080"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"soa_email_address","label":"Email address for domain SOA. REQUIRED for DNS","example":"user@domain.tld","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":1243763,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MainConcept XAVC Transcoder Demo One-Click","description":"MainConcept XAVC Transcoder","ordinal":61,"logo_url":"assets/mainconcept.svg","images":["linode/ubuntu22.04"],"deployments_total":2,"deployments_active":0,"is_public":true,"mine":false,"created":"2023-09-28T15:05:47","updated":"2023-12-06T21:20:30","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## MainConcept XAVC Transcoder Demo Settings\n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-xavc-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n mc_port: ${MC_PORT}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"No domain entered\";\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"mc_port","label":"MainConcept XAVC Transcoder API Port","example":"Default: 8080","default":"8080"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"soa_email_address","label":"Email address for domain SOA. REQUIRED for DNS","example":"user@domain.tld","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":1243764,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MainConcept XDCAM Transcoder Demo One-Click","description":"MainConcept XDCAM Transcoder","ordinal":62,"logo_url":"assets/mainconcept.svg","images":["linode/ubuntu22.04"],"deployments_total":1,"deployments_active":0,"is_public":true,"mine":false,"created":"2023-09-28T15:06:28","updated":"2023-12-06T21:21:16","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## MainConcept XDCAM Transcoder Demo Settings\n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-mc-xdcam-demo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n mc_port: ${MC_PORT}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n \n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"No domain entered\";\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"mc_port","label":"MainConcept XDCAM Transcoder API Port","example":"Default: 8080","default":"8080"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"soa_email_address","label":"Email address for domain SOA. REQUIRED for DNS","example":"user@domain.tld","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":1096122,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Mastodon One-Click","description":"Mastodon is an open-source and decentralized micro-blogging platform, supporting federation and public access to the server.","ordinal":63,"logo_url":"assets/mastodon.svg","images":["linode/debian11"],"deployments_total":1696,"deployments_active":62,"is_public":true,"mine":false,"created":"2022-12-05T15:57:04","updated":"2023-12-11T21:43:20","rev_note":"","script":"#!/bin/bash\nset -x\n## Mastodon Settings\n#\n#\n#\n#\n#\n#\n\n\n# git repo + workdirs\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/mastodon-oca.git\"\nexport WORK_DIR=\"/tmp/oca-deployment\"\nexport LINODE_API_TOKEN=\"${TOKEN_PASSWORD}\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nsource \n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n}\n\nfunction setup {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip python3-dev build-essential\n\n #clone repo and set up ansible environment\n mkdir -p ${WORK_DIR}\n cd ${WORK_DIR}\n git clone $GIT_REPO\n cd mastodon-oca\n\n # write udf vars\n cat < group_vars/mastodon/vars\n domain: ${DOMAIN}\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n owner_username: ${OWNER_USERNAME}\n owner_email: ${OWNER_EMAIL}\n single_user_mode: ${SINGLE_USER_MODE}\nEND\n\n #venv\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n}\n\nfunction run {\n# run playbooks\n ansible-playbook -v site.yml\n}\n\n# main\nsetup\nrun\ncleanup\necho \"Installation Complete!\"","user_defined_fields":[{"name":"domain","label":"Domain name for your Mastodon instance.","example":"domain.tld"},{"name":"token_password","label":"Your Linode API token"},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"owner_username","label":"Username for Mastodon Owner","example":""},{"name":"owner_email","label":"Email address for Mastodon Owner","example":"owner@example.com"},{"name":"single_user_mode","label":"Do you want to start Mastodon in single-user mode?","oneof":"Yes,No"}]},{"id":611895,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MEAN One-Click","description":"MEAN One-Click","ordinal":64,"logo_url":"assets/mean.svg","images":["linode/ubuntu20.04"],"deployments_total":726,"deployments_active":36,"is_public":true,"mine":false,"created":"2019-11-14T04:49:44","updated":"2023-12-06T14:01:30","rev_note":"Initial import","script":"#!/usr/bin/env bash\n\n## MEAN Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction dependmean {\n apt-get install -y build-essential git fontconfig libpng-dev ruby ruby-dev wget gnupg\n gem install sass\n}\n\nfunction mongoinstall {\n cd && wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\n if [ \"${detected_distro[distro]}\" = 'debian' ]; then \n echo \"deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\n elif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\n else \n echo \"Setting this up for the future incase we add more distros\"\n fi\n apt-get update -y\n apt-get install -y mongodb-org\n systemctl enable mongod.service\n systemctl start mongod.service\n}\n\n\nfunction meaninstall {\n apt-get install -y curl software-properties-common\n curl -fsSL https://deb.nodesource.com/setup_16.x | bash -\n apt-get install -y nodejs\n\n # MEAN APP CONFIGURATION\n cd && mkdir -p /opt/mean\n cd /opt/mean\n cat <> package.json\n{\n\"name\" : \"mean\",\n\"version\": \"0.0.1\"\n}\nEND\n npm install express --save\n npm install angular\n cat <> server.js\nvar express = require('express');\nvar app = express();\nvar port = 3000;\napp.get('/', function(req, res) {\nres.send('Hello World Powered By: Linode Marketplace');\n});\napp.listen(port, function(){\nconsole.log(\"Listening at port: \" + port);\n})\nEND\n # Start App on reboot\n cd && npm install pm2 -g\n pm2 start --name=\"MEAN_APP\" /opt/mean/server.js\n pm2 startup \n pm2 save\n}\n\nfunction nginxmean {\n apt-get install nginx -y \n cat < /etc/nginx/sites-available/$FQDN\nserver {\n server_name $FQDN www.$FQDN;\n location / {\n proxy_pass http://localhost:3000;\n proxy_http_version 1.1;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection 'upgrade';\n proxy_set_header Host \\$host;\n proxy_cache_bypass \\$http_upgrade;\n }\n}\nEND\n ln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/\n unlink /etc/nginx/sites-enabled/default\n nginx -t\n systemctl reload nginx\n}\n\nfunction sslmean {\n apt install certbot python3-certbot-nginx -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction firewallmean {\n ufw allow http\n ufw allow https\n}\n\nfunction main {\n dependmean\n firewallmean\n mongoinstall\n meaninstall\n nginxmean\n sslmean\n\n}\n\n# execute script\nmain\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address for SSL certificate"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":401702,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MERN One-Click","description":"MERN One-Click","ordinal":65,"logo_url":"assets/MERN.svg","images":["linode/debian10","linode/ubuntu20.04","linode/debian11"],"deployments_total":1433,"deployments_active":58,"is_public":true,"mine":false,"created":"2019-03-08T21:07:40","updated":"2023-12-10T12:50:08","rev_note":"","script":"#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 3000\nfail2ban_install\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install dependencies\napt-get install -y build-essential git \n\n# Install Mongodb\napt-get install -y wget gnupg\nwget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \necho \"deb http://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\necho \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\napt-get update -y\napt-get install -y mongodb-org\nsystemctl enable mongod.service\nsystemctl start mongod.service\n\n# Install NodeJS and NPM\napt-get install -y curl software-properties-common\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \ncurl -fsSL https://deb.nodesource.com/setup_16.x | bash -\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\ncurl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -\nelse \necho \"Setting this up for the future incase we add more distros\"\nfi\napt-get install -y nodejs\n\n# Install ExpressJS\nnpm update -g\nnpm install --global express\nnpm link express\nnpm -g install create-react-app\ncd /opt\ncreate-react-app hello-world\nnpm i --package-lock-only\nnpm audit fix\n\n# Start App on reboot\ncat < /lib/systemd/system/hello-world.service\n[Unit]\nDescription=Hello World React Application Service\nRequires=hello-world.service\nAfter=hello-world.service\n\n[Service]\nType=simple\nUser=root\nRemainAfterExit=yes\nRestart=on-failure\nWorkingDirectory=/opt/hello-world\nExecStart=npm start --host 0.0.0.0 --port=3000\n\n[Install]\nWantedBy=multi-user.target\nEND\n\nsystemctl daemon-reload\nsystemctl start hello-world\nsystemctl enable hello-world\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":1051714,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Microweber One-Click","description":"Microweber One-Click","ordinal":66,"logo_url":"assets/microweber.svg","images":["linode/ubuntu20.04"],"deployments_total":478,"deployments_active":21,"is_public":true,"mine":false,"created":"2022-09-01T15:43:41","updated":"2023-12-09T11:00:07","rev_note":"","script":"#!/usr/bin/env bash\n# https://github.com/microweber/microweber\nset -o pipefail\nMICROWEBER_INSTALLER_TAG=\"1.3.1\"\nWORKING_DIR=\"/var/www/html\"\nDOWNLOAD_URL='http://updater.microweberapi.com/builds/master/microweber.zip'\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## 03-force-ssh-logout.sh\ncat >>/etc/ssh/sshd_config </dev/null\napt install -y apache2 libapache2-mod-php8.1\napt install -y mysql-server\napt install -y php8.1-{bcmath,xml,fpm,mysql,iconv,xsl,zip,intl,ldap,gd,cli,dev,bz2,curl,exif,mbstring,pgsql,sqlite3,tokenizer,opcache,soap,cgi,common,imap,opcache}\napt install -y python3-certbot-apache software-properties-common unzip curl\napt install -y php-pear\npecl install -f libsodium\nsed -i 's/;opcache.enable\\s*=.*/opcache.enable=1/g' /etc/php/8.1/cli/php.ini\necho 'extension=sodium.so' > /etc/php/8.1/cli/10-sodium.ini\necho 'extension=sodium.so' > /etc/php/8.1/fpm/10-sodium.ini\necho 'extension=sodium.so' > /etc/php/8.1/cgi/10-sodium.ini\n# 01-fs.sh\ncat >/etc/apache2/sites-available/000-default.conf <\n \n Options Indexes FollowSymLinks\n AllowOverride All\n Require all granted\n \n ServerAdmin webmaster@localhost\n DocumentRoot /var/www/html\n ErrorLog \\${APACHE_LOG_DIR}/error.log\n CustomLog \\${APACHE_LOG_DIR}/access.log combined\n\nEOM\ncat >/etc/update-motd.d/99-one-click < certbot --apache -d example.com -d www.example.com\nIMPORTANT:\n * After connecting to the server for the first time, immediately install\n Microweber at http://\\$myip/\n * Secure your database by running:\n > mysql_secure_installation\nFor help and more information visit https://microweber.org\n********************************************************************************\nTo delete this message of the day: rm -rf \\$(readlink -f \\${0})\nEOF\nEOM\nchmod +x /etc/update-motd.d/99-one-click\ncat >/etc/cron.d/microweber </etc/php/8.1/apache2/conf.d/30-microweber.ini <>/var/log/per-instance.log\nMYSQL_ROOT_PASS=$(openssl rand -hex 16)\nDEBIAN_SYS_MAINT_MYSQL_PASS=$(openssl rand -hex 16)\nMICROWEBER_DB_HOST=localhost\nMICROWEBER_DB_PORT=3306\nMICROWEBER_DB_NAME=microweber\nMICROWEBER_DB_USER=microweber\nMICROWEBER_DB_PASS=$(openssl rand -hex 16)\ncat >/root/.mysql_password <>/etc/apache2/envvars </etc/mysql/debian.cnf <>/var/log/per-instance.log\necho \"[OK] Microweber Installer $MICROWEBER_INSTALLER_TAG provisioned!\"","user_defined_fields":[]},{"id":691614,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Mist.io One-Click","description":"Mist.io One-Click","ordinal":67,"logo_url":"assets/mistio.svg","images":["linode/debian10"],"deployments_total":326,"deployments_active":1,"is_public":true,"mine":false,"created":"2020-11-30T20:25:44","updated":"2023-12-12T12:08:07","rev_note":"","script":"#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# apt-get updates\n echo 'Acquire::ForceIPv4 \"true\";' > /etc/apt/apt.conf.d/99force-ipv4\n export DEBIAN_FRONTEND=noninteractive\n apt-get update -y\n\n# \n\n# \n\n## install docker\nsudo apt-get install -y \\\n apt-transport-https \\\n ca-certificates \\\n curl \\\n gnupg-agent \\\n software-properties-common\n\ncurl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -\n\nsudo add-apt-repository \\\n \"deb [arch=amd64] https://download.docker.com/linux/debian \\\n $(lsb_release -cs) \\\n stable\"\n\nsudo apt-get update\n\nsudo apt-get install -y docker-ce docker-ce-cli containerd.io\n\n## install docker-compose\nsudo curl -L \"https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose\n\nsudo chmod +x /usr/local/bin/docker-compose\n\n## get latest mist\nmkdir ~/mist && cd ~/mist\n\nexport MIST_CE_REPO=https://github.com/mistio/mist-ce/releases/latest\nexport LATEST_TAG=\"$(curl -sI \"${MIST_CE_REPO}\" | grep -Po 'tag\\/\\K(v\\S+)')\"\n\nwget https://github.com/mistio/mist-ce/releases/download/$LATEST_TAG/docker-compose.yml\n\n# set CORE_URI\nmkdir settings\nexport IP=$(ip r | grep /24 | grep -Eo \"([0-9]{1,3}[\\.]){3}[1-9]{1,3}\")\necho 'CORE_URI=\"http://'$IP'\"' > settings/settings.py\n\ndocker-compose up -d\n\nwhile !(curl -sSLf http://localhost >/dev/null); do\n sleep 5\ndone\n\ndocker-compose exec -T api ./bin/adduser --admin \"${MIST_EMAIL}\" --password \"${MIST_PASSWORD}\"","user_defined_fields":[{"name":"mist_email","label":"Mist admin user's email.","example":"Set your admin user's email."},{"name":"mist_password","label":"Mist admin user's password.","example":"Set your admin user's password."}]},{"id":609195,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MongoDB One-Click","description":"MongoDB One-Click","ordinal":68,"logo_url":"assets/mongodb.svg","images":["linode/ubuntu20.04","linode/debian11"],"deployments_total":1757,"deployments_active":78,"is_public":true,"mine":false,"created":"2019-11-06T07:14:07","updated":"2023-10-18T12:38:33","rev_note":"","script":"#!/bin/bash\n## Mongo Settings\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction mongoinstall {\n apt-get install -y wget gnupg\n if [ $MONGOVERSION == \"5.0\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/5.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-5.0.list\n elif [ $MONGOVERSION == \"4.4\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list\n elif [ $MONGOVERSION == \"4.2\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.2 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.2.list\n elif [ $MONGOVERSION == \"4.0\" ]; then\n wget -qO - https://www.mongodb.org/static/pgp/server-4.0.asc | sudo apt-key add -\n echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list\n fi\n\n apt-get update -y\n apt-get install -y mongodb-org\n systemctl enable mongod.service\n systemctl start mongod.service\n}\n\nfunction createmongouser {\n echo \"Creating Mongo User\" & sleep 3\n mongo < /etc/mongod.conf\n# mongod.conf\n# for documentation of all options, see:\n# http://docs.mongodb.org/manual/reference/configuration-options/\n# Where and how to store data.\nstorage:\n dbPath: /var/lib/mongodb\n journal:\n enabled: true\n# engine:\n# wiredTiger:\n# where to write logging data.\nsystemLog:\n destination: file\n logAppend: true\n path: /var/log/mongodb/mongod.log\n# network interfaces\nnet:\n port: 27017\n bindIp: 127.0.0.1\n# how the process runs\nprocessManagement:\n timeZoneInfo: /usr/share/zoneinfo\nsecurity:\n authorization: enabled\n#operationProfiling:\n#replication:\n#sharding:\n## Enterprise-Only Options:\n#auditLog:\n#snmp:\nEOF\n service mongod restart\n}\n\nfunction main {\n mongoinstall\n createmongouser \n setauth\n}\n\nmain\nstackscript_cleanup","user_defined_fields":[{"name":"db_password","label":"Mongo Password"},{"name":"mongoversion","label":"Mongo Version","oneof":"5.0,4.4,4.2,4.0","default":"5.0"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address for soa record","default":""}]},{"id":1067004,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MongoDB Cluster One-Click","description":"MongoDB replica set","ordinal":69,"logo_url":"assets/mongodbmarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":49,"deployments_active":0,"is_public":true,"mine":false,"created":"2022-09-29T18:32:36","updated":"2023-10-18T12:38:33","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\nexport GIT_PAT=\"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\"\nexport GIT_REPO=\"https://linode-solutions:${GIT_PAT}@github.com/linode-solutions/mongodb-occ.git\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/mongodb-cluster\" ]; then\n rm -rf /tmp/mongodb-cluster\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction destroy_linode {\n curl -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X DELETE \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction add_privateip {\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[+] Linode private IP present\"\n else\n echo \"[!] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[+] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction setup {\n # install dependancies\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # Rename Provisioner & add Private IP \n rename_provisioner\n configure_privateip \n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/mongodb-cluster\n cd /tmp/mongodb-cluster\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"","user_defined_fields":[{"name":"token_password","label":"Your Linode API token"},{"name":"sudo_username","label":"The limited sudo user to be created in the cluster"},{"name":"cluster_name","label":"Domain Name"},{"name":"add_ssh_keys","label":"Add Account SSH Keys to All Nodes?","oneof":"yes,no","default":"yes"},{"name":"sslheader","label":"SSL Information","header":"Yes","default":"Yes","required":"Yes"},{"name":"country_name","label":"Details for self-signed SSL certificates: Country or Region","oneof":"AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW"},{"name":"state_or_province_name","label":"State or Province","example":"Example: Pennsylvania"},{"name":"locality_name","label":"Locality","example":"Example: Philadelphia"},{"name":"organization_name","label":"Organization","example":"Example: Akamai Technologies"},{"name":"email_address","label":"Email Address","example":"Example: user@domain.tld"},{"name":"ca_common_name","label":"CA Common Name","default":"Mongo CA"},{"name":"common_name","label":"Common Name","default":"Mongo Server"},{"name":"cluster_size","label":"MongoDB cluster size","default":"3","oneof":"3"}]},{"id":869127,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Moodle One-Click","description":"Moodle One-Click","ordinal":70,"logo_url":"assets/moodle.svg","images":["linode/ubuntu20.04"],"deployments_total":1304,"deployments_active":102,"is_public":true,"mine":false,"created":"2021-07-20T18:48:49","updated":"2023-12-12T02:13:31","rev_note":"","script":"#!/usr/bin/env bash\n\n### UDF Variables\n## Moodle settings\n#\n#\n#\n#\n\n## Domain settings\n#\n#\n#\n\n## Linode/SSH Security Settings \n#\n#\n\n## Linode/SSH Settings - Optional\n#\n#\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n# System Update\nsystem_update\n\n# Install dependencies \napt install -y apache2 mysql-client mysql-server php libapache2-mod-php git graphviz aspell ghostscript clamav php7.4-pspell php7.4-curl php7.4-gd php7.4-intl php7.4-mysql php7.4-xml php7.4-xmlrpc php7.4-ldap php7.4-zip php7.4-soap php7.4-mbstring\n\n# Firewall\nufw allow http \nufw allow https\n\n# Secure MySQL\nrun_mysql_secure_installation_ubuntu20\n\n# Install Moodle\ncd /var/www/html\ngit clone git://git.moodle.org/moodle.git\ncd moodle\ngit branch --track MOODLE_39_STABLE origin/MOODLE_39_STABLE\ngit checkout MOODLE_39_STABLE\n\n# Configure Moodle\nmkdir /var/moodledata\nchmod -R 777 /var/moodledata \nchmod -R 755 /var/www/html/moodle \n\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"CREATE DATABASE moodle DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\"\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"CREATE USER 'moodle'@'localhost' IDENTIFIED BY '$DB_PASSWORD';\";\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,CREATE TEMPORARY TABLES,DROP,INDEX,ALTER ON moodle.* TO 'moodle'@'localhost';\"\nmysql -uroot -p\"$DBROOT_PASSWORD\" -e \"FLUSH PRIVILEGES\";\n\ncat < /etc/apache2/sites-available/moodle.conf\n\n ServerAdmin admin@$FQDN\n DocumentRoot /var/www/html/moodle/\n ServerName $FQDN\n ServerAlias www.$FQDN \n \n Options +FollowSymlinks\n AllowOverride All\n Require all granted\n \n ErrorLog \\${APACHE_LOG_DIR}/error.log\n CustomLog \\${APACHE_LOG_DIR}/access.log combined\n\nEND\n\na2enmod rewrite\na2ensite moodle.conf\na2dissite 000-default.conf\nservice apache2 restart\n\napt install certbot python3-certbot-apache -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\n/usr/bin/php admin/cli/install.php --chmod=777 --lang=en_us --wwwroot=https://$FQDN --dataroot=/var/moodledata/ --dbtype=mysqli --dbhost=localhost --dbname=moodle --dbuser=moodle --dbpass=$DB_PASSWORD --dbport=3306 --dbsocket=1 --prefix=mdl_ --fullname=moodle --shortname=moodle --summary=\"Moodle: Powered By Linode Marketplace\" --adminuser=moodle --adminpass=\"$ADMIN_PASSWORD\" --adminemail=$SOA_EMAIL_ADDRESS --upgradekey= --non-interactive --agree-license\n\nchown -R www-data: /var/www/html/moodle\n\n# Clean up\nstackscript_cleanup","user_defined_fields":[{"name":"admin_password","label":"Moodle Admin Password"},{"name":"soa_email_address","label":"Moodle Admin Email"},{"name":"dbroot_password","label":"MySQL Root Password"},{"name":"db_password","label":"Moodle database User password"},{"name":"token_password","label":"Your Linode API token. This is required in order to create DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"username","label":"The username for the Linode's admin/SSH user (Please ensure that the username entered does not contain any uppercase characters)","example":"user1"},{"name":"password","label":"The password for the Linode's admin/SSH user","example":"S3cuReP@s$w0rd"},{"name":"pubkey","label":"The SSH Public Key used to securely access the Linode via SSH","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":607026,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"MySQL/MariaDB One-Click","description":"MySql One Click","ordinal":71,"logo_url":"assets/mysql.svg","images":["linode/ubuntu20.04"],"deployments_total":4605,"deployments_active":335,"is_public":true,"mine":false,"created":"2019-10-29T19:03:33","updated":"2023-12-11T19:45:23","rev_note":"Initial import","script":"#!/usr/bin/env bash\n\n## MySQL Settings\n#\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 3306\nfail2ban_install\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\nif [[ \"$DATABASE\" == \"MySQL\" ]]; then\n # Install/configure MySQL\n apt install -y mysql-server\n # Secure MySQL install\n run_mysql_secure_installation_ubuntu20 \nelse \n # Install/configure MySQL\n apt install -y mariadb-server\n # Secure MySQL install\n run_mysql_secure_installation\nfi\n\nmysql -uroot -p$DBROOT_PASSWORD -e \"create database $DATABASE_NAME;\"\nmysql -uroot -p$DBROOT_PASSWORD -e \"CREATE USER '$DBUSER' IDENTIFIED BY '$DBUSER_PASSWORD';\"\nmysql -uroot -p$DBROOT_PASSWORD -e \"GRANT ALL PRIVILEGES ON $DATABASE_NAME.* TO '$DBUSER'@'%' WITH GRANT OPTION;\"\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"database","label":"Would you like to install MySQL or MariaDB?","oneof":"MySQL,MariaDB"},{"name":"dbroot_password","label":"MySQL Root Password","example":"s3cur3_9a55w04d"},{"name":"dbuser","label":"MySQL User","example":"user1"},{"name":"dbuser_password","label":"MySQL User Password","example":"s3cur3_9a55w04d"},{"name":"database_name","label":"Create Database","example":"testdb"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":970561,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"NodeJS One-Click","description":"NodeJS One-Click","ordinal":72,"logo_url":"assets/nodejs.svg","images":["linode/ubuntu20.04"],"deployments_total":2158,"deployments_active":264,"is_public":true,"mine":false,"created":"2022-02-07T17:21:41","updated":"2023-12-12T10:17:05","rev_note":"","script":"#!/usr/bin/env bash\n\n## NodeJS Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction nodejs {\n if [ \"${detected_distro[distro]}\" = 'debian' ]; then \n curl -fsSL https://deb.nodesource.com/setup_16.x | bash -\n elif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\n curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -\n else \n echo \"Setting this up for the future incase we add more distros\"\n fi\n apt-get install -y nodejs\n \n mkdir -p /opt/nodejs\n cat < /opt/nodejs/hello.js\nconst http = require('http');\n\nconst hostname = 'localhost';\nconst port = 3000;\n\nconst server = http.createServer((req, res) => {\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/plain');\n res.end('Hello World Powered By Linode Marketplace');\n});\n\nserver.listen(port, hostname, () => {\n console.log(`Server running at http://localhost:3000/`);\n});\nEND\n}\n\nfunction pm2nodejs {\n npm install pm2@latest -g --no-audit\n cd /opt/nodejs/\n pm2 start hello.js\n sleep 5\n pm2 startup systemd\n sleep 5\n pm2 save\n}\n\nfunction nginxnodejs {\n apt-get install nginx -y \n cat < /etc/nginx/sites-available/$FQDN\nserver {\n server_name $FQDN www.$FQDN;\n\n location / {\n proxy_pass http://localhost:3000;\n proxy_http_version 1.1;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection 'upgrade';\n proxy_set_header Host \\$host;\n proxy_cache_bypass \\$http_upgrade;\n }\n\n}\nEND\n ln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/\n unlink /etc/nginx/sites-enabled/default\n nginx -t\n systemctl reload nginx\n}\n\nfunction sslnodejs {\n apt install certbot python3-certbot-nginx -y\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction firewallnodejs {\n ufw allow http\n ufw allow https\n\n}\nfunction main {\n nodejs\n pm2nodejs\n firewallnodejs \n nginxnodejs \n sslnodejs \n}\n\n# Execute Script\nmain\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"This is the Email address for the LetsEncrypt SSL Certificate","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":869156,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"NirvaShare One-Click","description":"NirvaShare One-Click","ordinal":73,"logo_url":"assets/nirvashare.svg","images":["linode/ubuntu22.04"],"deployments_total":216,"deployments_active":3,"is_public":true,"mine":false,"created":"2021-07-20T19:08:35","updated":"2023-12-06T21:21:49","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Nirvashare Settings \n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-nirvashare\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n}\n\nfunction udf {\n \n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # Nirvashare \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"}]},{"id":971043,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Odoo One-Click","description":"Odoo One-Click","ordinal":74,"logo_url":"assets/odoo.svg","images":["linode/ubuntu22.04"],"deployments_total":1836,"deployments_active":90,"is_public":true,"mine":false,"created":"2022-02-08T16:21:37","updated":"2023-12-12T15:08:11","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## ODOO Settings \n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-odoo\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # ODOO vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"}]},{"id":1102907,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"ONLYOFFICE Docs One-Click","description":"ONLYOFFICE Docs One-Click app","ordinal":75,"logo_url":"assets/onlyoffice.svg","images":["linode/ubuntu22.04"],"deployments_total":291,"deployments_active":13,"is_public":true,"mine":false,"created":"2022-12-20T17:50:23","updated":"2023-12-02T15:29:24","rev_note":"","script":"#!/usr/bin/env bash\n# \n# \n# \n\n# SSL Settings\n# \n# \n# \n# \n\n# Enable Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n\n## Register default rDNS \nexport DEFAULT_RDNS=$(dnsdomainname -A | awk '{print $1}')\n\n#set absolute domain if any, otherwise use DEFAULT_RDNS\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DEFAULT_RDNS\"\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n\n# Get and install docker\n# curl -fsSL get.docker.com | sudo sh\napt install -y apt-transport-https ca-certificates curl software-properties-common\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg\necho \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null \napt update\napt install -y docker-ce\nsystemctl enable --now docker.service\n\nCONTAINER_NAME=\"onlyoffice-docs\"\n\n# Run ONLYOFFICE-Docs with SSL\nif [[ \"${SSL_ENABLED}\" == \"true\" ]]; then\n\tif [[ -z ${ABS_DOMAIN} ]]; then\n\t\techo \"Missing required LETS_ENCRYPT_DOMAIN parameter for correct SSL work\"\n\t\texit 1\n\tfi\n\tif [[ -z ${LETS_ENCRYPT_MAIL} ]]; then\n\t\techo \"Missing required LETS_ENCRYPT_MAIL parameter for correct SSL work\"\n\t\texit 1\n fi\n\tsudo docker run -i -t -d -p 80:80 -p 443:443 \\\n\t\t-e JWT_ENABLED=${JWT_ENABLED} \\\n \t\t-e JWT_SECRET=${JWT_SECRET} \\\n\t\t-e LETS_ENCRYPT_DOMAIN=${ABS_DOMAIN} \\\n -e LETS_ENCRYPT_MAIL=${LETS_ENCRYPT_MAIL} \\\n\t\t-v /app/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \\\n\t\t-v /app/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \\\n \t-v /app/onlyoffice/DocumentServer/lib:/var/lib/onlyoffice \\\n \t-v /app/onlyoffice/DocumentServer/rabbitmq:/var/lib/rabbitmq \\\n \t-v /app/onlyoffice/DocumentServer/redis:/var/lib/redis \\\n \t-v /app/onlyoffice/DocumentServer/db:/var/lib/postgresql \\\n\t\t--name ${CONTAINER_NAME} \\\n\t\tonlyoffice/documentserver:${DOCS_VERSION}\n\telse \n# Run ONLYOFFICE-Docs without SSL\n\tsudo docker run -i -t -d -p 80:80 \\\n -e JWT_ENABLED=${JWT_ENABLED} \\\n -e JWT_SECRET=${JWT_SECRET} \\\n -v /app/onlyoffice/DocumentServer/logs:/var/log/onlyoffice \\\n -v /app/onlyoffice/DocumentServer/data:/var/www/onlyoffice/Data \\\n -v /app/onlyoffice/DocumentServer/lib:/var/lib/onlyoffice \\\n -v /app/onlyoffice/DocumentServer/rabbitmq:/var/lib/rabbitmq \\\n -v /app/onlyoffice/DocumentServer/redis:/var/lib/redis \\\n -v /app/onlyoffice/DocumentServer/db:/var/lib/postgresql \\\n --name ${CONTAINER_NAME} \\\n onlyoffice/documentserver:${DOCS_VERSION}\nfi\n\n# Wait for run\nready_check() {\n echo -e \"\\e[0;32m Waiting for the launch of DocumentServer... \\e[0m\" \n for i in {1..30}; do\n echo \"Getting the DocumentServer status: ${i}\"\n OUTPUT=\"$(curl -Is http://localhost/healthcheck/ | head -1 | awk '{ print $2 }')\"\n if [ \"${OUTPUT}\" == \"200\" ]; then\n echo -e \"\\e[0;32m DocumentServer is ready \\e[0m\"\n local DS_READY\n DS_READY='yes'\n break\n else\n sleep 10\n fi\n done\n if [[ \"${DS_READY}\" != 'yes' ]]; then\n err \"\\e[0;31m Something goes wrong documentserver does not started, check logs with command --> docker logs -f ${CONTAINER_NAME} \\e[0m\"\n exit 1\n fi\n}\n\nready_check\n\n# Enable Docs-example\nsudo docker exec ${CONTAINER_NAME} supervisorctl start ds:example\n\n# Add Docs-example to autostart\nsudo docker exec ${CONTAINER_NAME} sudo sed 's,autostart=false,autostart=true,' -i /etc/supervisor/conf.d/ds-example.conf\n\n# Add MOTD \ncat >/etc/motd < >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n### Install OpenLiteSpeed and Django\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/djangosetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )\n### Reboot server\nreboot","user_defined_fields":[]},{"id":923031,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"OpenLiteSpeed NodeJS One-Click","description":"OpenLiteSpeed NodeJS One-Click","ordinal":77,"logo_url":"assets/openlitespeednodejs.svg","images":["linode/centos7","linode/debian10","linode/ubuntu20.04","linode/debian11","linode/ubuntu22.04"],"deployments_total":500,"deployments_active":19,"is_public":true,"mine":false,"created":"2021-10-18T00:52:51","updated":"2023-12-08T12:05:05","rev_note":"","script":"#!/bin/bash\n### linode\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n### Install OpenLiteSpeed and NodeJS\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/nodejssetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )","user_defined_fields":[]},{"id":923030,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"OpenLiteSpeed Rails One-Click","description":"OpenLiteSpeed Rails One-Click","ordinal":78,"logo_url":"assets/openlitespeedrails.svg","images":["linode/centos7","linode/debian10","linode/ubuntu20.04","linode/debian11","linode/ubuntu22.04"],"deployments_total":51,"deployments_active":0,"is_public":true,"mine":false,"created":"2021-10-18T00:51:05","updated":"2023-12-09T06:40:57","rev_note":"","script":"#!/bin/bash\n### linode\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n### Install OpenLiteSpeed and Rails\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/railssetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )","user_defined_fields":[]},{"id":691622,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"OpenLiteSpeed WordPress One-Click","description":"OpenLiteSpeed WordPress One-Click","ordinal":79,"logo_url":"assets/openlitespeedwordpress.svg","images":["linode/centos7","linode/debian10","linode/ubuntu20.04","linode/debian11","linode/ubuntu22.04"],"deployments_total":7991,"deployments_active":633,"is_public":true,"mine":false,"created":"2020-11-30T21:25:01","updated":"2023-12-12T06:54:23","rev_note":"","script":"#!/bin/bash\n\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n### linode\n### Install OpenLiteSpeed and WordPress\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Setup/wpimgsetup.sh )\n### Regenerate password for Web Admin, Database, setup Welcome Message\nbash <( curl -sk https://raw.githubusercontent.com/litespeedtech/ls-cloud-image/master/Cloud-init/per-instance.sh )\n### Clean up ls tmp folder\nsudo rm -rf /tmp/lshttpd/*","user_defined_fields":[]},{"id":401719,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"OpenVPN One-Click","description":"OpenVPN OCA Debian 11 & ubuntu 20","ordinal":80,"logo_url":"assets/OpenVPN.svg","images":["linode/ubuntu20.04","linode/debian11"],"deployments_total":40352,"deployments_active":1664,"is_public":true,"mine":false,"created":"2019-03-09T03:02:02","updated":"2023-12-12T15:29:16","rev_note":"Install extra dependencies ","script":"#!/bin/bash\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Install OpenVPN dependencies\napt update && apt -y install ca-certificates wget net-tools gnupg\nif [ \"${detected_distro[distro]}\" = 'debian' ]; then \nwget -qO - https://as-repository.openvpn.net/as-repo-public.gpg | apt-key add -\necho \"deb http://as-repository.openvpn.net/as/debian bullseye main\">/etc/apt/sources.list.d/openvpn-as-repo.list\nelif [ \"${detected_distro[distro]}\" = 'ubuntu' ]; then\nwget -qO - https://as-repository.openvpn.net/as-repo-public.gpg | apt-key add -\necho \"deb http://as-repository.openvpn.net/as/debian focal main\">/etc/apt/sources.list.d/openvpn-as-repo.list\nelse \necho \"Distro Not Supported\"\nfi\n\n## Apt Update & Install OpenVPN\napt update -y && apt -y install openvpn-as\n\n# UFW install\nufw_install\nufw allow 1194/udp\nsed -ie \"s/DEFAULT_FORWARD_POLICY=\\\"DROP\\\"/DEFAULT_FORWARD_POLICY=\\\"ACCEPT\\\"/g\" /etc/default/ufw\n\n# Cleanup\nstackscript_cleanup\n\n# Adding to display default password as last line in LISH console\nsleep 3\ncat /usr/local/openvpn_as/init.log | grep 'To login'; echo \"(password can be changed on Admin UI)\"","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is required for creating DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"soa_email_address","label":"Admin Email for the server","default":""}]},{"id":804172,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Owncast One-Click","description":"Owncast One-Click","ordinal":81,"logo_url":"assets/owncast.svg","images":["linode/debian10"],"deployments_total":1801,"deployments_active":84,"is_public":true,"mine":false,"created":"2021-04-01T15:24:50","updated":"2023-12-12T02:12:06","rev_note":"","script":"#!/usr/bin/bash\n#\n#\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Add owncast user\nadduser owncast --disabled-password --gecos \"\"\n\n# Install dependencies\napt-get install -y libssl-dev unzip curl\n\n# Install Owncast\nmkdir -p /opt/owncast\ncd /opt/owncast || exit\n\ncurl -s https://owncast.online/install.sh | bash\nchown -R owncast:owncast /opt/owncast\n\n# Setup Owncast as a systemd service\ncat >/etc/systemd/system/owncast.service </etc/caddy/Caddyfile </etc/motd <\n#\n#\n## LAMP Stack Settings\n#\n#\n#\n#\n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n\n# This also sets some useful variables, like $IP and $FQDN\nsource \n\n## Update\napt_setup_update\n\n## Local Functions used by this StackScript\nfunction owncloud_install {\n system_install_package unzip php-gd php-json php-curl php-mbstring \\\n php-intl php-imagick php-xml php-zip\n PHP_VERSION=$(php -r \"echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;\")\n cd /var/www\n wget https://download.owncloud.com/server/stable/owncloud-complete-latest.zip\n unzip owncloud-complete-latest.zip\n chown -R www-data:www-data owncloud\n rm owncloud-complete-latest.zip\n local -a input_text=(\n \"Alias / \\\"/var/www/owncloud/\\\"\"\n \"\"\n \" Options +FollowSymlinks\"\n \" AllowOverride All\"\n \"\"\n \" Dav off\"\n \"\"\n \"SetEnv HOME /var/www/owncloud\"\n \"SetEnv HTTP_HOME /var/www/owncloud\"\n \"\"\n )\n for i in \"${input_text[@]}\"; do\n echo \"$i\" >> /etc/apache2/sites-available/owncloud.conf\n done\n a2ensite owncloud\n a2enmod rewrite headers env dir mime\n sed -i '/^memory_limit =/s/=.*/= 512M/' /etc/php/$PHP_VERSION/apache2/php.ini\n systemctl restart apache2\n echo \"ownCloud is installed\"\n}\n\nfunction owncloud_vhost_configure {\n local -r fqdn=\"$1\"\n local -r soa_email_address=\"$2\"\n local -a input_text=(\n \"\"\n \" ServerName ${fqdn}\"\n \" ServerAdmin ${soa_email_address}\"\n \" DocumentRoot /var/www/owncloud\"\n \" \"\n \" Require all granted\"\n \" AllowOverride All\"\n \" Options FollowSymLinks MultiViews\"\n \" SetEnv HOME /var/www/owncloud\"\n \" SetEnv HTTP_HOME /var/www/owncloud\"\n \" \"\n \"\"\n )\n echo \"\" >> /etc/apache2/sites-available/owncloud.conf\n for i in \"${input_text[@]}\"; do\n echo \"$i\" >> /etc/apache2/sites-available/owncloud.conf\n done\n}\n\n## Main Script\n# Install and configure the LAMP Stack\nlamp_stack \"$DB_NAME\" \"$DB_ROOT_PASSWORD\" \"${DB_USERNAME:-owncloud}\" \"$DB_USER_PASSWORD\"\n\n# Install ownCloud to be accessed via domain and configure the VirtualHost\nowncloud_install \"$FQDN\"\nowncloud_vhost_configure \"$FQDN\" \"$SOA_EMAIL_ADDRESS\"\n\n# Configure ownCloud - This replaces the installer GUI that was in the previous version of this OCA\nsudo -u www-data php /var/www/owncloud/occ maintenance:install \\\n --database \"mysql\" \\\n --database-name \"$DB_NAME\" \\\n --database-user \"${DB_USERNAME:-owncloud}\" \\\n --database-pass \"$DB_USER_PASSWORD\" \\\n --admin-user \"$OC_ADMIN\" \\\n --admin-pass \"$OC_ADMIN_PASSWORD\"\nsudo -u www-data php /var/www/owncloud/occ conf:sys:set trusted_domains 1 --value=$FQDN\nsudo -u www-data php /var/www/owncloud/occ conf:sys:set trusted_domains 2 --value=$IP\necho \"Trusted Domain setting added\"\n\n# Open the needed firewall ports\nufw allow http\nufw allow https\napt install certbot python3-certbot-apache -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\n# Clean up\nstackscript_cleanup","user_defined_fields":[{"name":"oc_admin","label":"The name of the admin user for ownCloud"},{"name":"oc_admin_password","label":"The password for ownCloud's admin user"},{"name":"soa_email_address","label":"Admin Email for the ownCloud server"},{"name":"db_name","label":"The name of the database","default":"owncloud"},{"name":"db_root_password","label":"The root password for the database"},{"name":"db_username","label":"The name of the database user to create","default":"owncloud"},{"name":"db_user_password","label":"The password for the created database user"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is required for creating DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""}]},{"id":1102906,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Passky One-Click","description":"Passky One-Click app","ordinal":83,"logo_url":"assets/passky.svg","images":["linode/debian11","linode/ubuntu22.04"],"deployments_total":184,"deployments_active":10,"is_public":true,"mine":false,"created":"2022-12-20T17:48:51","updated":"2023-12-07T09:51:25","rev_note":"","script":"#!/bin/bash\n\n# \n# \n# \n# \n\n# Motd\ncat << EOF > /etc/motd\n _____ _ \n | __ \\ | | \n | |__) |_ _ ___ ___| | ___ _ \n | ___/ _\\` / __/ __| |/ / | | |\n | | | (_| \\__ \\__ \\ <| |_| |\n |_| \\__,_|___/___/_|\\_\\\\__, |\n __/ |\n |___/ \nInstalling...\nPlease logout and come back in few minutes.\nEOF\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\nDEBIAN_FRONTEND=noninteractive apt-get -y -o DPkg::options::=\"--force-confdef\" -o DPkg::options::=\"--force-confold\" install grub-pc\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n## Import the Bash StackScript Library\nsource \n\n# Install docker compose\nsystem_install_package docker-compose\n\n#\n# Passky Server\n#\nwget https://github.com/Rabbit-Company/Passky-Server/releases/latest/download/passky-server.tar.xz\ntar -xf passky-server.tar.xz\ncd passky-server\ncp .env.example .env\n\nSERVER_CORES=$(grep -c ^processor /proc/cpuinfo)\nIP_ADDRESS=$(system_primary_ip)\n\nsed -i \"s/SERVER_CORES=1/SERVER_CORES=$SERVER_CORES/g\" .env\nsed -i \"s/ADMIN_USERNAME=admin/ADMIN_USERNAME=$ADMINUSER/g\" .env\nsed -i \"s/ADMIN_PASSWORD=/ADMIN_PASSWORD=$ADMIN_PASSWORD/g\" .env\n\ndocker-compose up -d\n\napache_install\na2enmod proxy && a2enmod proxy_http && systemctl restart apache2\necho \"\" > /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyPreserveHost On\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyRequests Off\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ServerName $WEBSITE\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyPass / http://localhost:8080/\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \" ProxyPassReverse / http://localhost:8080/\" >> /etc/apache2/sites-available/$WEBSITE.conf\necho \"\" >> /etc/apache2/sites-available/$WEBSITE.conf\na2ensite \"$WEBSITE\"\nsystemctl restart apache2\n\n# Install SSL\nsystem_install_package python3-certbot-apache\ncat << EOF > /usr/local/bin/installCert\n#!/bin/bash\nif ! certbot -n --apache --agree-tos --redirect -d $WEBSITE -m $EMAIL; then\n echo \"There was a problem while installing SSL certificate. Make sure your A record for domain: $WEBSITE does redirect to IP: $IP_ADDRESS\"\nelse\n echo \"Certificate installed successfully.\"\nfi\nEOF\nchmod +x /usr/local/bin/installCert\n\n# Configure auto-renewal for the certificate\ncrontab -l > cron\necho \"0 4 * * * /usr/bin/certbot renew\" >> cron\ncrontab cron\nrm cron\n\nstackscript_cleanup\n\n# Motd\ncat << EOF > /etc/motd\n _____ _ \n | __ \\ | | \n | |__) |_ _ ___ ___| | ___ _ \n | ___/ _\\` / __/ __| |/ / | | |\n | | | (_| \\__ \\__ \\ <| |_| |\n |_| \\__,_|___/___/_|\\_\\\\__, |\n __/ |\n |___/ \nAdmin Panel:\n Link: http://$IP_ADDRESS (https://$WEBSITE)\n Username: $ADMINUSER\n Password: $ADMIN_PASSWORD\nTo install SSL certificate please run command: installCert\nEOF","user_defined_fields":[{"name":"website","label":"Website","example":"passky.domain.com"},{"name":"email","label":"Email Address","example":"info@rabbit-company.com"},{"name":"adminuser","label":"Admin Username"},{"name":"admin_password","label":"Admin Password"}]},{"id":804143,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Peppermint One-Click","description":"Peppermint One-Click","ordinal":84,"logo_url":"assets/peppermint.svg","images":["linode/ubuntu22.04"],"deployments_total":1879,"deployments_active":120,"is_public":true,"mine":false,"created":"2021-04-01T12:45:15","updated":"2023-12-12T04:11:16","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Peppermint setup\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-peppermint\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n \n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"}]},{"id":644908,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Percona (PMM) One-Click","description":"Percona One-Click","ordinal":85,"logo_url":"assets/percona.svg","images":["linode/debian10"],"deployments_total":195,"deployments_active":7,"is_public":true,"mine":false,"created":"2020-04-30T14:49:38","updated":"2023-12-08T04:59:34","rev_note":"","script":"#!/bin/bash\n# \n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Docker\napt -y install docker.io\nsystemctl enable docker.service\n\n#PMM \ndocker pull percona/pmm-server:2\ndocker create -v /srv --name pmm2-data percona/pmm-server:2 /bin/true\ndocker run -d -p 80:80 -p 443:443 \\\n --volumes-from pmm2-data \\\n --name pmm2-server \\\n --restart always percona/pmm-server:2\n\necho \"Waiting for PMM to initialize to set password...\"\n\nuntil [ \"`docker inspect -f {{.State.Health.Status}} pmm2-server`\" = \"healthy\" ]; do sleep 1; done\n\ndocker exec -t pmm2-server bash -c \"ln -s /srv/grafana /usr/share/grafana/data; grafana-cli --homepath /usr/share/grafana admin reset-admin-password $PMMPASSWORD\"\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"pmmpassword","label":"Admin Password","example":"Admin User Password for PMM Server"}]},{"id":609018,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"phpMyAdmin One-Click","description":"phpMyAdmin One-Click","ordinal":86,"logo_url":"assets/phpmyadmin.svg","images":["linode/debian11"],"deployments_total":2176,"deployments_active":112,"is_public":true,"mine":false,"created":"2019-11-05T00:28:33","updated":"2023-12-12T14:10:22","rev_note":"Initial import","script":"#!/bin/bash\n#\n#\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname\nset_hostname\n\n# Update system\napt_setup_update\n\n# Install/configure MySQL, Add Admin User\napt-get install -y mariadb-server\nsystemctl enable mariadb --now\nrun_mysql_secure_installation\nmysql -u root -e \"CREATE USER '$DB_USER'@'localhost' IDENTIFIED BY '$DBUSER_PASSWORD'\"\nmysql -u root -e \"GRANT ALL PRIVILEGES ON *.* TO '$DB_USER'@'localhost' WITH GRANT OPTION\"\nmysql -u root -e \"FLUSH PRIVILEGES\"\n\n# Install PHP\necho 'phpmyadmin phpmyadmin/dbconfig-install boolean true' | debconf-set-selections\necho 'phpmyadmin phpmyadmin/mysql/admin-pass password $DBROOT_PASSWORD' | debconf-set-selections\necho 'phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2' | debconf-set-selections\napt-get install -y phpmyadmin libapache2-mod-php7.4\n\n# Configure ufw\nufw_install\nufw allow http\nufw reload\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"db_user","label":"phpMyAdmin/MySQL Admin User","example":"admin"},{"name":"dbuser_password","label":"phpMyAdmin/MySQL Admin Password"},{"name":"dbroot_password","label":"MySQL root Password"}]},{"id":970522,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Pi-hole One-Click","description":"Pi-hole One-Click","ordinal":87,"logo_url":"assets/pihole.svg","images":["linode/ubuntu20.04"],"deployments_total":3928,"deployments_active":263,"is_public":true,"mine":false,"created":"2022-02-07T16:04:53","updated":"2023-12-12T06:45:30","rev_note":"","script":"#!/usr/bin/env bash\n\n## PIHOLE Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nIPV4=$(ip a | awk '/inet / {print $2}'| sed -n '2 p')\nIPV6=$(ip -6 a | grep inet6 | awk '/global/{print $2}' | cut -d/ -f1)\nGENPIHOLEPASSWD=$(echo -n $PIHOLE_PASSWORD | sha256sum | awk '{printf \"%s\",$1 }' | sha256sum)\nPIHOLE_PASSWD=${GENPIHOLEPASSWD:0:-1}\n\nfunction firewall {\n ufw allow 80\n ufw allow 53\n ufw allow 67\n ufw allow 547\n ufw allow 4711\n}\n\nfunction config_pihole {\n mkdir -p /etc/pihole\n cat < /etc/pihole/setupVars.conf\nPIHOLE_INTERFACE=eth0\nIPV4_ADDRESS=$IPV4\nIPV6_ADDRESS=$IPV6\nPIHOLE_DNS_1=8.8.8.8\nPIHOLE_DNS_2=8.8.4.4\nQUERY_LOGGING=true\nINSTALL_WEB_SERVER=true\nINSTALL_WEB_INTERFACE=true\nLIGHTTPD_ENABLED=true\nCACHE_SIZE=10000\nDNS_FQDN_REQUIRED=true\nDNS_BOGUS_PRIV=true\nDNSMASQ_LISTENING=local\nWEBPASSWORD=$PIHOLE_PASSWD\nBLOCKING_ENABLED=true\nEND\n\ncurl -L https://install.pi-hole.net | bash /dev/stdin --unattended\n}\n\nfunction main {\n config_pihole\n firewall\n}\n\n# Execute script\napt_setup_update\nmain\nstackscript_cleanup","user_defined_fields":[{"name":"pihole_password","label":"PIHOLE USER Password"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"This is the Email address for the SOA record","default":""}]},{"id":662119,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Plex One-Click","description":"Plex One-Click","ordinal":88,"logo_url":"assets/plex.svg","images":["linode/debian10"],"deployments_total":2940,"deployments_active":53,"is_public":true,"mine":false,"created":"2020-08-12T15:54:44","updated":"2023-12-11T02:34:49","rev_note":"","script":"#!/bin/bash\n# INPUT VARIABLES:\n# \n# \n# \n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Limited user setup if username is not \"root\"\nif [ \"$USERNAME\" != \"root\" ]; then\n \n# ensure sudo is installed and configure secure user\n apt -y install sudo\n adduser -uid 1000 $USERNAME --disabled-password --gecos \"\"\n echo \"$USERNAME:$PASSWORD\" | chpasswd\n usermod -aG sudo $USERNAME\n \n# Harden SSH Access\n sed -i -e 's/PermitRootLogin yes/PermitRootLogin no/g' /etc/ssh/sshd_config\n \n# set home directory\n HOME=/home/$USERNAME\n \n# configure ssh key for secure user if provided\n if [ \"$SSHKEY\" != \"\" ]; then\n SSHDIR=$HOME/.ssh\n mkdir $SSHDIR && echo \"$SSHKEY\" >> $SSHDIR/authorized_keys\n chmod -R 700 $SSHDIR && chmod 600 $SSHDIR/authorized_keys\n chown -R $USERNAME:$USERNAME $SSHDIR\n fi\n \n# Enable SSH hardening\n systemctl restart sshd\n \n# Create docker group, add limited user, and enable\n groupadd docker\n usermod -aG docker $USERNAME\nfi\n\n# Install and configure UFW for Plex\nufw_install\nufw allow 32400,3005,8324,32469/tcp\nufw allow 1900,32410,32412,32413,32414/udp\n\n# Install the dependencies & add Docker to the APT repository\napt install -y apt-transport-https ca-certificates curl software-properties-common gnupg2\ncurl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable\"\n\n# Update & install Docker-CE\napt_setup_update\napt install -y docker-ce\n\n# Install plex as limited user\ndocker pull plexinc/pms-docker\ndocker run \\\n -d \\\n --name plex \\\n --restart always \\\n -p 32400:32400/tcp \\\n -p 3005:3005/tcp \\\n -p 8324:8324/tcp \\\n -p 32469:32469/tcp \\\n -p 1900:1900/udp \\\n -p 32410:32410/udp \\\n -p 32412:32412/udp \\\n -p 32413:32413/udp \\\n -p 32414:32414/udp \\\n -e ADVERTISE_IP=\"http://$IP:32400/\" \\\n -h \"Linode Plex Server\" \\\n -v $HOME/plex/config:/config \\\n -v $HOME/plex/media:/media \\\n -v $HOME/plex/transcode:/transcode \\\n plexinc/pms-docker\n\n# Recursively update ownership of Plex directories after delay\nsleep 1\nchown -R $USERNAME:$USERNAME $HOME/plex\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"USERNAME","label":"Limited User Name (not 'root')"},{"name":"PASSWORD","label":"Limited User Password"},{"name":"SSHKEY","label":"Limited User SSH Key","default":"","example":"Usually found in: ./ssh/id_rsa.pub"}]},{"id":611376,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"PostgreSQL One-Click","description":"PostgreSQL One-Click","ordinal":89,"logo_url":"assets/postgresql.svg","images":["linode/debian11"],"deployments_total":2864,"deployments_active":219,"is_public":true,"mine":false,"created":"2019-11-13T06:05:28","updated":"2023-12-12T11:40:20","rev_note":"Initial import","script":"#!/bin/bash\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 22\nufw allow 5432\n\n# Install PostgreSQL\napt install -y postgresql postgresql-contrib\nsystemctl enable postgresql\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":1068726,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"PostgreSQL Cluster One-Click","description":"PostgreSQL Cluster","ordinal":90,"logo_url":"assets/postgresqlmarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":175,"deployments_active":8,"is_public":true,"mine":false,"created":"2022-10-03T20:11:59","updated":"2023-12-12T10:41:11","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n\n# set force apt non-interactive\nexport DEBIAN_FRONTEND=noninteractive\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/postgresql-occ.git\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n# source script libraries\nsource \nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/postgresql-cluster\" ]; then\n rm -rf /tmp/postgresql-cluster\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[info] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[+] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\nfunction setup {\n # install dependancies\n export DEBIAN_FRONTEND=non-interactive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n configure_privateip\n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n if [ ! -d ~/.ssh ]; then \n mkdir ~/.ssh\n else \n echo \".ssh directory is already created\"\n fi\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/postgresql-cluster\n cd /tmp/postgresql-cluster\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"","user_defined_fields":[{"name":"token_password","label":"Your Linode API token"},{"name":"cluster_name","label":"Domain Name"},{"name":"sudo_username","label":"The limited sudo user to be created in the cluster"},{"name":"add_ssh_keys","label":"Add Account SSH Keys to All Nodes?","oneof":"yes,no","default":"yes"},{"name":"cluster_size","label":"PostgeSQL cluster size","default":"3","oneof":"3"}]},{"id":985364,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Prometheus & Grafana One-Click","description":"Prometheus and Grafana","ordinal":91,"logo_url":"assets/prometheusgrafana.svg","images":["linode/ubuntu20.04","linode/ubuntu22.04"],"deployments_total":578,"deployments_active":60,"is_public":true,"mine":false,"created":"2022-03-08T17:03:20","updated":"2023-12-12T11:55:19","rev_note":"","script":"#!/usr/bin/env bash\n## Updated: 01-17-2023\n## Author: n0vabyte, Elvis Segura, esegura@linode.com\n\n#\n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\ncreds=\"/root/credentials.txt\"\nprometheus_htpasswd_file=\"/etc/nginx/.prometheus_htpasswd\"\n\nfunction add_firewalls {\n ufw allow http\n ufw allow https\n}\n\nfunction configure_nginx {\n apt-get install nginx apache2-utils -y\n cat << EOF > /etc/nginx/sites-available/$FQDN.conf\nserver {\n listen 80;\n server_name $FQDN;\n location / {\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header Host \\$http_host;\n proxy_pass http://localhost:3000;\n }\n location /prometheus/ {\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header Host \\$http_host;\n proxy_pass http://localhost:9090;\n auth_basic \"Restricted Area\";\n auth_basic_user_file $prometheus_htpasswd_file;\n }\n# allow let's encrypt\n location ^~ /.well-known {\n allow all;\n auth_basic off;\n alias /var/www/html/.well-known;\n }\n}\nEOF\n\n ln -s /etc/nginx/sites-{available,enabled}/$FQDN.conf\n unlink /etc/nginx/sites-enabled/default\n systemctl reload nginx\n systemctl enable nginx\n}\n\nfunction install_node_exporter {\n groupadd --system prometheus\n useradd -s /sbin/nologin --system -g prometheus prometheus\n curl -s https://api.github.com/repos/prometheus/node_exporter/releases/latest | grep browser_download_url | grep linux-amd64 | cut -d '\"' -f 4 | wget -qi - \n tar -xvf node_exporter*.tar.gz\n chmod +x node_exporter-*/node_exporter\n chown prometheus:prometheus node_exporter\n mv node_exporter-*/node_exporter /usr/local/bin\n rm -fr node_exporter-*\n cat < /etc/systemd/system/node_exporter.service\n[Unit]\nDescription=Node Exporter\nWants=network-online.target\nAfter=network-online.target\n[Service]\nUser=prometheus\nExecStart=/usr/local/bin/node_exporter\n[Install]\nWantedBy=default.target\nEOF\n systemctl daemon-reload\n systemctl start node_exporter\n systemctl enable node_exporter\n}\n\nfunction configure_prometheus {\n latest_version=$(curl -s https://raw.githubusercontent.com/prometheus/prometheus/main/VERSION)\n prom_conf=\"/etc/prometheus/prometheus.yml\"\n file_sd_targets=\"/etc/prometheus/file_sd_targets\"\n prometheus_conf_dir=\"/etc/prometheus\"\n prometheus_data_dir=\"/var/lib/prometheus\"\n mkdir $prometheus_conf_dir $prometheus_conf_dir/file_sd_targets \\\n $prometheus_conf_dir/rules $prometheus_data_dir\n\n wget https://github.com/prometheus/prometheus/releases/download/v$latest_version/prometheus-$latest_version.linux-amd64.tar.gz\n tar xvf prometheus-$latest_version.linux-amd64.tar.gz\n mv prometheus-$latest_version.linux-amd64/* $prometheus_conf_dir\n chown -R prometheus:prometheus $prometheus_conf_dir $prometheus_data_dir\n mv $prometheus_conf_dir/{prometheus,promtool} /usr/local/bin\n ## cleanup\n rm prometheus-$latest_version.linux-amd64.tar.gz\n rmdir prometheus-$latest_version.linux-amd64\n\n ## backup config before updating\n cp $prom_conf{,.bak}\n sed -i -e '/- job_name: \"prometheus\"/ s/^/#/' $prom_conf\n sed -i -e '/- targets:/ s/^/#/' $prom_conf\n sed -i -e '/static_configs/ s/^/#/g' $prom_conf\n ## add our config\n cat << EOF >> $prom_conf\n#########################################\n## Local Prometheus Instance - This Box #\n#########################################\n - job_name: local_prometheus\n scrape_interval: 3s\n file_sd_configs:\n - files:\n - file_sd_targets/local_prometheus.yml\n honor_labels: true\n relabel_configs:\n - regex: (.*)\n replacement: \\${1}:9100\n source_labels:\n - __address__\n target_label: __address__\n - regex: (.+)\n replacement: \\${1}\n source_labels:\n - __instance\n target_label: instance\nEOF\n ## add to file_sd_targets\n cat << EOF >> $file_sd_targets/local_prometheus.yml\n- labels:\n __instance: prometheus\n cluster: local\n targets:\n - 127.0.0.1\nEOF\n cat << EOF > /etc/systemd/system/prometheus.service\n[Unit]\nDescription=Prometheus\nDocumentation=https://prometheus.io/docs/introduction/overview/\nWants=network-online.target\nAfter=network-online.target\n[Service]\nUser=prometheus\nGroup=prometheus\nType=simple\nExecStart=/usr/local/bin/prometheus \\\n--config.file /etc/prometheus/prometheus.yml \\\n--storage.tsdb.path $prometheus_data_dir/ \\\n--web.console.templates=$prometheus_conf_dir/consoles \\\n--web.console.libraries=$prometheus_conf_dir/console_libraries \\\n--web.listen-address=127.0.0.1:9090 \\\n--web.external-url=https://$FQDN/prometheus \\\n--storage.tsdb.retention=60d\nRestart=always\nExecReload=/usr/bin/kill -HUP \\$MAINPID\nTimeoutStopSec=20s\nOOMScoreAdjust=-900\nSendSIGKILL=no\n[Install]\nWantedBy=multi-user.target\nEOF\n systemctl daemon-reload\n systemctl start prometheus\n systemctl enable prometheus\n\n ## protect with htpasswd\n prometheus_htpasswd=$(openssl rand -base64 32)\n htpasswd -cb $prometheus_htpasswd_file prometheus $prometheus_htpasswd\n ## log credentials locally\n cat << EOF >> $creds\n#################\n# Prometheus #\n#################\nLocation: https://$FQDN/prometheus\nUsername: prometheus\nPassword: $prometheus_htpasswd\nEOF\n ## sanity check\n function fallback {\n echo \"[FATAL] Creating custom configuration failed. Restoring old configuration\"\n cp $prom_conf{.bak,}\n systemctl restart prometheus\n sleep 2\n systemctl is-active prometheus\n if [ $? -ne 0 ]; then\n echo \"[CRITICAL] Encoutered unexpected error while configuring Prometheus. Please reach out to Support.\"\n exit 2\n fi\n }\n systemctl is-active prometheus\n if [ $? -ne 0 ]; then\n echo \"[ERROR] Prometheus is not running. Falling back to default config..\"\n fallback\n fi\n\n}\n\nfunction configure_grafana {\n echo \"[info] configuring Grafana - Installing Packages\"\n apt-get install -y apt-transport-https \\\n software-properties-common \\\n wget \\\n gnupg2 \\\n sqlite3\n\n wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key\n echo \"deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main\" | sudo tee -a /etc/apt/sources.list.d/grafana.list\n apt-get -y update\n apt-get -y install grafana\n\n ## reset Grafana admin password\n grafana_password=$(openssl rand -base64 32)\n\n echo \"[info] updating grafana config\"\n sed -i -e 's/;admin_user = admin/admin_user = admin/g' /etc/grafana/grafana.ini\n sed -i \"s|;admin_password = admin|admin_password = $grafana_password|g\" /etc/grafana/grafana.ini\n\n echo \"[info] starting grafana-server\"\n systemctl start grafana-server\n systemctl enable grafana-server\n\n ## log credentials locally\n cat << EOF >> $creds\n##############\n# Grafana #\n##############\nLocation: https://$FQDN/\nUsername: admin\nPassword: $grafana_password\nEOF\n}\n\nfunction ssl_grafana {\n apt install -y certbot python3-certbot-nginx\n certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction main {\n add_firewalls\n configure_nginx\n install_node_exporter\n configure_prometheus\n configure_grafana\n ssl_grafana\n}\n\n## execute script\nmain\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"This email is for the LetsEncrypt SSL certificate"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":607034,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Prometheus One-Click","description":"Prometheus One Click App","ordinal":92,"logo_url":"assets/prometheus.svg","images":["linode/debian10"],"deployments_total":356,"deployments_active":12,"is_public":true,"mine":false,"created":"2019-10-29T20:59:30","updated":"2023-12-10T13:40:45","rev_note":"Initial import","script":"#!/bin/bash\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Prometheus\ngroupadd --system prometheus\nuseradd -s /sbin/nologin --system -g prometheus prometheus\nmkdir /var/lib/prometheus\nfor i in rules rules.d files_sd; do mkdir -p /etc/prometheus/${i}; done\napt-get -y install wget\nmkdir -p /tmp/prometheus && cd /tmp/prometheus\ncurl -s https://api.github.com/repos/prometheus/prometheus/releases/latest \\\n | grep browser_download_url \\\n | grep linux-amd64 \\\n | cut -d '\"' -f 4 \\\n | wget -qi -\ntar xvf prometheus*.tar.gz\ncd prometheus*/\nmv prometheus promtool /usr/local/bin/\nmv prometheus.yml /etc/prometheus/prometheus.yml\nmv consoles/ console_libraries/ /etc/prometheus/\ncd ~/\nrm -rf /tmp/prometheus\n\n# Edit Prometheus config\nsudo tee /etc/prometheus/prometheus.yml</etc/systemd/system/prometheus.service\n[Unit]\nDescription=Prometheus\nDocumentation=https://prometheus.io/docs/introduction/overview/\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nType=simple\nUser=prometheus\nGroup=prometheus\nExecReload=/bin/kill -HUP $MAINPID\nExecStart=/usr/local/bin/prometheus \\\n --config.file=/etc/prometheus/prometheus.yml \\\n --storage.tsdb.path=/var/lib/prometheus \\\n --web.console.templates=/etc/prometheus/consoles \\\n --web.console.libraries=/etc/prometheus/console_libraries \\\n --web.listen-address=0.0.0.0:9090 \\\n --web.external-url=\n\nSyslogIdentifier=prometheus\nRestart=always\nRestartSec=3\n\n[Install]\nWantedBy=multi-user.target\nEND\n\nfor i in rules rules.d files_sd; do chown -R prometheus:prometheus /etc/prometheus/${i}; done\nfor i in rules rules.d files_sd; do chmod -R 775 /etc/prometheus/${i}; done\nchown -R prometheus:prometheus /var/lib/prometheus/\n\n# Add node_exporter & Enable services\ncurl -s https://api.github.com/repos/prometheus/node_exporter/releases/latest \\\n| grep browser_download_url \\\n| grep linux-amd64 \\\n| cut -d '\"' -f 4 \\\n| wget -qi -\n\ntar -xvf node_exporter*.tar.gz\ncd node_exporter*/\ncp node_exporter /usr/local/bin\nnode_exporter --version\n\ncat </etc/systemd/system/node_exporter.service\n[Unit]\nDescription=Node Exporter\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nUser=prometheus\nExecStart=/usr/local/bin/node_exporter\n\n[Install]\nWantedBy=default.target\nEND\n\nsystemctl daemon-reload\nsystemctl start prometheus\nsystemctl enable prometheus\nsystemctl start node_exporter\nsystemctl enable node_exporter\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[]},{"id":688890,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"RabbitMQ One-Click","description":"RabbitMQ One-Click","ordinal":93,"logo_url":"assets/rabbitmq.svg","images":["linode/debian10"],"deployments_total":393,"deployments_active":48,"is_public":true,"mine":false,"created":"2020-11-17T20:53:00","updated":"2023-12-08T15:47:55","rev_note":"","script":"#!/bin/bash\n#\n#\n\n# Logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Set hostname, configure apt and perform update/upgrade\napt_setup_update\n\n## Install prerequisites\napt-get install curl gnupg -y\n\n## Get RabbitMQ \n$ curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo apt-key add -\nsudo apt-key adv --keyserver \"hkps://keys.openpgp.org\" --recv-keys \"0x0A9AF2115F4687BD29803A206B73A36E6026DFCA\"\n## Install apt HTTPS transport\napt-get install apt-transport-https\n\n## Add Bintray repositories that provision latest RabbitMQ and Erlang 23.x releases\ntee /etc/apt/sources.list.d/bintray.rabbitmq.list <\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# System Update\nset_hostname\napt_setup_update\n\nfunction install_redis {\n apt install -y redis-server\n systemctl enable redis-server\n}\n\nfunction redis_config {\n sed -ie \"s/supervised no/supervised systemd/g\" /etc/redis/redis.conf\n sed -ie \"s/appendonly no/appendonly yes/g\" /etc/redis/redis.conf\n systemctl restart redis-server\n}\n\nfunction main {\n install_redis\n redis_config\n}\nmain\n\n# cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address for SOA Recorf","default":""}]},{"id":1132204,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Marketplace App for Redis® Sentinel Cluster One-Click","description":"Redis Sentinel One-Click Cluster","ordinal":95,"logo_url":"assets/redissentinelmarketplaceocc.svg","images":["linode/ubuntu22.04"],"deployments_total":136,"deployments_active":7,"is_public":true,"mine":false,"created":"2023-02-27T20:05:44","updated":"2023-12-06T05:47:35","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Deployment Variables\n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n# \n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/redis-occ.git\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# source script libraries\nsource \n\nfunction cleanup {\n if [ \"$?\" != \"0\" ] || [ \"$SUCCESS\" == \"true\" ]; then\n #deactivate\n cd ${HOME}\n if [ -d \"/tmp/linode\" ]; then\n rm -rf /tmp/linode\n fi\n if [ -d \"/usr/local/bin/run\" ]; then\n rm /usr/local/bin/run\n fi\n stackscript_cleanup\n fi\n}\n\nfunction add_privateip {\n echo \"[info] Adding instance private IP\"\n curl -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X POST -d '{\n \"type\": \"ipv4\",\n \"public\": false\n }' \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips\n}\n\nfunction get_privateip {\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}/ips | \\\n jq -r '.ipv4.private[].address'\n}\n\nfunction configure_privateip {\n LINODE_IP=$(get_privateip)\n if [ ! -z \"${LINODE_IP}\" ]; then\n echo \"[info] Linode private IP present\"\n else\n echo \"[warn] No private IP found. Adding..\"\n add_privateip\n LINODE_IP=$(get_privateip)\n ip addr add ${LINODE_IP}/17 dev eth0 label eth0:1\n fi\n}\n\nfunction rename_provisioner {\n INSTANCE_PREFIX=$(curl -sH \"Authorization: Bearer ${TOKEN_PASSWORD}\" \"https://api.linode.com/v4/linode/instances/${LINODE_ID}\" | jq -r .label)\n export INSTANCE_PREFIX=\"${INSTANCE_PREFIX}\"\n echo \"[info] renaming the provisioner\"\n curl -s -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" \\\n -X PUT -d \"{\n \\\"label\\\": \\\"${INSTANCE_PREFIX}1\\\"\n }\" \\\n https://api.linode.com/v4/linode/instances/${LINODE_ID}\n}\n\nfunction setup {\n # install dependencies\n export DEBIAN_FRONTEND=non-interactive\n apt-get update && apt-get upgrade -y\n apt-get install -y jq git python3 python3-pip python3-dev build-essential firewalld\n # add private IP address\n rename_provisioner\n configure_privateip \n # write authorized_keys file\n if [ \"${ADD_SSH_KEYS}\" == \"yes\" ]; then\n if [ ! -d ~/.ssh ]; then \n mkdir ~/.ssh\n else \n echo \".ssh directory is already created\"\n fi\n curl -sH \"Content-Type: application/json\" -H \"Authorization: Bearer ${TOKEN_PASSWORD}\" https://api.linode.com/v4/profile/sshkeys | jq -r .data[].ssh_key > /root/.ssh/authorized_keys\n fi\n # clone repo and set up ansible environment\n git clone ${GIT_REPO} /tmp/linode\n cd /tmp/linode\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n # copy run script to path\n cp scripts/run.sh /usr/local/bin/run\n chmod +x /usr/local/bin/run\n}\n# main\nsetup\nrun ansible:build\nrun ansible:deploy && export SUCCESS=\"true\"","user_defined_fields":[{"name":"token_password","label":"Your Linode API token"},{"name":"sudo_username","label":"The limited sudo user to be created in the cluster"},{"name":"sslheader","label":"SSL Information","header":"Yes","default":"Yes","required":"Yes"},{"name":"country_name","label":"Details for self-signed SSL certificates: Country or Region","oneof":"AD,AE,AF,AG,AI,AL,AM,AO,AQ,AR,AS,AT,AU,AW,AX,AZ,BA,BB,BD,BE,BF,BG,BH,BI,BJ,BL,BM,BN,BO,BQ,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CD,CF,CG,CH,CI,CK,CL,CM,CN,CO,CR,CU,CV,CW,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER,ES,ET,FI,FJ,FK,FM,FO,FR,GA,GB,GD,GE,GF,GG,GH,GI,GL,GM,GN,GP,GQ,GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IM,IN,IO,IQ,IR,IS,IT,JE,JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS,LT,LU,LV,LY,MA,MC,MD,ME,MF,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV,MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG,PH,PK,PL,PM,PN,PR,PS,PT,PW,PY,QA,RE,RO,RS,RU,RW,SA,SB,SC,SD,SE,SG,SH,SI,SJ,SK,SL,SM,SN,SO,SR,SS,ST,SV,SX,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TL,TM,TN,TO,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF,WS,YE,YT,ZA,ZM,ZW"},{"name":"state_or_province_name","label":"State or Province","example":"Example: Pennsylvania"},{"name":"locality_name","label":"Locality","example":"Example: Philadelphia"},{"name":"organization_name","label":"Organization","example":"Example: Akamai Technologies"},{"name":"email_address","label":"Email Address","example":"Example: user@domain.tld"},{"name":"ca_common_name","label":"CA Common Name","default":"Redis CA"},{"name":"common_name","label":"Common Name","default":"Redis Server"},{"name":"clusterheader","label":"Cluster Settings","default":"Yes","header":"Yes"},{"name":"add_ssh_keys","label":"Add Account SSH Keys to All Nodes?","oneof":"yes,no","default":"yes"},{"name":"cluster_size","label":"Redis cluster size","default":"3","oneof":"3,5"}]},{"id":923036,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Restyaboard One-Click","description":"Restyaboard One-Click","ordinal":96,"logo_url":"assets/restyaboard.svg","images":["linode/centos7","linode/debian10","linode/ubuntu20.04"],"deployments_total":209,"deployments_active":2,"is_public":true,"mine":false,"created":"2021-10-18T01:07:09","updated":"2023-12-03T04:43:28","rev_note":"","script":"#!/bin/bash\n#\n# Install script for Restyaboard\n#\n# Usage: ./restyaboard.sh\n#\n# Copyright (c) 2014-2021 Restya.\n# Dual License (OSL 3.0 & Commercial License)\n{\n\tmain() {\n\t\tif [[ $EUID -ne 0 ]];\n\t\tthen\n\t\t\techo \"This script must be run as root\"\n\t\t\texit 1\n\t\tfi\n\t\tset -x\n\t\twhoami\n\t\t#\n\t\t# Checking the OS name and OS version\n\t\t#\n\t\tfind_release ()\n\t\t{\n\t\t\t# Checking the Ubuntu OS\n\t\t\tif [ -f /etc/lsb-release ]; then\n\t\t\t\tOS_REQUIREMENT=\"`grep DISTRIB_ID /etc/lsb-release`\"\n\t\t\t\tDISTRIB_ID='DISTRIB_ID='\n\t\t\t\tOS_NAME=$OS_REQUIREMENT$DISTRIB_ID\n\t\t\t\tarray=();\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" != \"$DISTRIB_ID\" ])\n\t\t\t\tthen\n\t\t\t\t\twhile [[ $OS_NAME ]]; do\n\t\t\t\t\tarray+=( \"${OS_NAME%%\"$DISTRIB_ID\"*}\" );\n\t\t\t\t\tOS_NAME=${OS_NAME#*\"$DISTRIB_ID\"};\n\t\t\t\t\tdone;\n\t\t\t\t\tOS_REQUIREMENT=${array[1]}\n\t\t\t\tfi\n\t\t\t\tOS_VERSION=\"`grep DISTRIB_RELEASE /etc/lsb-release`\"\n\t\t\t\tDISTRIB_RELEASE='DISTRIB_RELEASE='\n\t\t\t\tOS_Ver=$OS_VERSION$DISTRIB_RELEASE\n\t\t\t\tversion=();\n\t\t\t\tif ([ \"$OS_VERSION\" != \"$DISTRIB_RELEASE\" ])\n\t\t\t\tthen\n\t\t\t\t\twhile [[ $OS_Ver ]]; do\n\t\t\t\t\tversion+=( \"${OS_Ver%%\"$DISTRIB_RELEASE\"*}\" );\n\t\t\t\t\tOS_Ver=${OS_Ver#*\"$DISTRIB_RELEASE\"};\n\t\t\t\t\tdone;\n\t\t\t\t\tOS_VERSION=${version[1]}\n\t\t\t\tfi\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t\t# Checking the Redhat, Fedora, and Centos\n\t\t\tif [ -f /etc/redhat-release ]; then\n\t\t\t\tOS_REQUIREMENT=\"`cat /etc/redhat-release | cut -d ' ' -f 1`\"\n\t\t\t\tOS_VERSION=\"`cat /etc/redhat-release | cut -d ' ' -f 4 | cut -d '.' -f 1`\"\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t\t# Checking the Debian OS\n\t\t\tif [ -f /etc/issue ]; then\n\t\t\t\tOS_REQUIREMENT=\"`cat /etc/issue | cut -d ' ' -f 1`\"\n\t\t\t\tOS_VERSION=\"`cat /etc/issue | cut -d ' ' -f 3`\"\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t\t# Checking the OpenBSD \n\t\t\tif [ -f /etc/motd ]; then\n\t\t\t\tOS_REQUIREMENT=\"`cat /etc/motd | head -1 | cut -d ' ' -f 1`\"\n\t\t\t\tOS_VERSION=\"`cat /etc/motd | head -1 | cut -d ' ' -f 2`\"\n\t\t\t\treturn\n\t\t\tfi\n\n\t\t}\n\t\tfindbin ()\n {\n ret=0\n newpath=`echo $PATH | tr : ' '`\n for i in ${newpath}; do\n\t\t\t\tif [ -x $i/$1 ]; then\n\t\t\t\t\tret=1\n\t\t\t\t\tbreak\n\t\t\t\tfi\n done\n echo $ret\n return \n }\n checkdeps()\n {\n pkginfo=\"dpkg rpm ipkg pkg_info\"\n for i in $pkginfo; do\n ret=`findbin $i`\n if [ $ret -eq 1 ]; then\n\t\t\t\t\tpkginfo=$i\n\t\t\t\t\techo \"Yes, found $i, so we'll use that for listing packages\"\n\t\t\t\t\tbreak\n fi\n done\n\n if [ ${pkginfo} = \"pkg_info\" ]; then\n # BSD needs PKG_PATH set to load anything over the net.\n if [ x${PKG_PATH} = x ]; then\n\t\t\t\t\techo \"Please set the environment variable PKG_PATH and try again.\"\n\t\t\t\t\texit 1\n fi\n fi\n \n \n pkg_name=\"yum apt-get ipkg pkg_add\"\n for i in ${pkg_name}; do\n ret=`findbin $i`\n if [ $ret -eq 1 ]; then\n pkg_name=$i\n\t\t\t\t\techo \"Yes, found $i, so we'll use that to install packages\"\n\t\t\t\t\tbreak\n fi\n done\n \n\n for i in ${genericdeps} ${gtkdeps} ${kdedeps}; do\n case $pkginfo in\n dpkg)\n deps=\"`dpkg -l \"*$i*\" | grep -- \"^ii\" | cut -d ' ' -f 3`\"\n ;;\n rpm)\n deps=\"`rpm -q $i`\"\n ;;\n pkg_info)\n deps=\"`pkg_info | grep \"$i\" | sed -e 's: .*$::'`\"\n ;;\n ipkg)\n deps=\"todo\"\n ;;\n *)\n echo \"ERROR: No package manager found!\"\n exit 1\n ;;\n esac\n found=`echo ${deps} | grep -v 'not installed' | grep -c \"${i}\" 2>&1`\n if [ $found -gt 0 ]; then\n \techo \"Yes, found $i\"\n else\n\t\t\t\t\techo \"Nope, $i appears to not be installed\"\n\t\t\t\t\tmissing=\"${missing} $i\"\n fi\n done\n\n if [ -n \"${missing}\" ]; then\n echo \"package(s)\\\"${missing}\\\" are missing!\"\n echo \"You will need sudo priviledges to install the packages\"\n if [ x$yes = xno ]; then\n \t$debug sudo ${pkgnet} install ${missing}\n else\n \t$debug sudo ${pkgnet} -y install ${missing}\n fi\n fi\n }\n\t\tinstall_nginx() \n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n echo \"Checking nginx...\"\n if ! which nginx > /dev/null 2>&1; then\n echo \"nginx not installed!\"\n echo \"Installing nginx...\"\n apt install -y cron nginx\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"nginx installation failed with error code ${error_code} (nginx installation failed with error code 2)\"\n return 2\n fi\n if [ -f \"/etc/nginx/conf.d/default\" ]; then\n rm -rf /etc/nginx/conf.d/default\n fi\n if [ -f \"/etc/nginx/sites-enabled/default\" ]; then\n rm -rf /etc/nginx/sites-enabled/default\n fi\n if [ -f \"/etc/nginx/sites-available/default\" ]; then\n rm -rf /etc/nginx/sites-available/default\n fi\n service nginx start\n fi\n\t\t\telse\t\t\t\t\n echo \"Checking nginx...\"\n if ! which nginx > /dev/null 2>&1; then\n echo \"nginx not installed!\"\n echo \"Installing nginx...\"\n rpm -Uvh \"http://nginx.org/packages/centos/${OS_VERSION}/noarch/RPMS/nginx-release-centos-${OS_VERSION}-0.el${OS_VERSION}.ngx.noarch.rpm\"\n yum install -y zip cronie nginx\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"cron nginx installation failed with error code ${error_code} cron nginx installation failed with error code 18\"\n return 18\n fi\n if [ -f \"/etc/nginx/conf.d/default.conf\" ]; then\n rm -rf /etc/nginx/conf.d/default.conf\n fi\n if [ -f \"/etc/nginx/sites-enabled/default.conf\" ]; then\n rm -rf /etc/nginx/sites-enabled/default.conf\n fi\n if [ -f \"/etc/nginx/sites-available/default.conf\" ]; then\n rm -rf /etc/nginx/sites-available/default.conf\n fi\n service nginx start\n chkconfig --levels 35 nginx on\n fi\n\t\t\tfi\n\t\t}\n\t\tinstall_php()\n\t\t{\n\t\t\tif ! hash php 2>&-; then\n\t\t\t\techo \"PHP is not installed!\"\n if ([ \"$pkg_name\" = \"apt-get\" ])\n then\t\t\t\t\t\t\t\n echo \"Installing PHP...\"\n apt install -y php7.4 php7.4-common --allow-unauthenticated\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"PHP installation failed with error code ${error_code} (PHP installation failed with error code 3)\"\n return 3\n fi\n else \n if ([ \"$pkg_name\" = \"yum\" ])\n then\n if ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n then\n echo \"Note: For the latest version of PHP, we're going to download https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm and https://rpms.remirepo.net/enterprise/remi-release-8.rpm.\"\n echo \"Installing PHP...\"\n dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm\n dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm\n dnf module enable php:remi-7.4\n dnf -y install php php-cli php-common\n else\n yum install -y epel-release\n echo \"Note: For the latest version of PHP, we're going to download http://rpms.famillecollet.com/enterprise/remi-release-${OS_VERSION}.rpm.\"\n echo \"Installing PHP...\"\n rpm -Uvh \"http://rpms.famillecollet.com/enterprise/remi-release-${OS_VERSION}.rpm\"\n yum --enablerepo=remi-php74 install -y php\n fi\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"php installation failed with error code ${error_code} (php installation failed with error code 20)\"\n return 20\n fi\n fi\n fi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Installing PHP fpm and cli extension...\"\n\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\tthen\n\t\t\t\tapt install -y php7.4-fpm php7.4-cli --allow-unauthenticated\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"php7.4-cli installation failed with error code ${error_code} (php7.4-cli installation failed with error code 4)\"\n\t\t\t\tfi\n\t\t\t\tservice php7.4-fpm start\n\t\t\telse \n\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\tthen\n\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n \t\t\tthen\n\t\t\t\t\t\tdnf -y install php-fpm php-devel php-opcache\n\t\t\t\t\t\tdnf -y install php-json\n\t\t\t\t\telse\n\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-fpm php-devel php-cli php-opcache\n\t\t\t\t\tfi\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php-devel installation failed with error code ${error_code} (php-devel installation failed with error code 21)\"\n\t\t\t\t\t\treturn 21\n\t\t\t\t\tfi\t\t\t\t\t\n\t\t\t\t\tservice php-fpm start\n\t\t\t\tfi\n\t\t\tfi\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \"....\"\n\t\t\telse\n\t\t\t\tchkconfig --levels 35 php-fpm on\t\t\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP curl extension...\"\n\t\t\tphp -m | grep curl\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-curl...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-curl --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-curl installation failed with error code ${error_code} (php7.4-curl installation failed with error code 5)\"\n\t\t\t\t\t\treturn 5\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-curl\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-curl\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-curl installation failed with error code ${error_code} (php-curl installation failed with error code 22)\"\n\t\t\t\t\t\t\treturn 22\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP pgsql extension...\"\n\t\t\tphp -m | grep pgsql\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-pgsql...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install libpq5\n\t\t\t\t\tapt install -y php7.4-pgsql --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-pgsql installation failed with error code ${error_code} (php7.4-pgsql installation failed with error code 6)\"\n\t\t\t\t\t\treturn 6\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-pgsql\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-pgsql\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-pgsql installation failed with error code ${error_code} (php-pgsql installation failed with error code 23)\"\n\t\t\t\t\t\t\treturn 23\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP mbstring extension...\"\n\t\t\tphp -m | grep mbstring\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-mbstring...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-mbstring --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-mbstring installation failed with error code ${error_code} (php7.4-mbstring installation failed with error code 7)\"\n\t\t\t\t\t\treturn 7\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-mbstring\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-mbstring\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-mbstring installation failed with error code ${error_code} (php-mbstring installation failed with error code 24)\"\n\t\t\t\t\t\t\treturn 24\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP ldap extension...\"\n\t\t\tphp -m | grep ldap\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-ldap...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-ldap --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-ldap installation failed with error code ${error_code} (php7.4-ldap installation failed with error code 8)\"\n\t\t\t\t\t\treturn 8\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-ldap\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-ldap\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-ldap installation failed with error code ${error_code} (php-ldap installation failed with error code 25)\"\n\t\t\t\t\t\t\treturn 25\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP imagick extension...\"\n\t\t\tphp -m | grep imagick\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php-imagick...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y gcc\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"gcc installation failed with error code ${error_code} (gcc installation failed with error code 9)\"\n\t\t\t\t\t\treturn 9\n\t\t\t\t\tfi\n\t\t\t\t\tapt install -y imagemagick\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"imagemagick installation failed with error code ${error_code} (imagemagick installation failed with error code 9)\"\n\t\t\t\t\t\treturn 9\n\t\t\t\t\tfi\n\t\t\t\t\tapt install -y php7.4-imagick --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-imagick installation failed with error code ${error_code} (php7.4-imagick installation failed with error code 10)\"\n\t\t\t\t\t\treturn 10\n\t\t\t\t\tfi\n\t\t\t\telse \n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tyum install -y ImageM* netpbm gd gd-* libjpeg libexif gcc coreutils make\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-pear\n\t\t\t\t\t\t\tdnf -y install php-gd\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-pear\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-gd\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"Installing php-imagick failed with error code ${error_code} (Installing php-imagick failed with error code 26)\"\n\t\t\t\t\t\t\treturn 26\n\t\t\t\t\t\tfi\n\n\t\t\t\t\t\tcd /usr/local/src\n\t\t\t\t\t\twget http://pecl.php.net/get/imagick-2.2.2.tgz\n\t\t\t\t\t\ttar zxvf ./imagick-2.2.2.tgz\n\t\t\t\t\t\tcd imagick-2.2.2\n\t\t\t\t\t\tphpize\n\t\t\t\t\t\t./configure\n\t\t\t\t\t\tmake\n\t\t\t\t\t\tmake test\n\t\t\t\t\t\tmake install\n\t\t\t\t\t\techo \"extension=imagick.so\" >> /etc/php.ini\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking PHP imap extension...\"\n\t\t\tphp -m | grep imap\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing php7.4-imap...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-imap --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-imap installation failed with error code ${error_code} (php7.4-imap installation failed with error code 11)\"\n\t\t\t\t\t\treturn 11\n\t\t\t\t\tfi\n\t\t\t\telse\n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-imap\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-imap\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"php-imap installation failed with error code ${error_code} (php-imap installation failed with error code 26)\"\n\t\t\t\t\t\t\treturn 26\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t\t\n\t\t\techo \"Checking xml...\"\n\t\t\tphp -m | grep xml\n\t\t\tif [ \"$?\" -gt 0 ]; then\n\t\t\t\techo \"Installing xml...\"\n\t\t\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n\t\t\t\tthen\n\t\t\t\t\tapt install php7.4-xml --allow-unauthenticated\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"xml installation failed with error code ${error_code} (xml installation failed with error code 56)\"\n\t\t\t\t\t\treturn 56\n\t\t\t\t\tfi\n\t\t\t\telse\n\t\t\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install php-xml\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum --enablerepo=remi-php74 install -y php-xml\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"xml installation failed with error code ${error_code} (xml installation failed with error code 57)\"\n\t\t\t\t\t\t\treturn 57\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tset_timezone()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\ttimezone=$(cat /etc/timezone)\n\t\t\t\tsed -i -e 's/date.timezone/;date.timezone/g' /etc/php/7.4/fpm/php.ini\n\t\t\t\techo \"date.timezone = $timezone\" >> /etc/php/7.4/fpm/php.ini\n\t\t\telse \n\t\t\t\tPHP_VERSION=$(php -v | grep \"PHP 5\" | sed 's/.*PHP \\([^-]*\\).*/\\1/' | cut -c 1-3)\n\t\t\t\techo \"Installed PHP version: '$PHP_VERSION'\"\n\t\t\t\ttimezone=$(cat /etc/sysconfig/clock | grep ZONE | cut -d\"\\\"\" -f2)\n\t\t\t\tsed -i -e 's/date.timezone/;date.timezone/g' /etc/php.ini\n\t\t\t\techo \"date.timezone = $timezone\" >> /etc/php.ini\n\t\t\tfi\n\t\t}\n\t\tinstall_postgresql()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tid -a postgres\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]; then\n\t\t\t\t\techo \"PostgreSQL not installed!\"\n echo \"Installing PostgreSQL...\"\n sh -c 'echo \"deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main\" > /etc/apt/sources.list.d/pgdg.list'\n apt install wget ca-certificates\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"ca-certificates installation failed with error code ${error_code} (ca-certificates installation failed with error code 12)\"\n fi\n wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc\n apt-key add ACCC4CF8.asc\n apt update\n apt install -y postgresql --allow-unauthenticated\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"postgresql installation failed with error code ${error_code} (postgresql installation failed with error code 13)\"\n return 13\n fi\n\t\t\t\telse\n\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}' | head -1)\n\t\t\t\t\tif [[ ${PSQL_VERSION} == \"\" ]]; then\n\t\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ ${PSQL_VERSION} =~ ^10\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\t\tPSQL_VERSION=10\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ ${PSQL_VERSION} =~ ^11\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\t\tPSQL_VERSION=11\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ ${PSQL_VERSION} =~ ^12\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\t\tPSQL_VERSION=12\n\t\t\t\t\tfi\n\t\t\t\t\tif [[ 1 -eq \"$(echo \"${PSQL_VERSION} < 9.3\" | bc)\" ]]; then\n\t\t\t\t\t\tset +x\n\t\t\t\t\t\techo \"Restyaboard will not work in your PostgreSQL version (i.e. less than 9.3). So script going to update PostgreSQL version 9.6\"\n\t\t\t\t\t\tsh -c 'echo \"deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main\" > /etc/apt/sources.list.d/pgdg.list'\n\t\t\t\t\t\tapt install wget ca-certificates\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"ca-certificates installation failed with error code ${error_code} (ca-certificates installation failed with error code 12)\"\n\t\t\t\t\t\tfi\n\t\t\t\t\t\twget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc\n\t\t\t\t\t\tapt-key add ACCC4CF8.asc\n\t\t\t\t\t\tapt update\n\t\t\t\t\t\tapt upgrade\n\t\t\t\t\t\tapt install -y postgresql --allow-unauthenticated\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"postgresql installation failed with error code ${error_code} (postgresql installation failed with error code 13)\"\n\t\t\t\t\t\t\treturn 13\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}' | head -1)\n\t\t\t\tif [[ ${PSQL_VERSION} == \"\" ]]; then\n\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\tfi\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^10\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=10\n\t\t\t\tfi\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^11\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=11\n\t\t\t\tfi\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^12\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=12\n\t\t\t\tfi\n\t\t\t\tsed -e 's/peer/trust/g' -e 's/ident/trust/g' < /etc/postgresql/${PSQL_VERSION}/main/pg_hba.conf > /etc/postgresql/${PSQL_VERSION}/main/pg_hba.conf.1\n\t\t\t\tcd /etc/postgresql/${PSQL_VERSION}/main || exit\n\t\t\t\tmv pg_hba.conf pg_hba.conf_old\n\t\t\t\tmv pg_hba.conf.1 pg_hba.conf\n\t\t\t\tservice postgresql restart\n\t\t\telse\n\t\t\t\tif ! which psql > /dev/null 2>&1;\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL not installed!\"\n echo \"Installing PostgreSQL...\"\n if [ $(getconf LONG_BIT) = \"64\" ]; then\n if [[ $OS_REQUIREMENT = \"Fedora\" ]]; then\n dnf install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/F-${OS_VERSION}-x86_64/pgdg-fedora-repo-latest.noarch.rpm\"\n else\n if ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" != \"8\" ])\n then\n yum install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm\"\n fi\n fi\n fi\n if ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n then\n dnf module enable postgresql:13\n dnf -y install postgresql-server postgresql-contrib postgresql-libs\n else\n yum install -y postgresql13 postgresql13-server postgresql13-contrib postgresql13-libs\t\n fi\n error_code=$?\n if [ ${error_code} != 0 ]\n then\n echo \"postgresql13 installation failed with error code ${error_code} (postgresql13 installation failed with error code 29)\"\n return 29\n fi\n\t\t\t\telse \n\t\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\t\tif [[ $PSQL_VERSION < 9.3 ]]; then\n\t\t\t\t\t\tset +x\n\t\t\t\t\t\techo \"Restyaboard will not work in your PostgreSQL version (i.e. less than 9.3). So script going to update PostgreSQL version 9.6\"\n\t\t\t\t\t\tif [ $(getconf LONG_BIT) = \"64\" ]; then\n\t\t\t\t\t\t\tif [[ $OS_REQUIREMENT = \"Fedora\" ]]; then\n\t\t\t\t\t\t\t\tdnf install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/F-${OS_VERSION}-x86_64/pgdg-fedora-repo-latest.noarch.rpm\"\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" != \"8\" ])\n\t\t\t\t\t\t\t\tthen\n\t\t\t\t\t\t\t\t\tyum install -y \"https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VERSION}-x86_64/pgdg-redhat-repo-latest.noarch.rpm\"\n\t\t\t\t\t\t\t\tfi\n\t\t\t\t\t\t\tfi\n\t\t\t\t\t\tfi\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf module enable postgresql:13\n\t\t\t\t\t\t\tdnf -y install postgresql-server postgresql-contrib postgresql-libs\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum install -y postgresql13 postgresql13-server postgresql13-contrib postgresql13-libs\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"postgresql installation failed with error code ${error_code} (postgresql installation failed with error code 29)\"\n\t\t\t\t\t\t\treturn 29\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\t\tPSQL_VERSION=$(psql --version | egrep -o '[0-9]{1,}\\.[0-9]{1,}')\n\t\t\t\tif [[ ${PSQL_VERSION} =~ ^13\\.[0-9]{1,}$ ]]; then\n\t\t\t\t\tPSQL_VERSION=13\n\t\t\t\tfi\n\t\t\t\tPSQL_FOLDER=$(echo ${PSQL_VERSION} | sed 's/\\.//')\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tpostgresql-setup --initdb\n\t\t\t\telse\n\t\t\t\t\t\"/usr/pgsql-${PSQL_VERSION}/bin/postgresql-${PSQL_VERSION}-setup\" initdb\n\t\t\t\tfi\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tsystemctl enable postgresql\n\t\t\t\t\tsystemctl start postgresql\n\t\t\t\telse\n\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\tsystemctl start \"postgresql-${PSQL_VERSION}.service\"\n\t\t\t\t\t\tsystemctl enable \"postgresql-${PSQL_VERSION}.service\"\n\t\t\t\t\telse\n\t\t\t\t\t\t\"/etc/init.d/postgresql-${PSQL_VERSION}\" start\n\t\t\t\t\t\tchkconfig --levels 35 \"postgresql-${PSQL_VERSION}\" on\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tsed -e 's/peer/trust/g' -e 's/ident/trust/g' < \"/var/lib/pgsql/data/pg_hba.conf\" > \"/var/lib/pgsql/data/pg_hba.conf.1\"\n\t\t\t\t\tcd \"/var/lib/pgsql/data\" || exit\n\t\t\t\telse\n\t\t\t\t\tsed -e 's/peer/trust/g' -e 's/ident/trust/g' < \"/var/lib/pgsql/${PSQL_VERSION}/data/pg_hba.conf\" > \"/var/lib/pgsql/${PSQL_VERSION}/data/pg_hba.conf.1\"\n\t\t\t\t\tcd \"/var/lib/pgsql/${PSQL_VERSION}/data\" || exit\n\t\t\t\tfi\n\t\t\t\tmv pg_hba.conf pg_hba.conf_old\n\t\t\t\tmv pg_hba.conf.1 pg_hba.conf\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\tthen\n\t\t\t\t\tsystemctl restart postgresql\n\t\t\t\telse\n\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\tsystemctl restart \"postgresql-${PSQL_VERSION}.service\"\n\t\t\t\t\telse\n\t\t\t\t\t\t\"/etc/init.d/postgresql-${PSQL_VERSION}\" restart\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tinstall_geoip()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tif ! hash GeoIP-devel 2>&-;\n\t\t\t\tthen\n\t\t\t\t\tapt install -y php7.4-geoip php7.4-dev libgeoip-dev\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"php7.4-geoip php7.4-dev libgeoip-dev installation failed with error code ${error_code} (php7.4-geoip php7.4-dev libgeoip-dev installation failed with error code 50)\"\n\t\t\t\t\tfi\n\t\t\t\tfi\n\n\t\t\t\tif ! hash pecl/geoip 2>&-;\n\t\t\t\tthen\n\t\t\t\t\tpecl install geoip\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"pecl geoip installation failed with error code ${error_code} (pecl geoip installation failed with error code 47)\"\n\t\t\t\t\tfi\n\t\t\t\tfi\n\n\t\t\t\techo \"extension=geoip.so\" >> /etc/php.ini\n\n\t\t\t\tmkdir -v /usr/share/GeoIP\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"GeoIP folder creation failed with error code ${error_code} (GeoIP folder creation failed with error code 52)\"\n\t\t\t\tfi\n\t\t\t\tget_geoip_data\n\t\t\telse\n\t\t\t\tif ! hash pecl/geoip 2>&-;\n\t\t\t\tthen\n\t\t\t\t\tpecl install geoip\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"pecl geoip installation failed with error code ${error_code} (pecl geoip installation failed with error code 47)\"\n\t\t\t\t\t\treturn 47\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tconfigure_restyaboard()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n cp ${DOWNLOAD_DIR}/restyaboard.conf /etc/nginx/conf.d\n echo \"Changing server_name in nginx configuration...\"\n sed -i \"s/server_name.*$/server_name \\\"$IPADDR\\\";/\" /etc/nginx/conf.d/restyaboard.conf\n sed -i \"s|listen 80.*$|listen 80;|\" /etc/nginx/conf.d/restyaboard.conf\n mkdir -p \"$RESTYABOARD_DIR\"\n echo \"Changing root directory in nginx configuration...\"\n sed -i \"s|root.*html|root $RESTYABOARD_DIR|\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\telse\n cp ${DOWNLOAD_DIR}/restyaboard.conf /etc/nginx/conf.d\n sed -i \"s/server_name.*$/server_name \\\"$IPADDR\\\";/\" /etc/nginx/conf.d/restyaboard.conf\n sed -i \"s|listen 80.*$|listen 80;|\" /etc/nginx/conf.d/restyaboard.conf\n mkdir -p \"$RESTYABOARD_DIR\"\n echo \"Changing root directory in nginx configuration...\"\n sed -i \"s|root.*html|root $RESTYABOARD_DIR|\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\tfi\n\t\t}\n\t\tinstall_postfix()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \"Installing postfix...\"\n\t\t\t\techo \"postfix postfix/mailname string $IPADDR\"\\\n\t\t\t\t| debconf-set-selections &&\\\n\t\t\t\techo \"postfix postfix/main_mailer_type string 'Internet Site'\"\\\n\t\t\t\t| debconf-set-selections &&\\\n\t\t\t\tapt install -y postfix\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"postfix installation failed with error code ${error_code} (postfix installation failed with error code 16)\"\n\t\t\t\tfi\n\t\t\t\tPHP_VERSION=$(php --version | head -n 1 | cut -d \" \" -f 2 | grep --only-matching --perl-regexp \"^\\\\d\\.\\\\d+\")\n\t\t\t\tif [ -f \"/etc/php/${PHP_VERSION}/fpm/php.ini\" ] \n\t\t\t\tthen\n\t\t\t\t\tsed -i \"s/;sendmail_path =/sendmail_path = \\\"\\/usr\\/sbin\\/sendmail -t -i\\\"/g\" /etc/php/${PHP_VERSION}/fpm/php.ini\n\t\t\t\tfi\n\t\t\t\tif [ -f \"/etc/php/${PHP_VERSION}/cli/php.ini\" ] \n\t\t\t\tthen\n\t\t\t\t\tsed -i \"s/;sendmail_path =/sendmail_path = \\\"\\/usr\\/sbin\\/sendmail -t -i\\\"/g\" /etc/php/${PHP_VERSION}/cli/php.ini\n\t\t\t\tfi\n\t\t\t\tif [ -f \"/etc/php.ini\" ] \n\t\t\t\tthen\n\t\t\t\t\tsed -i \"s/;sendmail_path =/sendmail_path = \\\"\\/usr\\/sbin\\/sendmail -t -i\\\"/g\" /etc/php.ini\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tchange_permission()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\tthen\n\t\t\t\tchcon -R -t httpd_sys_rw_content_t $RESTYABOARD_DIR/media/ $RESTYABOARD_DIR/tmp/cache/ $RESTYABOARD_DIR/client/img/\n\t\t\t\tchcon -Rv --type=httpd_t $RESTYABOARD_DIR/\n\t\t\tfi\n\t\t}\n\t\tpsql_connect()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tpsql -U postgres -c \"\\q\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL Changing the permission failed with error code ${error_code} (PostgreSQL Changing the permission failed with error code 34)\"\n\t\t\t\t\treturn 34\n\t\t\t\tfi\n\t\t\t\tsleep 1\n\t\t\t\techo \"Creating PostgreSQL user and database...\"\n\t\t\t\tpsql -U postgres -c \"DROP USER IF EXISTS ${POSTGRES_DBUSER};CREATE USER ${POSTGRES_DBUSER} WITH ENCRYPTED PASSWORD '${POSTGRES_DBPASS}'\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL user creation failed with error code ${error_code} (PostgreSQL user creation failed with error code 35)\"\n\t\t\t\t\treturn 35\n\t\t\t\tfi\n\t\t\t\tpsql -U postgres -c \"CREATE DATABASE ${POSTGRES_DBNAME} OWNER ${POSTGRES_DBUSER} ENCODING 'UTF8' TEMPLATE template0\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL database creation failed with error code ${error_code} (PostgreSQL database creation failed with error code 36)\"\n\t\t\t\t\treturn 36\n\t\t\t\tfi\n\t\t\t\tpsql -U postgres -c \"CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL extension creation failed with error code ${error_code} (PostgreSQL extension creation failed with error code 37)\"\n\t\t\t\t\treturn 37\n\t\t\t\tfi\n\t\t\t\tpsql -U postgres -c \"COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} = 0 ];\n\t\t\t\tthen\n\t\t\t\t\techo \"Importing empty SQL...\"\n\t\t\t\t\tpsql -d ${POSTGRES_DBNAME} -f \"$RESTYABOARD_DIR/sql/restyaboard_with_empty_data.sql\" -U ${POSTGRES_DBUSER}\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"PostgreSQL Empty SQL importing failed with error code ${error_code} (PostgreSQL Empty SQL importing failed with error code 39)\"\n\t\t\t\t\t\treturn 39\n\t\t\t\t\tfi\n\t\t\t\tfi\n\t\t\telse\n\t\t\t\tpsql -U postgres -c \"\\q\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL Changing the permission failed with error code ${error_code} (PostgreSQL Changing the permission failed with error code 40)\"\n\t\t\t\t\treturn 40\n\t\t\t\tfi\t\t\t\n\t\t\t\tsleep 1\n\t\t\t\techo \"Creating PostgreSQL user and database...\"\n\t\t\t\tpsql -U postgres -c \"DROP USER IF EXISTS ${POSTGRES_DBUSER};CREATE USER ${POSTGRES_DBUSER} WITH ENCRYPTED PASSWORD '${POSTGRES_DBPASS}'\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL user creation failed with error code ${error_code} (PostgreSQL user creation failed with error code 41)\"\n\t\t\t\t\treturn 41\n\t\t\t\tfi\t\t\t\n\t\t\t\tpsql -U postgres -c \"CREATE DATABASE ${POSTGRES_DBNAME} OWNER ${POSTGRES_DBUSER} ENCODING 'UTF8' TEMPLATE template0\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL database creation failed with error code ${error_code} (PostgreSQL database creation failed with error code 42)\"\n\t\t\t\t\treturn 42\n\t\t\t\tfi\t\t\t\n\t\t\t\tpsql -U postgres -c \"CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\"\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL extension creation failed with error code ${error_code} (PostgreSQL extension creation failed with error code 43)\"\n\t\t\t\t\treturn 43\n\t\t\t\tfi\t\t\t\n\t\t\t\tpsql -U postgres -c \"COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';\"\n\t\t\t\tif [ \"$?\" = 0 ];\n\t\t\t\tthen\n\t\t\t\t\techo \"Importing empty SQL...\"\n\t\t\t\t\tpsql -d ${POSTGRES_DBNAME} -f \"$RESTYABOARD_DIR/sql/restyaboard_with_empty_data.sql\" -U ${POSTGRES_DBUSER}\n\t\t\t\t\terror_code=$?\n\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"PostgreSQL Empty SQL importing failed with error code ${error_code} (PostgreSQL Empty SQL importing failed with error code 45)\"\n\t\t\t\t\t\treturn 45\n\t\t\t\t\tfi\t\n\t\t\t\tfi\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\t\tthen\n\t\t\t\t\tsetsebool -P allow_postfix_local_write_mail_spool 1\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tphp_fpm_reset()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \".........\"\n\t\t\telse\n\t\t\t\techo \"Reset php-fpm (use unix socket mode)...\"\n\t\t\t\tif [ -f \"/run/php/php7.4-fpm.sock\" ]; then\n\t\t\t\t\tsed -i \"s/listen = 127.0.0.1:9000/listen = \\/run\\/php\\/php7.4-fpm.sock/g\" /etc/php-fpm.d/www.conf\n\t\t\t\telif [ -f \"/run/php-fpm/www.sock\" ]; then\n\t\t\t\t\tsed -i \"s/listen = 127.0.0.1:9000/listen = \\/run\\/php-fpm\\/www.sock/g\" /etc/php-fpm.d/www.conf\n\t\t\t\t\tsed -i \"s/unix:\\/run\\/php\\/php7.4-fpm.sock/unix:\\/run\\/php-fpm\\/www.sock/g\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\t\telse\n\t\t\t\t\tsed -i \"s/unix:\\/run\\/php\\/php7.4-fpm.sock/127.0.0.1:9000/g\" /etc/nginx/conf.d/restyaboard.conf\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tinstall_jq()\n\t\t{\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tapt install -y jq\n\t\t\t\terror_code=$?\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"jq installation failed with error code ${error_code} (jq installation failed with error code 53)\"\n\t\t\t\tfi\n\t\t\telse\n\t\t\t\tyum install -y jq\n\t\t\t\terror_code\n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"jq installation failed with error code ${error_code} (jq installation failed with error code 49)\"\n\t\t\t\t\treturn 49\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tset_db_connection()\n\t\t{\t\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\techo \"Starting services...\"\n\t\t\t\tservice cron restart\n\t\t\t\tservice php7.4-fpm restart\n\t\t\t\tservice nginx restart\n\t\t\t\tservice postfix restart\n\t\t\t\tapt install -y python-pip\n\t\t\t\tpip install virtualenv\n\t\t\telse\n\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\techo \"Starting services with systemd...\"\n\t\t\t\t\tsystemctl restart nginx\n\t\t\t\t\tsystemctl restart php-fpm\n\t\t\t\telse\n\t\t\t\t\techo \"Starting services...\"\n\t\t\t\t\t/etc/init.d/php-fpm restart\n\t\t\t\t\t/etc/init.d/nginx restart\n\t\t\t\tfi\n\t\t\t\tyum install -y python-pip\n\t\t\t\tpip install virtualenv\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\t\tthen\n\t\t\t\t\tsetsebool -P httpd_can_network_connect_db=1\n\t\t\t\tfi\n\t\t\tfi\n\t\t}\n\t\tssl_connectivity()\n\t\t{\n\t\t\tif [[ $IPADDR =~ ^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$ ]]; then\n\t\t\t\techo \"SSL connectivity cannot be set for IP address\"\n\t\t\telse\n\t\t\t\tset +x\n\t\t\t\techo \"Do you want to set up SSL connectivity for your domain and your domain should be publicly accessible Restyaboard instance and your domain should be mappped to this Restyaboard Server, Note: If you're trying to set SSL for Non-publicly accessible instance, then your Restyaboard will not work (y/n)?\"\n\t\t\t\tread -r answer\n\t\t\t\tset -x\n\t\t\t\tcase \"${answer}\" in\n\t\t\t\t\t[Yy])\n\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\t\t\tthen\n\t\t\t\t\t\tapt install certbot python3-certbot-nginx -y\n\t\t\t\t\t\tservice nginx restart\n\t\t\t\t\t\tservice php7.4-fpm restart\n\t\t\t\t\t\tcertbot --nginx\n\t\t\t\t\telse\n\t\t\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\tdnf -y install epel-release\n\t\t\t\t\t\t\tdnf -y install certbot python3-certbot-nginx\n\t\t\t\t\t\t\tcertbot --nginx\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tyum install -y epel-release\n\t\t\t\t\t\t\tyum install certbot-nginx\n\t\t\t\t\t\t\tcertbot --nginx\n\t\t\t\t\t\tfi\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"SSL installation failed with error code ${error_code} (php installation failed with error code 20)\"\n\t\t\t\t\t\t\treturn 20\n\t\t\t\t\t\tfi\n\t\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\t\techo \"Starting services with systemd...\"\n\t\t\t\t\t\t\tsystemctl restart nginx\n\t\t\t\t\t\t\tsystemctl restart php-fpm\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\techo \"Starting services...\"\n\t\t\t\t\t\t\t/etc/init.d/php-fpm restart\n\t\t\t\t\t\t\t/etc/init.d/nginx restart\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tesac\n\t\t\tfi\n\t\t}\n\t\tfind_release\n\t\tcheckdeps\n\t\tif ([ \"$pkg_name\" = \"apt-get\" ])\n then\n\t\t\tapt update\n apt install -y net-tools\n\t\t\tapt install -y curl unzip\n\t\telse\n\t\t\tif ([ \"$pkg_name\" = \"yum\" ])\n \tthen\n yum install -y net-tools\n\t\t\t\tyum install -y curl unzip\n\t\t\tfi\n\t\tfi\n IFCONFIG_PATH=$(which ifconfig)\n IPADDR=$(${IFCONFIG_PATH} eth0 | awk '/inet / { print $2 }' | sed 's/addr://')\n\t\tRESTYABOARD_VERSION=$(curl --silent https://api.github.com/repos/RestyaPlatform/board/releases | grep tag_name -m 1 | awk '{print $2}' | sed -e 's/[^v0-9.]//g')\n\t\tPOSTGRES_DBHOST=localhost\n\t\tPOSTGRES_DBNAME=restyaboard\n\t\tPOSTGRES_DBUSER=restya\n\t\tPOSTGRES_DBPASS=hjVl2!rGd\n\t\tPOSTGRES_DBPORT=5432\n\t\tDOWNLOAD_DIR=/opt/restyaboard\n RESTYABOARD_DIR=/usr/share/nginx/html/restyaboard\n\t\t\n\t\tget_geoip_data () \n\t\t{\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIP.dat.gz\n\t\t\tgunzip GeoIP.dat.gz\n\t\t\tmv GeoIP.dat /usr/share/GeoIP/GeoIP.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIPv6.dat.gz\n\t\t\tgunzip GeoIPv6.dat.gz\n\t\t\tmv GeoIPv6.dat /usr/share/GeoIP/GeoIPv6.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.xz\n\t\t\tunxz GeoLiteCity.dat.xz\n\t\t\tmv GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoLiteCityv6.dat.gz\n\t\t\tgunzip GeoLiteCityv6.dat.gz\n\t\t\tmv GeoLiteCityv6.dat /usr/share/GeoIP/GeoLiteCityv6.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIPASNum.dat.gz\n\t\t\tgunzip GeoIPASNum.dat.gz\n\t\t\tmv GeoIPASNum.dat /usr/share/GeoIP/GeoIPASNum.dat\n\t\t\twget https://mirrors-cdn.liferay.com/geolite.maxmind.com/download/geoip/database/GeoIPASNumv6.dat.gz\n\t\t\tgunzip GeoIPASNumv6.dat.gz\n\t\t\tmv GeoIPASNumv6.dat /usr/share/GeoIP/GeoIPASNumv6.dat\n\t\t}\n\n\t\tupgrade-0.3-0.4()\n\t\t{\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/chat_activities.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/0 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/periodic_chat_email_notification.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/indexing_to_elasticsearch.sh//\" /var/spool/cron/crontabs/root\n\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/upgrade_v0.2.1_v0.3.php\n\n\t\t\trm -rf $RESTYABOARD_DIR/client/apps/\n\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/jaxl3/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp-prebind-php/\n\t\t}\n\n\t\tupgrade-0.4-0.4.1()\n\t\t{\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/chat_activities.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/0 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/periodic_chat_email_notification.sh//\" /var/spool/cron/crontabs/root\n\t\t\tsed -i \"s/*\\/5 * * * * $RESTYABOARD_DIR\\/server\\/php\\/shell\\/indexing_to_elasticsearch.sh//\" /var/spool/cron/crontabs/root\n\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/chat_activities.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/indexing_to_elasticsearch.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.sh\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/periodic_chat_email_notification.php\n\t\t\trm $RESTYABOARD_DIR/server/php/shell/upgrade_v0.2.1_v0.3.php\n\n\t\t\trm -rf $RESTYABOARD_DIR/client/apps/\n\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/jaxl3/\n\t\t\trm -rf $RESTYABOARD_DIR/server/php/libs/vendors/xmpp-prebind-php/\n\t\t}\n\n\t\tupgrade-0.5.2-0.6()\n\t\t{\n\t\t\tsed -i \"s/rewrite ^\\/ical\\/.*/rewrite ^\\/ical\\/([0-9]*)\\/([0-9]*)\\/([a-z0-9]*).ics\\$ \\/server\\/php\\/ical.php?board_id=\\$1\\&user_id=\\$2\\&hash=\\$3 last;/\" /etc/nginx/conf.d/restyaboard.conf\n\t\t}\n\n\t\tupgrade-0.6.3-0.6.4()\n\t\t{\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps/r_hide_card_created_date\" ]; then\n\t\t\t\trm -rf $RESTYABOARD_DIR/client/apps/r_hide_card_created_date/\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_hide_card_additional_informations-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_hide_card_additional_informations-v0.1.1.zip\n\t\t\t\tunzip /tmp/r_hide_card_additional_informations-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t}\n\n\t\tupgrade-0.6.4-0.6.5()\n\t\t{\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps/r_hide_card_id\" ]; then\n\t\t\t\trm -rf $RESTYABOARD_DIR/client/apps/r_hide_card_id/\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_hide_card_additional_informations-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_hide_card_additional_informations-v0.1.2.zip\n\t\t\t\tunzip /tmp/r_hide_card_additional_informations-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t}\n\n\t\tupgrade-0.6.5-0.6.6()\n\t\t{\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.1.zip\n\t\t\t\tunzip /tmp/r_codenames-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.1.zip\n\t\t\t\tunzip /tmp/r_codenames-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t}\n\t\t\n\t\tupgrade-0.6.6-0.6.7(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_card_counter-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_card_counter-v0.1.1.zip\n\t\t\tunzip /tmp/r_card_counter-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.2.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n\t\t\tcurl -v -L -G -o /tmp/r_eu_gdpr-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_eu_gdpr-v0.1.2.zip\n\t\t\tunzip /tmp/r_eu_gdpr-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n\t\t\tcurl -v -L -G -o /tmp/r_gmail_addon-v0.1.1.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_gmail_addon-v0.1.1.zip\n\t\t\tunzip /tmp/r_gmail_addon-v0.1.1.zip -d \"$RESTYABOARD_DIR/client/apps\"\t\t\t\n\t\t\t\n\t\t\tcurl -v -L -G -o /tmp/r_hide_card_additional_informations-v0.1.3.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_hide_card_additional_informations-v0.1.3.zip\n\t\t\tunzip /tmp/r_hide_card_additional_informations-v0.1.3.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n find \"$RESTYABOARD_DIR/client/apps\" -type d -exec chmod 755 {} \\;\n find \"$RESTYABOARD_DIR/client/apps\" -type f -exec chmod 644 {} \\;\n chmod 0777 $RESTYABOARD_DIR/client/apps/**/*.json\n\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\t: > /var/spool/cron/crontabs/root\n\t\t\t\techo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/crontabs/root\n\t\t\telse\n\t\t\t\t: > /var/spool/cron/root\n\t\t\t\techo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/root\n\t\t\tfi\n\t\t}\n\n\t\tupgrade-0.6.7-0.6.8(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.3.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.3.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.3.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n find \"$RESTYABOARD_DIR/client/apps\" -type d -exec chmod 755 {} \\;\n find \"$RESTYABOARD_DIR/client/apps\" -type f -exec chmod 644 {} \\;\n chmod 0777 $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t}\n\n\t\tupgrade-0.6.8-0.6.9(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.4.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.4.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.4.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\n find \"$RESTYABOARD_DIR/client/apps\" -type d -exec chmod 755 {} \\;\n find \"$RESTYABOARD_DIR/client/apps\" -type f -exec chmod 644 {} \\;\n chmod 0777 $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t}\n\t\tupgrade-0.6.9-1.7(){\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps/r_togetherjs\" ]; then\n\t\t\t\trm -rf $RESTYABOARD_DIR/client/apps/r_togetherjs/\n\t\t\tfi\n\t\t\tif [ -d \"$RESTYABOARD_DIR/client/apps\" ]; then\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\telse \n\t\t\t\tmkdir \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\tchmod -R go+w \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tfi\n\t\t\tcurl -v -L -G -o /tmp/r_codenames-v0.1.5.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_codenames-v0.1.5.zip\n\t\t\tunzip /tmp/r_codenames-v0.1.5.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tcurl -v -L -G -o /tmp/r_gmail_addon-v0.1.2.zip https://github.com/RestyaPlatform/board-apps/releases/download/v1/r_gmail_addon-v0.1.2.zip\n\t\t\tunzip /tmp/r_gmail_addon-v0.1.2.zip -d \"$RESTYABOARD_DIR/client/apps\"\n\t\t\t\n\t\t\techo \"Applying permission...\"\n\t\t\tuseradd restyaboard\n\t\t\tusermod --password 'hjVl2!rGd' restyaboard\n\t\t\tPHP_VERSION=$(php --version | head -n 1 | cut -d \" \" -f 2 | grep --only-matching --perl-regexp \"^\\\\d\\.\\\\d+\")\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\tthen\n\t\t\t\tuser www-data;\n\t\t\t\tusermod -a -G restyaboard www-data\n\t\t\t\tsed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php/${PHP_VERSION}/fpm/pool.d/www.conf\n\t\t\t\tsed -i \"s/user\\s*=\\s*www-data/user = restyaboard/g\" /etc/php/${PHP_VERSION}/fpm/pool.d/www.conf\n\t\t\t\tsed -i \"0,/group\\s*=\\s*www-data/s//group = restyaboard/g\" /etc/php/${PHP_VERSION}/fpm/pool.d/www.conf\n\t\t\telse\n\t\t\t\tuser nginx;\n\t\t\t\tusermod -a -G restyaboard nginx\n\t\t\t\tsed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php-fpm.d/www.conf\n\t\t\t\tsed -i \"s/user\\s*=\\s*apache/user = restyaboard/g\" /etc/php-fpm.d/www.conf\n\t\t\t\tsed -i \"0,/group\\s*=\\s*apache/s//group = restyaboard/g\" /etc/php-fpm.d/www.conf\n\t\t\tfi\n\t\t\tchown -R restyaboard:restyaboard $RESTYABOARD_DIR\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/media\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/media;\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/client/img\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/client/img;\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/tmp/cache\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/tmp/cache;\n\t\t\tchmod +x $RESTYABOARD_DIR/server/php/shell/main.sh\n\t\t\tchown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tchmod -R u=rwX,g=rX,o= \"$RESTYABOARD_DIR/client/apps\"\n\t\t\tchmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ])\n\t\t\tthen\n\t\t\t\tchcon -R -t httpd_sys_rw_content_t $RESTYABOARD_DIR/client/apps/**/*.json\n\t\t\tfi\n\t\t}\n\n\t\tupdate_version()\n\t\t{\n\t\t\tset +x\n\t\t\techo -e \"A newer version ${RESTYABOARD_VERSION} of Restyaboard is available.\\n\\nImportant: Please note that upgrading will remove any commercial apps that were free in previous version.\\nFor more details about commercial apps, please visit https://restya.com/board/pricing\\n\\nDo you want to get it now y/n?\"\n\t\t\tread -r answer\n\t\t\tset -x\n\t\t\tcase \"${answer}\" in\n\t\t\t\t[Yy])\n\t\t\t\tset +x\n\t\t\t\tset -x\n\t\t\t\t\n\t\t\t\techo \"Downloading files...\"\n\t\t\t\tcurl -v -L -G -d \"app=board&ver=${RESTYABOARD_VERSION}\" -o /tmp/restyaboard.zip -k https://restya.com/download.php\n\t\t\t\tunzip /tmp/restyaboard.zip -d ${DOWNLOAD_DIR}\n\t\t\t\t\n\t\t\t\techo \"Updating files...\"\n\t\t\t\tcp -r ${DOWNLOAD_DIR}/. \"$RESTYABOARD_DIR\"\n\t\t\t\t\n\t\t\t\techo \"Connecting database to run SQL changes...\"\n\t\t\t\tpsql -U postgres -c \"\\q\"\n\t\t\t\terror_code=$? \n\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\tthen\n\t\t\t\t\techo \"PostgreSQL database connection failed with error code ${error_code} (PostgreSQL database connection failed with error code 32)\"\n\t\t\t\t\treturn 32\n\t\t\t\tfi\n\t\t\t\tsleep 1\n\t\t\t\t\n\t\t\t\techo \"Changing PostgreSQL database name, user and password...\"\n\t\t\t\tsed -i \"s/^.*'R_DB_NAME'.*$/define('R_DB_NAME', '${POSTGRES_DBNAME}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_USER'.*$/define('R_DB_USER', '${POSTGRES_DBUSER}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_PASSWORD'.*$/define('R_DB_PASSWORD', '${POSTGRES_DBPASS}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_HOST'.*$/define('R_DB_HOST', '${POSTGRES_DBHOST}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tsed -i \"s/^.*'R_DB_PORT'.*$/define('R_DB_PORT', '${POSTGRES_DBPORT}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n\t\t\t\tPHP_VERSION=$(php --version | head -n 1 | cut -d \" \" -f 2 | grep --only-matching --perl-regexp \"^\\\\d\\.\\\\d+\")\n\t\t\t\tversion=$(cat ${DOWNLOAD_DIR}/release)\n\t\t\t\tdeclare -a upgrade;\n\t\t\t\tif [[ $version < \"v0.4\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.3-0.4\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.4.1\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.4-0.4.1\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.5\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.4.2-0.5\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.5.2\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.5.1-0.5.2\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.5.2-0.6\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.1\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6-0.6.1\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.2\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.1-0.6.2\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.3\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.2-0.6.3\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.4\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.3-0.6.4\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.5\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.4-0.6.5\")\n\t\t\t\tfi\t\n\t\t\t\tif [[ $version < \"v0.6.6\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.5-0.6.6\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.7\" ]];\n\t\t\t\tthen\n\t\t\t\t\tset +x\n\t\t\t\t\techo \"Before updating make sure to remove duplicate username's and emails used by more than one user, otherwise unique indexing for users will be thrown an error But all other queries will be executed without any issue.\"\n\t\t\t\t\tread -r -s -p $'Press [Enter] key to continue...'\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.6-0.6.7\")\n\t\t\t\tfi\n\t\t\t\tif [[ $version < \"v0.6.8\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.7-0.6.8\")\n\t\t\t\tfi\t\t \n\t\t\t\tif [[ $version < \"v0.6.9\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.8-0.6.9\")\n\t\t\t\tfi\t\n\t\t\t\tif [[ $version < \"v1.7\" ]];\n\t\t\t\tthen\n\t\t\t\t\tupgrade+=(\"upgrade-0.6.9-1.7\")\n\t\t\t\tfi\n\t\t\t\t# use for loop to read all values and indexes\n\t\t\t\tfor i in \"${upgrade[@]}\"\n\t\t\t\tdo\n\t\t\t\t\tif [ \"$(type -t ${i})\" = function ];\n\t\t\t\t\tthen\n\t\t\t\t\t\teval ${i}\n\t\t\t\t\tfi\n\t\t\t\t\tif [ -f \"$RESTYABOARD_DIR/sql/${i}.sql\" ];\n\t\t\t\t\tthen\n\t\t\t\t\t\techo \"Updating SQL...\"\n\t\t\t\t\t\tpsql -d ${POSTGRES_DBNAME} -f \"$RESTYABOARD_DIR/sql/${i}.sql\" -U ${POSTGRES_DBUSER}\n\t\t\t\t\t\terror_code=$?\n\t\t\t\t\t\tif [ ${error_code} != 0 ]\n\t\t\t\t\t\tthen\n\t\t\t\t\t\t\techo \"PostgreSQL updation of SQL failed with error code ${error_code} (PostgreSQL updation of SQL failed with error code 33)\"\n\t\t\t\t\t\t\treturn 33\n\t\t\t\t\t\tfi\n\t\t\t\t\tfi\n\t\t\t\tdone\n\t\t\t\t/bin/echo \"$RESTYABOARD_VERSION\" > ${DOWNLOAD_DIR}/release\n\n\t\t\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\t\t\tthen\t\t\t\t \n service nginx restart\n\t\t\t\t\tservice php${PHP_VERSION}-fpm restart\n\t\t\t\telse\n\t\t\t\t\tif [ -f \"/bin/systemctl\" ]; then\n\t\t\t\t\t\techo \"Starting services with systemd...\"\n\t\t\t\t\t\tsystemctl restart nginx\n\t\t\t\t\t\tsystemctl restart php-fpm\n\t\t\t\t\telse\n\t\t\t\t\t\techo \"Starting services...\"\n\t\t\t\t\t\t/etc/init.d/php-fpm restart\n\t\t\t\t\t\t/etc/init.d/nginx restart\n\t\t\t\t\tfi\n\t\t\t\tfi\n\n\t\t\tesac\n\t\t}\n\n\t\tif [ -f \"$DOWNLOAD_DIR/release\" ];\n\t\tthen\n\t\t\tversion=$(cat ${DOWNLOAD_DIR}/release)\n\t\t\tif [[ $version < $RESTYABOARD_VERSION ]];\n\t\t\tthen\n\t\t\t\tupdate_version\n\t\t\t\texit;\n\t\t\telse\n\t\t\t\techo \"No new version available\"\n\t\t\t\texit;\n\t\t\tfi\n\t\telse\n\t\t\tset +x\n\t\t\techo \"Is Restyaboard already installed and configured/working y/n?\"\n\t\t\tread -r answer\n\t\t\tset -x\n\t\t\tcase \"${answer}\" in\n\t\t\t\t[Yy])\n\t\t\t\tupdate_version\n\t\t\t\texit;\n\t\t\tesac\n\t\tfi\n\n if ([ \"$OS_REQUIREMENT\" = \"Debian\" ])\n then\n sed -i -e 's/deb cdrom/#deb cdrom/g' /etc/apt/sources.list\n sh -c 'echo \"deb http://ftp.de.debian.org/debian jessie main\" > /etc/apt/sources.list.d/debjessie.list'\n apt install apt-transport-https lsb-release ca-certificates -y\n wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg\n echo \"deb https://packages.sury.org/php/ $(lsb_release -sc) main\" | tee /etc/apt/sources.list.d/php.list\n fi\n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n apt install debian-keyring debian-archive-keyring -y\n apt update -y\n apt upgrade -y\n apt install python-software-properties -y\n apt install software-properties-common -y\n if ! hash php 2>&-; then\n add-apt-repository -y ppa:ondrej/php\n apt update -y\n apt install libjpeg8 -y --allow-unauthenticated\n fi\n fi\n install_nginx\n \n echo \"Checking PHP...\"\n install_php\n\n echo \"Setting up timezone...\"\n set_timezone\n \n echo \"Checking PostgreSQL...\"\n install_postgresql\n\n install_geoip\n \n echo \"Downloading Restyaboard script...\"\n if ([ \"$pkg_name\" = \"apt-get\" ])\n then\n apt install -y curl\n fi\n mkdir ${DOWNLOAD_DIR}\n curl -v -L -G -d \"app=board&ver=${RESTYABOARD_VERSION}\" -o /tmp/restyaboard.zip -k https://restya.com/download.php\n unzip /tmp/restyaboard.zip -d ${DOWNLOAD_DIR}\n rm /tmp/restyaboard.zip\n\n configure_restyaboard\n \n \n echo \"Copying Restyaboard script to root directory...\"\n cp -r ${DOWNLOAD_DIR}/* \"$RESTYABOARD_DIR\"\n \n install_postfix\n \n echo \"Changing permission...\"\n useradd restyaboard\n usermod --password 'hjVl2!rGd' restyaboard\n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n user www-data;\n usermod -a -G restyaboard www-data\n sed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php/7.4/fpm/pool.d/www.conf\n sed -i \"s/user\\s*=\\s*www-data/user = restyaboard/g\" /etc/php/7.4/fpm/pool.d/www.conf\n sed -i \"0,/group\\s*=\\s*www-data/s//group = restyaboard/g\" /etc/php/7.4/fpm/pool.d/www.conf\n else\n user nginx;\n usermod -a -G restyaboard nginx\n sed -i \"s/\\[www\\]/[restyaboard] group=restyaboard/g\" /etc/php-fpm.d/www.conf\n sed -i \"s/user\\s*=\\s*apache/user = restyaboard/g\" /etc/php-fpm.d/www.conf\n sed -i \"0,/group\\s*=\\s*apache/s//group = restyaboard/g\" /etc/php-fpm.d/www.conf\n fi\n chown -R restyaboard:restyaboard $RESTYABOARD_DIR\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR\n chown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/media\"\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/media;\n chown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/client/img\"\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/client/img;\n chown -R restyaboard:restyaboard \"$RESTYABOARD_DIR/tmp/cache\"\n chmod -R u=rwX,g=rX,o= $RESTYABOARD_DIR/tmp/cache;\n chmod +x $RESTYABOARD_DIR/server/php/shell/main.sh\n change_permission\n\n psql_connect\n \n echo \"Changing PostgreSQL database name, user and password...\"\n sed -i \"s/^.*'R_DB_NAME'.*$/define('R_DB_NAME', '${POSTGRES_DBNAME}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_USER'.*$/define('R_DB_USER', '${POSTGRES_DBUSER}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_PASSWORD'.*$/define('R_DB_PASSWORD', '${POSTGRES_DBPASS}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_HOST'.*$/define('R_DB_HOST', '${POSTGRES_DBHOST}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n sed -i \"s/^.*'R_DB_PORT'.*$/define('R_DB_PORT', '${POSTGRES_DBPORT}');/g\" \"$RESTYABOARD_DIR/server/php/config.inc.php\"\n \n echo \"Setting up cron for every 5 minutes..\"\n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n echo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/crontabs/root\n else\n echo \"*/5 * * * * $RESTYABOARD_DIR/server/php/shell/main.sh > /dev/null 2> /dev/null\" >> /var/spool/cron/root\n fi\n php_fpm_reset\n \n if ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n then\n service nginx restart\n service php7.4-fpm restart\n else\n if [ -f \"/bin/systemctl\" ]; then\n echo \"Starting services with systemd...\"\n systemctl restart nginx\n systemctl restart php-fpm\n else\n echo \"Starting services...\"\n /etc/init.d/php-fpm restart\n /etc/init.d/nginx restart\n fi\n fi\n set_db_connection\n\t\t/bin/echo \"$RESTYABOARD_VERSION\" > ${DOWNLOAD_DIR}/release\n\t\tif ([ \"$OS_REQUIREMENT\" = \"Ubuntu\" ] || [ \"$OS_REQUIREMENT\" = \"Debian\" ] || [ \"$OS_REQUIREMENT\" = \"LinuxMint\" ] || [ \"$OS_REQUIREMENT\" = \"Raspbian\" ])\n\t\tthen\n\t\t\tssl_connectivity\n\t\telse\n\t\t\tssl_connectivity\n\t\tfi\n\t\tif ([ \"$OS_REQUIREMENT\" = \"CentOS\" ] && [ \"$OS_VERSION\" = \"8\" ])\n then\n\t\t\tsemanage permissive -a httpd_t\n\t\tfi\n\t\tset +x\n\t\techo \"Checking Hosting...\"\n\t\tresponse=$(curl -H Metadata:true http://169.254.169.254/metadata/instance?api-version=2017-04-02 --write-out %{http_code} --connect-timeout 10 --max-time 10 --silent --output /dev/null)\n\t\t\n\t\tif [ -f /etc/ImageMagick-6/policy.xml ]; then\n \t\tsed -i -e 's///g' /etc/ImageMagick-6/policy.xml\n\t\tfi\n\n\t\tif [ -f /etc/ImageMagick/policy.xml ]; then\n\t\t\tsed -i -e 's///g' /etc/ImageMagick/policy.xml\n\t\tfi\n\n\t\tif [ ${response} -eq 200 ];then\n\t\t\techo \"Note: PHP Mailer will not work in Azure. Kindly use external SMTP mail server.\"\n\t\tfi\n\t\tset +x\n\t\tcurl -v -L -G -d \"app=board&os=${os}&version=${version}\" -k \"https://restya.com/success_installation.php\"\n\t\techo \"Restyaboard URL : $IPADDR\"\n\n\t\techo \"Login with username admin and password restya\"\n\t\texit 1\n\t}\n\tmain\n\terror=$?\n\tos=$(lsb_release -i -s)\n\tcurl -v -L -G -d \"app=board&os=${os}&error=${error}\" -k \"https://restya.com/error_installation.php\"\n\techo \"If you're finding it difficult to install Restyaboard from your end, we do also offer installation support that you may consider https://restya.com/contact\"\n\texit 1\n} 2>&1 | tee -a /tmp/restyaboard_install.log","user_defined_fields":[]},{"id":912264,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Rocket.Chat One-Click","description":"Rocket.Chat One-Click","ordinal":97,"logo_url":"assets/rocketchat.svg","images":["linode/ubuntu20.04"],"deployments_total":1810,"deployments_active":91,"is_public":true,"mine":false,"created":"2021-09-29T17:16:16","updated":"2023-12-11T15:12:25","rev_note":"","script":"#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Update system & set hostname & basic security\nset_hostname\napt_setup_update\nufw_install\nufw allow 443\nufw allow 80\nufw allow 3000\nfail2ban_install\n\n# Snapd & rocketchat install\napt install snapd -y\nsnap install rocketchat-server\nsnap info rocketchat-server\n\n# Check DNS\ncheck_dns_propagation \"${FQDN}\" \"${IP}\"\n# SSL\nsnap set rocketchat-server siteurl=https://$FQDN\nsystemctl enable --now snap.rocketchat-server.rocketchat-caddy \nsnap restart rocketchat-server\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address for the SOA","default":""}]},{"id":609048,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Ruby on Rails One-Click","description":"Ruby on Rails One-Click","ordinal":98,"logo_url":"assets/rubyonrails.svg","images":["linode/ubuntu20.04"],"deployments_total":459,"deployments_active":20,"is_public":true,"mine":false,"created":"2019-11-05T07:22:54","updated":"2023-12-09T10:22:03","rev_note":"Initial import","script":"#!/bin/bash\n#\n\nsource \nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Set hostname, configure apt and perform update/upgrade\nset_hostname\napt_setup_update\n\n# Install Ruby on Rails\napt install -y ruby rails\n\n# Configure rails Directory\nmkdir /home/railsapp\ncd /home/railsapp\nrails new $RAILSAPP\ncd $RAILSAPP\nrails s -b 0.0.0.0 &\n\n# Start rails app on reboot\ncrontab -l | { cat; echo \"@reboot cd /home/railsapp/app1/ && rails s -b 0.0.0.0 &\"; } | crontab -\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"railsapp","label":"Rails Application name","example":"railsapp"}]},{"id":401703,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Rust One-Click","description":"Rust - Latest One-Click","ordinal":99,"logo_url":"assets/Rust.svg","images":["linode/ubuntu20.04"],"deployments_total":2455,"deployments_active":8,"is_public":true,"mine":false,"created":"2019-03-08T21:09:34","updated":"2023-12-10T08:41:10","rev_note":"Remove SSH Pubkey UDF","script":"#!/bin/bash\n#\n#\n#\n#\n#\n#\n#\n#\n#\n#\n\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \nsource \n\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\nGAMESERVER=\"rustserver\"\n\nset_hostname\napt_setup_update\n\n\nif [[ \"$RUSTHOSTNAME\" = \"\" ]]; then\n RUSTHOSTNAME=\"Linode Rust Server\"\nfi\n\nif [[ \"$LEVEL\" = \"Procedural Map\" ]]; then\n LEVEL=\"\"\nfi\n\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix curl \\\nwget file bzip2 gzip unzip bsdmainutils python \\\nutil-linux ca-certificates binutils bc jq tmux \\\nlib32gcc1 libstdc++6 libstdc++6:i386 lib32z1\n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install Rust\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\n#Game Config Options\n\ncp /home/rustserver/lgsm/config-lgsm/rustserver/_default.cfg /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\nchown -R rustserver:rustserver /home/rustserver/\n\necho \"server.globalchat $GLOBALCHAT/\" > /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.pve $PVE\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.description \\\"$DESCRIPTION\\\"\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.maxplayers $MAXPLAYERS\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.seed \\\"$SEED\\\"\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.level $LEVEL\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.hostname \\\"$RUSTHOSTNAME\\\"\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\necho \"server.ip $IP\" >> /home/rustserver/serverfiles/server/rustserver/cfg/server.cfg\nsed -i \"s/rconpassword=\\\"CHANGE_ME\\\"/rconpassword=\\\"$RCONPASSWORD\\\"/\" /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\nsed -i \"s/worldsize=\\\"3000\\\"/worldsize=\\\"$WORLDSIZE\\\"/\" /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\nsed -i \"s/maxplayers=\\\"50\\\"/maxplayers=\\\"$MAXPLAYERS\\\"/\" /home/rustserver/lgsm/config-lgsm/rustserver/common.cfg\n\n\n# Start the service and setup firewall\nufw allow 28015\nufw allow 28016\n\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup","user_defined_fields":[{"name":"rusthostname","label":"Server Hostname","default":"Linode Rust Server"},{"name":"description","label":"Server Description","default":"Powered by Linode!"},{"name":"rconpassword","label":"RCON Password"},{"name":"maxplayers","label":"Maximum Players","oneof":"10,25,50,75,100","default":"50"},{"name":"level","label":"World","oneof":"Procedural Map,Barren,HapisIsland,SavasIsland_koth","default":"Procedural Map"},{"name":"worldsize","label":"World Size","oneof":"1000,3000,6000","default":"3000"},{"name":"seed","label":"Seed","default":"50000"},{"name":"globalchat","label":"Global Chat Enabled","oneof":"true,false","default":"true"},{"name":"pve","label":"PvE Enabled","oneof":"true,false","default":"false"}]},{"id":971042,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Saltcorn One-Click","description":"Saltcorn One-Click","ordinal":100,"logo_url":"assets/saltcorn.svg","images":["linode/ubuntu20.04","linode/debian11"],"deployments_total":304,"deployments_active":6,"is_public":true,"mine":false,"created":"2022-02-08T16:21:05","updated":"2023-12-02T23:13:46","rev_note":"","script":"#!/bin/bash\n## Saltcorn Settings\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\nfunction saltcorninstall {\n wget -qO - https://deb.nodesource.com/setup_14.x | sudo bash -\n apt-get install -qqy nodejs\n npx saltcorn-install -y\n systemctl enable saltcorn\n systemctl stop saltcorn\n cat < /lib/systemd/system/saltcorn.service\n[Unit]\nDescription=saltcorn\nDocumentation=https://saltcorn.com\nAfter=network.target\n\n[Service]\nType=notify\nWatchdogSec=5\nUser=saltcorn\nWorkingDirectory=/home/saltcorn\nExecStart=/home/saltcorn/.local/bin/saltcorn serve -p 8080\nRestart=always\nEnvironment=\"NODE_ENV=production\"\n\n[Install]\nWantedBy=multi-user.target\nEND\n systemctl daemon-reload\n systemctl start saltcorn\n}\n\nfunction firewallsaltcorn {\n ufw allow 22\n ufw allow 80\n ufw allow 443\n}\n\nfunction nginxreversesaltcorn {\n apt-get install nginx -y\n cat < /etc/nginx/conf.d/saltcorn.conf\nserver {\n listen 80;\n server_name $FQDN $IP;\n\n location / {\n proxy_set_header X-Forwarded-For \\$remote_addr;\n proxy_set_header Host \\$http_host;\n proxy_pass http://localhost:8080;\n }\n}\nEND\n nginx -t\n unlink /etc/nginx/sites-enabled/default\n systemctl restart nginx\n}\n\nfunction ssl_saltcorn {\napt install certbot python3-certbot-nginx -y\ncertbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'nginx'\n}\n\nfunction main {\n saltcorninstall\n nginxreversesaltcorn\n firewallsaltcorn\n ssl_saltcorn\n\n}\n# Execute\nmain \nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address for Letsencrypt SSL","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":774829,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"ServerWand One-Click","description":"ServerWand One-Click","ordinal":101,"logo_url":"assets/serverwand.svg","images":["linode/ubuntu22.04"],"deployments_total":1085,"deployments_active":11,"is_public":true,"mine":false,"created":"2021-02-19T17:28:16","updated":"2023-12-11T22:11:37","rev_note":"","script":"#!/bin/bash\n\n# Logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# serverwand ssh key\nmkdir -p /root/.ssh/\nchmod 700 /root/.ssh/\ncurl https://serverwand.com/api/servers/connect > ~/.ssh/authorized_keys\nchmod 600 /root/.ssh/authorized_keys","user_defined_fields":[]},{"id":1177225,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Seatable One-Click","description":"Seatable One-Click App","ordinal":102,"logo_url":"assets/seatable.svg","images":["linode/debian11"],"deployments_total":44,"deployments_active":1,"is_public":true,"mine":false,"created":"2023-05-16T19:56:00","updated":"2023-12-04T16:58:01","rev_note":"","script":"#!/bin/bash\n\n# \n# \n# \n\nsource \n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION \n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Update and basic installs\nsystem_update\ndebian_upgrade\nenable_fail2ban\nsystem_install_package ufw ca-certificates curl gnupg lsb-release curl pwgen\n\n# Install docker\nmkdir -p /etc/apt/keyrings\ncurl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg\necho \\\n \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \\\n $(lsb_release -cs) stable\" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\nchmod a+r /etc/apt/keyrings/docker.gpg\napt-get -y update\napt-get -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin docker-compose\n\n# Pull current seatable container\ndocker pull seatable/seatable-enterprise:latest\nmkdir /opt/seatable\nwget -O \"/opt/seatable/docker-compose.yml\" \"https://manual.seatable.io/docker/Enterprise-Edition/docker-compose.yml\"\n\n# Prepare SeaTable\nMYSQL_PASSWORD=`pwgen -s 30 1`\nsed -i \"s|DB_ROOT_PASSWD=.*|DB_ROOT_PASSWD=${MYSQL_PASSWORD}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|MYSQL_ROOT_PASSWORD=.*|MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|SEATABLE_SERVER_LETSENCRYPT=.*|SEATABLE_SERVER_LETSENCRYPT=${LE}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|SEATABLE_SERVER_HOSTNAME=.*|SEATABLE_SERVER_HOSTNAME=${URL}|\" /opt/seatable/docker-compose.yml\nsed -i \"s|TIME_ZONE=.*|TIME_ZONE=${TIMEZONE}|\" /opt/seatable/docker-compose.yml\n\n# Add a license\nmkdir -p /opt/seatable/seatable-data/seatable\ntouch /opt/seatable/seatable-data/seatable/seatable-license.txt\ncat << EOF > /opt/seatable/seatable-data/seatable/seatable-license.txt\n#SeaTable server licence\nName = \"Cloud Trial\"\nLicencetype = \"User\"\nLicenceKEY = \"1672935702\"\nProductID = \"SeaTable server\"\nExpiration = \"2024-01-31\"\nMaxUsers = \"3\"\nMode = \"subscription\"\nHash = \"045af708265d7d549cad51fc2b678272a1d15ab8cbfbf05734e371504bb72b388f4441493c7bfeccce7c19ac9c6877cb8f3aecc3beebe685db007832e1c0231728a92772d45dc1c08facbc225d90776f86d34cb4154bafe7c983b6767ffb31a74b133de61edf15c170564fcefb6e457012f63b95ed4aaf6fd2e1e1cfc2ad93a682cfab2fe86f427f7d93ae9b69cbaf02a7565074a95a8c1176402f250d2e815ab206a6b65009c65d94259772ab31a00c11e5c6b57fda0fbb1b22a69734c10214594a5d7b4c88a995eaeb3a65f9aa5d163d9e5c09f73105a4ef760a8421fb66d1982da739c42808fded9a95e456090747e494b0a1aee2a40f388d9f1146051754\"\nEOF\n\n# firewall\nufw limit ssh\nufw allow 80\nufw allow 443\nufw --force enable\n\n# Message of the day\ncat << EOF > /etc/motd\n#############################\n#############################\nSeaTable Enterprise Server\n\nTo finish the installation, change to the directory /opt/seatable and follow our deployment instructions at https://manual.seatable.io/docker/Enterprise-Edition/Deploy%20SeaTable-EE%20with%20Docker/.\nYou can skip the beginning and start directly with the adjustment of the docker-compose.yml file.\n\nPlease visit https://forum.seatable.io for SeaTable community support.\n#############################\n#############################\n\nEOF\n\necho \"Installation complete\"\nall_set\nstackscript_cleanup","user_defined_fields":[{"name":"url","label":"The domain/subdomain for SeaTable Server","example":"https://seatable.example.org"},{"name":"le","label":"Get a Let's Encrypt certificate","default":"True","oneof":"True,False"},{"name":"timezone","label":"Choose your timezone (e.g Europe/Berlin)","example":"Choices can be found here: http://en.wikipedia.org/wiki/List_of_tz_zones_by_name","default":"Etc/UTC"}]},{"id":604068,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Shadowsocks One-Click","description":"Shadowsocks One-Click","ordinal":103,"logo_url":"assets/shadowsocks.svg","images":["linode/ubuntu20.04"],"deployments_total":9287,"deployments_active":352,"is_public":true,"mine":false,"created":"2019-10-22T16:11:39","updated":"2023-12-12T14:27:20","rev_note":"final edit","script":"#!/usr/bin/env bash\n\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n## Import the Bash StackScript Library\nsource \n\n## Import the DNS/API Functions Library\nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# Install & configure shadowsocks\nfunction install_shadowsocks {\n apt-get install shadowsocks-libev -y\n cat </etc/shadowsocks-libev/config.json\n{\n\"server\":\"$IP\",\n\"server_port\":8000,\n\"local_port\":1080,\n\"password\":\"$SHADOWPASSWORD\",\n\"timeout\":60,\n\"method\":\"aes-256-gcm\"\n}\nEND\n systemctl start shadowsocks-libev\n systemctl enable shadowsocks-libev\n systemctl restart shadowsocks-libev\n}\n\nfunction shadowsocks_firewall {\n ufw allow 8000\n}\n\nfunction main {\n install_shadowsocks\n shadowsocks_firewall\n stackscript_cleanup\n}\n\n# Execute function\nmain","user_defined_fields":[{"name":"shadowpassword","label":"Shadowsocks Password","example":"Password"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address for SOA Recorf","default":""}]},{"id":1243780,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"SimpleX Chat One-Click","description":"SimpleX Chat","ordinal":104,"logo_url":"assets/simplexchat.svg","images":["linode/ubuntu22.04"],"deployments_total":61,"deployments_active":8,"is_public":true,"mine":false,"created":"2023-09-28T15:20:59","updated":"2023-12-11T10:24:43","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Simplex Settings\n# \n# \n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-simplex-chat\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n # Simplex variables\n \n if [[ -n ${TOKEN_PASSWORD} ]]; then\n if [[ -n ${DOMAIN} && -n ${SUBDOMAIN} ]]; then\n echo \"addr: ${SUBDOMAIN}.${DOMAIN}\" >> ${group_vars}\n elif [[ -n ${DOMAIN} ]]; then\n echo \"addr: ${DOMAIN}\" >> ${group_vars}\n else\n echo \"addr: $(hostname -I | awk '{print $1}')\" >> ${group_vars}\n fi\n else\n echo \"addr: $(hostname -I | awk '{print $1}')\" >> ${group_vars}\n fi\n\n if [[ -n ${SMP_PASSWORD} ]]; then\n echo \"smp_password: ${SMP_PASSWORD}\" >> ${group_vars};\n fi\n\n if [[ -n ${XFTP_QUOTA} ]]; then\n case ${XFTP_QUOTA} in\n *gb) echo \"xftp_quota: ${XFTP_QUOTA}\" >> ${group_vars} ;;\n *) echo \"xftp_quota: ${XFTP_QUOTA}gb\" >> ${group_vars} ;;\n esac\n fi\n\n # Linode variables\n\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n else echo \"No email entered\";\n fi\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"smp_password","label":"Set password for smp-server.","example":"123qwe","default":""},{"name":"xftp_quota","label":"Set xftp-server file storage quota in GB.","example":"1/5/10/100gb","default":"10gb"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"SOA Email","example":"user@domain.tld","default":""}]},{"id":869153,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Splunk One-Click","description":"Splunk One-Click","ordinal":105,"logo_url":"assets/splunk.svg","images":["linode/debian10","linode/ubuntu20.04"],"deployments_total":961,"deployments_active":94,"is_public":true,"mine":false,"created":"2021-07-20T19:04:43","updated":"2023-12-11T14:21:26","rev_note":"","script":"#!/usr/bin/env bash\n\n### UDF Variables\n\n## Splunk settings\n#\n#\n\n## Domain settings\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n\n## Linode/SSH Settings - Optional\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -xo pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and OCA Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n# Configure Splunk\nwget https://download.splunk.com/products/splunk/releases/8.2.0/linux/splunk-8.2.0-e053ef3c985f-Linux-x86_64.tgz\nwget \ntar zxvf splunk-8.2.0-e053ef3c985f-Linux-x86_64.tgz -C /opt/\nuseradd splunk --system --shell=/usr/sbin/nologin\nchown -R splunk:splunk /opt/splunk\n\napt install -y expect\n SPLUNK_INSTALL=$(expect -c \"\n set timeout 10\n spawn /opt/splunk/bin/splunk enable boot-start -user splunk -systemd-managed 1 --accept-license\n expect \\\"Please enter an administrator username:\\\"\n send \\\"$SPLUNK_USER\\r\\\"\n expect \\\"Please enter a new password:\\\"\n send \\\"$SPLUNK_PASSWORD\\r\\\"\n expect \\\"Please confirm new password:\\\"\n send \\\"$SPLUNK_PASSWORD\\r\\\"\n expect eof\n \")\n\n# Start daemon\nsystemctl start Splunkd\nsystemctl status Splunkd\n\n# Firewall\nufw allow 22 \nufw allow 8000\nufw allow 8089\nufw allow 9997\n\n# Clean up\nstackscript_cleanup","user_defined_fields":[{"name":"splunk_user","label":"Splunk Admin User"},{"name":"splunk_password","label":"Splunk Admin password"},{"name":"token_password","label":"Your Linode API token. This is required in order to create DNS records.","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token)","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"soa_email_address","label":"Admin Email for the server","default":""},{"name":"username","label":"The username for the Linode's admin/SSH user (Please ensure that the username entered does not contain any uppercase characters)","example":"user1","default":""},{"name":"password","label":"The password for the Linode's admin/SSH user","example":"S3cuReP@s$w0rd","default":""},{"name":"pubkey","label":"The SSH Public Key used to securely access the Linode via SSH","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":1102904,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Superinsight One-Click","description":"Superinsight One-Click app","ordinal":106,"logo_url":"assets/superinsight.svg","images":["linode/ubuntu22.04"],"deployments_total":29,"deployments_active":1,"is_public":true,"mine":false,"created":"2022-12-20T17:43:01","updated":"2023-12-03T07:53:56","rev_note":"","script":"#!/usr/bin/bash\n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\n# Add Logging to /var/log/stackscript.log for future troubleshooting\nexec 1> >(tee -a \"/var/log/stackscript.log\") 2>&1\n# System Updates updates\napt-get -o Acquire::ForceIPv4=true update -y\n## END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Install docker\ncurl -fsSL get.docker.com | sudo sh\n\n# Creating Password\necho \"Superinsight setting up password....\"\nADMIN_PASSWORD=$(openssl rand -hex 12)\nNODE_IP=$(hostname -I | cut -f1 -d' ')\necho \"Downloading and Installing Superinsight instance......\"\n\n# Install Superinsight\ndocker run \\\n--detach \\\n--name superinsight-db-standalone \\\n--restart always \\\n-p 5432:5432 \\\n-v vol-superinsight:/db \\\n-e SUPERINSIGHT_USER=admin \\\n-e SUPERINSIGHT_PASSWORD=\"${ADMIN_PASSWORD}\" \\\nsuperinsight/superinsight-db-standalone:latest\n\n\n# Print instructions\ncat << EOF > /etc/motd\n\n################################################################################################################################################\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tSUPERINSIGHT\n################################################################################################################################################\n\nSuperinsight created the user admin with password: ${ADMIN_PASSWORD}\nYou can can connect using a database client with the following connection string postgres://admin:${ADMIN_PASSWORD}@${NODE_IP}:5432/superinsight\nFor complete source code and information, visit: https://github.com/superinsight/superinsight-db\n\n################################################################################################################################################\nEOF","user_defined_fields":[]},{"id":401705,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Terraria One-Click","description":"Terraria One-Click","ordinal":107,"logo_url":"assets/Terraria.svg","images":["linode/ubuntu20.04"],"deployments_total":705,"deployments_active":5,"is_public":true,"mine":false,"created":"2019-03-08T21:10:49","updated":"2023-12-06T13:35:55","rev_note":"Remove SSH Pubkey UDF","script":"#!/bin/bash\n#\n#\n#\n\n#Game config options\n\n#\n#\n#\n#\n#\n#\n#\n\n\n#Non-MVP config options\n#name=\"autocreate\" label=\"autocreate\" default=\"1\"/>\n#name=\"worldpath\" label=\"worldpath\" default=\"~/.local/share/Terraria/Worlds/\"/>\n#name=\"banlist\" label=\"banlist\" default=\"banlist.txt\"/>\n#name=\"priority\" label=\"priority\" default=\"1\"/>\n#name=\"upnp\" label=\"upnp\" default=\"1\"/>\n#name=\"npcstream\" label=\"npcstream\" default=\"60\"/>\n#name=\"secure\" label=\"secure\" default=\"1\"/>\n#name=\"language\" label=\"language\" default=\"en-US\"/>\n\n\nsource \nsource \nsource \nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -xo pipefail\n\nGAMESERVER=\"terrariaserver\"\n\n### UDF to config\n\nif [[ \"$DIFFICULTY\" = \"Normal\" ]]; then\n DIFFICULTY=\"0\"\nelif [[ \"$DIFFICULTY\" = \"Expert\" ]]; then\n DIFFICULTY=\"1\"\nfi\n\nset_hostname\napt_setup_update\n\n\n# Terraria specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\nsudo apt -q -y install mailutils postfix \\\ncurl wget file bzip2 gzip unzip bsdmainutils \\\npython util-linux ca-certificates binutils bc \\\njq tmux lib32gcc1 libstdc++6 libstdc++6:i386\n\n# Install linuxGSM\nlinuxgsm_install\n\necho Requires Steam username and password to install\nsu - $GAMESERVER -c \"mkdir -p /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER\"\nsu - $GAMESERVER -c \"touch /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER/common.cfg\"\nsu - $GAMESERVER -c \"echo steamuser=\\\"$STEAMUSER\\\" >> /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER/common.cfg\"\nsu - $GAMESERVER -c \"echo steampass=\\''$STEAMPASSWORD'\\' >> /home/$GAMESERVER/lgsm/config-lgsm/$GAMESERVER/common.cfg\"\n\n# Install Terraria\ngame_install\n\nsed -i s/#seed=AwesomeSeed/seed=\"$SEED\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/worldname=world1/worldname=\"$WORLDNAME\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/difficulty=0/difficulty=\"$DIFFICULTY\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/maxplayers=20/maxplayers=\"$MAXPLAYERS\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/port=7777/port=\"$PORT\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/password=/password=\"$PASSWORD\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\nsed -i s/motd=.*/motd=\"$MOTD\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n\n#Non-MVP config options\n# sed -i s/autocreate=1/autocreate=\"$AUTOCREATE\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/worldpath=\\~\\/\\.local\\/share\\/Terraria\\/Worlds\\//worldpath=\"$WORLDPATH\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/banlist=banlist.txt/banlist=\"$BANLIST\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/\\#priority=1/priority=\"$PRIORITY\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/#npcstream=60/npcstream=\"$NPCSTREAM\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/#upnp=1/upnp=\"$UPNP\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/secure=1/secure=\"$SECURE\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n#sed -i s/language=en\\-US/language=\"$LANGUAGE\"/ home/\"$GAMESERVER\"/serverfiles/\"$GAMESERVER\".txt\n\n# Setup crons and create systemd service file\nservice_config\n\n# Start the service and setup firewall\nufw_install\nufw allow \"$PORT\"/tcp\nufw allow \"$PORT\"/udp\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup","user_defined_fields":[{"name":"steamuser","label":"Steam Username","example":"username"},{"name":"steampassword","label":"Steam Password, must have Steam Guard turned off for deployment","example":"YourSteamPassword"},{"name":"worldname","label":"World Name","default":"world1"},{"name":"password","label":"Server Password","default":""},{"name":"motd","label":"Message of the Day","default":"Powered by Linode!"},{"name":"difficulty","label":"Difficulty Level","oneof":"Normal,Expert","default":"Normal"},{"name":"maxplayers","label":"Maximum Players","oneof":"1,10,20,50,100,200,255,","default":"20"},{"name":"port","label":"Port","default":"7777"},{"name":"seed","label":"Seed","default":"AwesomeSeed"}]},{"id":401704,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"TF2 One-Click","description":"TF2 One-Click","ordinal":108,"logo_url":"assets/TF2.svg","images":["linode/debian11"],"deployments_total":354,"deployments_active":2,"is_public":true,"mine":false,"created":"2019-03-08T21:10:23","updated":"2023-12-12T02:02:35","rev_note":"Remove SSH Pubkey UDF","script":"#!/bin/bash\n#\n#\n#\n#\n#\n#\n#\n#\n#\n\nsource \nsource \nsource \nsource \n\nGAMESERVER=\"tf2server\"\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n### UDF to config\n\n#Autoteambalance\nif [[ \"$AUTOTEAMBALANCE\" = \"Enabled\" ]]; then\n AUTOTEAMBALANCE=1\nelif [[ \"$AUTOTEAMBALANCE\" = \"Disabled\" ]]; then\n AUTOTEAMBALANCE=0\nfi\n\nif [[ \"$SERVERNAME\" = \"\" ]]; then\n SERVERNAME=\"Linode TF2 Server\"\nfi\n\n\n# Server config\nset_hostname\napt_setup_update\n\n\n# Teamfortress2 specific dependencies\ndebconf-set-selections <<< \"postfix postfix/main_mailer_type string 'No Configuration'\"\ndebconf-set-selections <<< \"postfix postfix/mailname string `hostname`\"\ndpkg --add-architecture i386\napt update\napt -q -y install mailutils postfix curl wget file \\\nbzip2 gzip unzip bsdmainutils python util-linux \\\nca-certificates binutils bc jq tmux lib32gcc-s1 libstdc++6 \\\nlibstdc++6:i386 libcurl4-gnutls-dev:i386 libtcmalloc-minimal4:i386\n\n# Install linuxGSM\nlinuxgsm_install\n\n# Install Teamfortress2\ngame_install\n\n# Setup crons and create systemd service file\nservice_config\n\ncp /home/tf2server/lgsm/config-lgsm/tf2server/_default.cfg /home/tf2server/lgsm/config-lgsm/tf2server/common.cfg\n\n# Custom game configs\n> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\ncat <> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\nlog on\nsv_logbans 1\nsv_logecho 1\nsv_logfile 1\nsv_log_onefile\nEND\n\necho \"hostname $SERVERNAME\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"mp_autoteambalance $AUTOTEAMBALANCE\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"mp_maxrounds $MAXROUNDS\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"mp_timelimit $TIMELIMIT\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"rcon_password \\\"$RCONPASSWORD\\\"\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"sv_password \\\"$SVPASSWORD\\\"\" >> /home/tf2server/serverfiles/tf/cfg/tf2server.cfg\necho \"\\\"$MOTD\\\"\" > /home/tf2server/serverfiles/tf/cfg/motd_default.txt\n\n\n# Start the service and setup firewall\nufw_install\nufw allow 27014:27050/tcp\nufw allow 3478:4380/udp\nufw allow 27000:27030/udp\nufw allow 26901\nufw enable\nfail2ban_install\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\nstackscript_cleanup","user_defined_fields":[{"name":"motd","label":"Message of the Day","default":"Powered by Linode!"},{"name":"servername","label":"Server Name","default":"Linode TF2 Server"},{"name":"svpassword","label":"Server Password","default":""},{"name":"gslt","label":"Game Server Login Token","example":"Steam gameserver token. Needed to list as public server","default":""},{"name":"autoteambalance","label":"Team Balance Enabled","oneof":"Enabled,Disabled","default":"Enabled"},{"name":"maxrounds","label":"Maximum Rounds","oneof":"1,3,5,10,15,20","default":"5"},{"name":"timelimit","label":"Round Time Limit","oneof":"10,15,35,45,60","default":"35"},{"name":"rconpassword","label":"RCON password"}]},{"id":1051711,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"UniFi Network Application One-Click","description":"UniFi Network Application One-Click","ordinal":109,"logo_url":"assets/unifi.svg","images":["linode/debian10"],"deployments_total":493,"deployments_active":23,"is_public":true,"mine":false,"created":"2022-09-01T15:41:39","updated":"2023-10-18T12:38:34","rev_note":"","script":"#!/bin/bash\n#\n# Script to install UniFi Controller on Linode\n# \n## Linode/SSH Security Settings\n#\n#\n#\n#\n## Domain Settings\n#\n#\n#\n## Enable logging\n\nset -x\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Register default rDNS \nexport DEFAULT_RDNS=$(dnsdomainname -A | awk '{print $1}')\n\n#set absolute domain if any, otherwise use DEFAULT_RDNS\nif [[ $DOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DEFAULT_RDNS\"\nelif [[ $SUBDOMAIN = \"\" ]]; then\n readonly ABS_DOMAIN=\"$DOMAIN\"\nelse\n readonly ABS_DOMAIN=\"$SUBDOMAIN.$DOMAIN\"\nfi\n\ncreate_a_record $SUBDOMAIN $IP $DOMAIN\n\n## install depends \nexport DEBIAN_FRONTEND=noninteractive\napt-get install apt-transport-https ca-certificates wget dirmngr gpg software-properties-common multiarch-support libcommons-daemon-java jsvc openjdk-11-jre-headless -y \n\n# install mongodb req libssl1\nwget http://security.debian.org/debian-security/pool/updates/main/o/openssl/libssl1.0.0_1.0.1t-1+deb8u12_amd64.deb\ndpkg -i libssl1.0.0_1.0.1t-1+deb8u12_amd64.deb\n\n# install mongodb-3.4\nwget -qO - https://www.mongodb.org/static/pgp/server-3.4.asc | apt-key add -\necho \"deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.4 main\" | tee /etc/apt/sources.list.d/mongodb-org-3.4.list\napt update && apt upgrade -y\napt install mongodb-org -y \n \n# install latest UniFi Controller \necho 'deb https://www.ui.com/downloads/unifi/debian stable ubiquiti' | sudo tee /etc/apt/sources.list.d/100-ubnt-unifi.list\nsudo wget -O /etc/apt/trusted.gpg.d/unifi-repo.gpg https://dl.ui.com/unifi/unifi-repo.gpg \napt update && apt install unifi -yq \n\n## install nginx reverse-proxy \napt install nginx -y \n\n#configure nginx reverse proxy\nrm /etc/nginx/sites-enabled/default\ntouch /etc/nginx/sites-available/reverse-proxy.conf\ncat < /etc/nginx/sites-available/reverse-proxy.conf\nserver {\n listen 80;\n listen [::]:80;\n server_name ${ABS_DOMAIN};\n\n access_log /var/log/nginx/reverse-access.log;\n error_log /var/log/nginx/reverse-error.log;\n location /wss/ {\n proxy_pass https://localhost:8443;\n proxy_http_version 1.1;\n proxy_buffering off;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection \"Upgrade\";\n proxy_read_timeout 86400;\n }\n location / {\n proxy_pass https://localhost:8443;\n proxy_set_header Host \\$host;\n proxy_set_header X-Real-IP \\$remote_addr;\n proxy_set_header X-Forward-For \\$proxy_add_x_forwarded_for;\n }\n}\nEND\nln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/reverse-proxy.conf\n\n#enable and start nginx\nsystemctl enable nginx\nsystemctl restart nginx \n\n## UFW rules \nufw allow http\nufw allow https\nufw allow 53\nufw allow 3479/udp\nufw allow 5514/udp\nufw allow 8080/tcp\nufw allow 8443/tcp\nufw allow 8880/tcp\nufw allow 8843/tcp\nufw allow 27117/tcp\nufw allow 5656:5699/udp\nufw allow 10001/udp \nufw allow 1900/udp\nufw allow 123/udp\nufw enable \n\nsleep 60 \n\n## install SSL certs. required \napt install python3-certbot-nginx -y \ncertbot run --non-interactive --nginx --agree-tos --redirect -d ${ABS_DOMAIN} -m ${SOA_EMAIL_ADDRESS} -w /var/www/html/\n \n## add some details \ncat << EOF > /etc/motd\n###################\n\n The installation is now complete, and you can access the UniFi Network Controller GUI from https://${ABS_DOMAIN}\n We recommend using the GUI to complete your configurations of the service\n\n################### \nEOF\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode.","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":970523,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Uptime Kuma One-Click","description":"Uptime Kuma One-Click","ordinal":110,"logo_url":"assets/uptimekuma.svg","images":["linode/ubuntu22.04"],"deployments_total":2284,"deployments_active":398,"is_public":true,"mine":false,"created":"2022-02-07T16:06:08","updated":"2023-12-12T11:49:54","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n## KUMA Settings \n#\n\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-uptimekuma\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n # Uptimekuma vars\n \n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n \n\n # populate group_vars\n udf\n # run playbooks\n for playbook in site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"}]},{"id":925530,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"UTunnel VPN One-Click","description":"UTunnel VPN One-Click","ordinal":111,"logo_url":"assets/utunnel.svg","images":["linode/ubuntu20.04"],"deployments_total":1194,"deployments_active":17,"is_public":true,"mine":false,"created":"2021-10-25T18:55:37","updated":"2023-12-11T18:05:44","rev_note":"","script":"#!/bin/bash\n# Update the packages on the system from the distribution repositories.\t\napt-get update\nDEBIAN_FRONTEND=noninteractive apt-get upgrade -y\n\n# Install pre-requisites for docker-ce\n\nDEBIAN_FRONTEND=noninteractive apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common\n\n#Add Docker official GPG key\n\ncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -\n\n#Add repository\n\nadd-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable\"\n\n# Download and install utnservice\n\nmkdir /utunnel\n\ncd /utunnel \n\nwget https://files.utunnel.io/production/deploy/install_bundle_20.tar\n\ntar -xf install_bundle_20.tar\n\nrm -f install_bundle_20.tar","user_defined_fields":[]},{"id":781317,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Valheim One-Click","description":"Valheim One-Click","ordinal":112,"logo_url":"assets/valheim.svg","images":["linode/debian10"],"deployments_total":2427,"deployments_active":52,"is_public":true,"mine":false,"created":"2021-03-01T13:26:36","updated":"2023-12-10T21:30:59","rev_note":"","script":"#!/usr/bin/env bash\n\n### UDF Variables\n\n## Valheim Server Settings - Required\n#\n#\n\n## Linode/SSH Security Settings - Required\n#\n#\n\n## Linode/SSH Settings - Optional\n#\n#\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nset -o pipefail\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Linode Bash StackScript, API, and LinuxGSM Helper libraries\nsource \nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\n[ ! $USERNAME ] && USERNAME='lgsmuser'\nsource \n\n\n# Download and install dependencies\ndpkg --add-architecture i386\nsystem_update\nsystem_install_package curl wget file tar expect bzip2 gzip unzip \\\n bsdmainutils python util-linux ca-certificates \\\n binutils bc jq tmux netcat lib32gcc1 lib32stdc++6 \\\n libc6-dev libsdl2-2.0-0:i386\n\n\n# Open the needed firewall ports\nufw allow 2456:2458/udp\nufw allow 4380/udp\nufw allow 27000:27030/udp\n\n# Install linuxGSM\nGAMESERVER='vhserver'\nv_linuxgsm_oneclick_install \"$GAMESERVER\" \"$USERNAME\"\n\n# Set the Valheim dedicated server's name and password\ncat /home/$USERNAME/lgsm/config-lgsm/vhserver/_default.cfg >> /home/$USERNAME/lgsm/config-lgsm/vhserver/vhserver.cfg\nsed -i \"s/servername=\\\"Valheim Server\\\"/servername=\\\"$SERVER_NAME\\\"/\" /home/$USERNAME/lgsm/config-lgsm/vhserver/vhserver.cfg\nsed -i \"s/serverpassword=\\\"\\\"/serverpassword=\\\"$SERVER_PASSWORD\\\"/\" /home/$USERNAME/lgsm/config-lgsm/vhserver/vhserver.cfg\n\n# Start and enable the Valheim services\nsystemctl start \"$GAMESERVER\".service\nsystemctl enable \"$GAMESERVER\".service\n\n# Clean up\nstackscript_cleanup","user_defined_fields":[{"name":"server_name","label":"The name of the Valheim dedicated server"},{"name":"server_password","label":"The password for the Valheim dedicated server","example":"S3cuReP@s$w0rd"},{"name":"username","label":"The username for the Linode's admin/SSH user (Please ensure that the username entered does not contain any uppercase characters)","example":"lgsmuser"},{"name":"password","label":"The password for the Linode's admin/SSH user","example":"S3cuReP@s$w0rd"},{"name":"pubkey","label":"The SSH Public Key used to securely access the Linode via SSH","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":954759,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"VictoriaMetrics Single One-Click","description":"VictoriaMetrics Single","ordinal":113,"logo_url":"assets/victoriametricssingle.svg","images":["linode/ubuntu20.04"],"deployments_total":40,"deployments_active":4,"is_public":true,"mine":false,"created":"2022-01-06T18:53:56","updated":"2023-12-07T22:56:22","rev_note":"","script":"#!/bin/bash\n# \nsource \nsystem_set_hostname \"$HOSTNAME\"\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nexport DEBIAN_FRONTEND=noninteractive\napt update && apt upgrade -y && apt install -y curl wget net-tools traceroute jq\n# Generate files\nmkdir -p /etc/victoriametrics/single\nmkdir -p /var/lib/victoria-metrics-data\nmkdir -p /var/lib/cloud/scripts/per-instance\n# Create victoriametrics user\ngroupadd -r victoriametrics\nuseradd -g victoriametrics -d /var/lib/victoria-metrics-data -s /sbin/nologin --system victoriametrics\nchown -R victoriametrics:victoriametrics /var/lib/victoria-metrics-data\n# Install VictoriaMetrics Single\nVM_VERSION=`curl -sg \"https://api.github.com/repos/VictoriaMetrics/VictoriaMetrics/tags\" | jq -r '.[0].name'`\nwget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/${VM_VERSION}/victoria-metrics-linux-amd64-${VM_VERSION}.tar.gz -O /tmp/victoria-metrics.tar.gz\ntar xvf /tmp/victoria-metrics.tar.gz -C /usr/bin\nchmod +x /usr/bin/victoria-metrics-prod\nchown root:root /usr/bin/victoria-metrics-prod\ntouch /etc/victoriametrics/single/scrape.yml\nchown root:root /etc/victoriametrics/single/scrape.yml\ncat </etc/systemd/system/vmsingle.service\n[Unit]\nDescription=VictoriaMetrics is a fast, cost-effective and scalable monitoring solution and time series database.\n# https://docs.victoriametrics.com\nAfter=network.target\n[Service]\nType=simple\nUser=victoriametrics\nGroup=victoriametrics\nWorkingDirectory=/var/lib/victoria-metrics-data\nStartLimitBurst=5\nStartLimitInterval=0\nRestart=on-failure\nRestartSec=5\nEnvironmentFile=-/etc/victoriametrics/single/victoriametrics.conf\nExecStart=/usr/bin/victoria-metrics-prod \\$ARGS\nExecStop=/bin/kill -s SIGTERM \\$MAINPID\nExecReload=/bin/kill -HUP \\$MAINPID\n# See docs https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#tuning\nProtectSystem=full\nLimitNOFILE=1048576\nLimitNPROC=1048576\nLimitCORE=infinity\nStandardOutput=syslog\nStandardError=syslog\nSyslogIdentifier=vmsingle\n[Install]\nWantedBy=multi-user.target\nEND\ncat </etc/victoriametrics/single/victoriametrics.conf\n# See https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#list-of-command-line-flags to get more information about supported command-line flags\n# \n# If you use IPv6 pleas add \"-enableTCP6\" to args line\nARGS=\"-promscrape.config=/etc/victoriametrics/single/scrape.yml -storageDataPath=/var/lib/victoria-metrics-data -retentionPeriod=12 -httpListenAddr=:8428 -graphiteListenAddr=:2003 -opentsdbListenAddr=:4242 -influxListenAddr=:8089 -enableTCP6\"\nEND\ncat < /etc/profile.d/victoriametrics_welcome.sh\n#!/bin/sh\n#\nmyip=$(hostname -I | awk '{print$1}')\n******************************************************************************** \nWelcome to VictoriaMetrics Single.\nTo keep this server secure, the UFW firewall is enabled.\nAll ports are BLOCKED except 22 (SSH), 80 (HTTP), and 443 (HTTPS), 8428 (VictoriaMetrics HTTP), 8089 (VictoriaMetrics Influx),\n4242 (VictoriaMetrics OpenTSDB), 2003 (VictoriaMetrics Graphite)\nIn a web browser, you can view:\n * The VictoriaMetrics Quickstart guide: https://kutt.it/1click-quickstart\nOn the server:\n * The default VictoriaMetrics root is located at /var/lib/victoria-metrics-data\n * VictoriaMetrics is running on ports: 8428, 8089, 4242, 2003 and they are bound to the local interface.\n********************************************************************************\n # This image includes version v1.74.0 of VictoriaMetrics. \n # See Release notes https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.70.0\n # Welcome to VictoriaMetrics droplet!\n # Website: https://victoriametrics.com\n # Documentation: https://docs.victoriametrics.com\n # VictoriaMetrics Github : https://github.com/VictoriaMetrics/VictoriaMetrics\n # VictoriaMetrics Slack Community: https://slack.victoriametrics.com\n # VictoriaMetrics Telegram Community: https://t.me/VictoriaMetrics_en\n # VictoriaMetrics config: /etc/victoriametrics/single/victoriametrics.conf\n # VictoriaMetrics scrape config: /etc/victoriametrics/single/scrape.yml\n # VictoriaMetrics UI accessable on: http://your_droplet_public_ipv4:8428/vmui/\nEND\n# Enable UFW and add some rules to it\nsed -e 's|DEFAULT_FORWARD_POLICY=.*|DEFAULT_FORWARD_POLICY=\"ACCEPT\"|g' \\\n -i /etc/default/ufw\nufw allow ssh comment \"SSH port\"\nufw allow http comment \"HTTP port\"\nufw allow https comment \"HTTPS port\"\nufw allow 8428 comment \"VictoriaMetrics Single HTTP port\"\nufw allow 8089/tcp comment \"TCP Influx Listen port for VictoriaMetrics\"\nufw allow 8089/udp comment \"UDP Influx Listen port for VictoriaMetrics\"\nufw allow 2003/tcp comment \"TCP Graphite Listen port for VictoriaMetrics\"\nufw allow 2003/udp comment \"UDP Graphite Listen port for VictoriaMetrics\"\nufw allow 4242 comment \"OpenTSDB Listen port for VictoriaMetrics\"\nufw --force enable\n# Cleaning up\nrm -rf /tmp/* /var/tmp/*\nhistory -c\ncat /dev/null > /root/.bash_history\nunset HISTFILE\nfind /var/log -mtime -1 -type f ! -name 'stackscript.log' -exec truncate -s 0 {} \\;\n# Start VictoriaMetrics\nsystemctl enable vmsingle.service\nsystemctl start vmsingle.service\necho \"Installation complete!\"","user_defined_fields":[{"name":"hostname","label":"Hostname"}]},{"id":662117,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Virtualmin One-Click","description":"Virtualmin One-Click","ordinal":114,"logo_url":"assets/virtualmin.svg","images":["linode/debian10","linode/ubuntu22.04"],"deployments_total":2204,"deployments_active":140,"is_public":true,"mine":false,"created":"2020-08-12T15:46:13","updated":"2023-12-12T15:29:25","rev_note":"","script":"#!/usr/bin/env bash\n\n### UDF Variables for the StackScript\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n#\n#\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nIFS=$'\\n\\t'\n\n## Import the Bash StackScript and API/DNS Libraries\nsource \nsource \n\n# Import the OCA Helper Functions\nsource \n\nfunction install_virtualmin {\n if [ $(cat /etc/os-release | grep -i 'ubuntu' )]; then\n if [ ! $(cat /etc/os-release | grep -i 'lts') ]; then\n printf \"Virtualmin only works with LTS versions of Ubuntu\\n\"\n exit 1;\n fi\n else\n wget http://software.virtualmin.com/gpl/scripts/virtualmin-install.sh -O /root/virtualmin-install.sh && {\n chmod +x /root/virtualmin-install.sh\n /bin/sh /root/virtualmin-install.sh -f -v\n }\n fi\n}\n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n## Configure firewall and install Fail2Ban\nufw_install\nufw allow http\nufw allow https\nufw allow 10000\nfail2ban_install\n\n# Install Webmin and Virtualmin\nsource \ninstall_virtualmin\n\n# Disable SSL so that everything works\nsed -i 's/^ssl=1/ssl=0/g' /etc/webmin/miniserv.conf\n\n# Restart Webmin\nsystemctl restart webmin\n\n# Clean up\nstackscript_cleanup","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"pwless_sudo","label":"Enable passwordless sudo access for the limited user?","oneof":"Yes,No","default":"No"},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"auto_updates","label":"Configure automatic security updates?","oneof":"Yes,No","default":"No"},{"name":"fail2ban","label":"Use fail2ban to prevent automated intrusion attempts?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your DNS records","default":""},{"name":"subdomain","label":"The subdomain for your server","default":""},{"name":"domain","label":"Your domain","default":""},{"name":"soa_email_address","label":"Admin Email for the server","default":""},{"name":"mx","label":"Do you need an MX record for this domain? (Yes if sending mail from this Linode)","oneof":"Yes,No","default":"No"},{"name":"spf","label":"Do you need an SPF record for this domain? (Yes if sending mail from this Linode)","oneof":"Yes,No","default":"No"}]},{"id":688903,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"VS Code Server One-Click","description":"Visual Studio Code One-Click","ordinal":115,"logo_url":"assets/vscodeserver.svg","images":["linode/debian10"],"deployments_total":5267,"deployments_active":123,"is_public":true,"mine":false,"created":"2020-11-17T21:10:25","updated":"2023-12-12T15:29:28","rev_note":"","script":"#!/usr/bin/env bash\n\n## VS Code Server OCA Script\n\n### UDF Variables\n\n## VS Code Web Password\n#\n#\n\n## User and SSH Security\n#\n#\n#\n#\n\n## Domain\n#\n#\n#\n#\n\n## Let's Encrypt SSL\n#\n\n\n### Logging and other debugging helpers\n\n# Enable logging for the StackScript\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Source the Bash StackScript Library and the API functions for DNS\nsource \nsource \n\n# Source and run the New Linode Setup script for DNS/SSH configuration\nsource \n\n\nfunction get_code_server {\n local -r username=\"$1\" vs_code_ver=\"$2\"\n\n cd \"/home/$username\"\n\n wget \"https://github.com/cdr/code-server/releases/download/v${vs_code_ver}/code-server-${vs_code_ver}-linux-amd64.tar.gz\"\n tar -xf \"code-server-${vs_code_ver}-linux-amd64.tar.gz\"\n mv code-server-*/ bin/\n\n chown -R \"${username}:${username}\" bin/\n chmod +x bin/code-server\n mkdir data/\n chown -R \"${username}:${username}\" data/\n\n cd /root/\n}\n\nfunction enable_code_service {\n local -r vs_code_password=\"$1\" username=\"$2\"\n\n # Set the password in /etc/systemd/system/code-server.service\n cat << EOF > /etc/systemd/system/code-server.service\n[Unit]\nDescription=code-server\nAfter=nginx.service\n[Service]\nUser=$username\nWorkingDirectory=/home/$username\nEnvironment=PASSWORD=$vs_code_password\nExecStart=/home/${username}/bin/code-server --host 127.0.0.1 --user-data-dir /home/${username}/data --auth password\nRestart=always\n[Install]\nWantedBy=multi-user.target\nEOF\n\n # Enable code-server as a service\n systemctl daemon-reload\n systemctl start code-server\n systemctl enable code-server\n}\n\nfunction certbot_standalone {\n local -r email_address=\"$1\" ssl_domain=\"$2\"\n\n # Get an SSL certificate from CertBot\n system_install_package \"certbot\"\n certbot -n certonly --standalone --agree-tos -m \"$email_address\" -d \"$ssl_domain\"\n}\n\nfunction nginx_reverse_proxy {\n local -r ssl_domain=\"$1\"\n\n ## Setup a reverse proxy with Nginx\n system_install_package \"nginx\"\n\n cat << EOF > /etc/nginx/sites-available/code-server\nserver {\n listen 80;\n server_name $ssl_domain;\n # enforce https\n return 301 https://\\$server_name:443\\$request_uri;\n}\nserver {\n listen 443 ssl http2;\n server_name $ssl_domain;\n ssl_certificate /etc/letsencrypt/live/${ssl_domain}/fullchain.pem;\n ssl_certificate_key /etc/letsencrypt/live/${ssl_domain}/privkey.pem;\n location / {\n proxy_pass http://127.0.0.1:8080/;\n proxy_set_header Host \\$host;\n proxy_set_header Upgrade \\$http_upgrade;\n proxy_set_header Connection upgrade;\n proxy_set_header Accept-Encoding gzip;\n }\n}\nEOF\n\n ln -s /etc/nginx/sites-available/code-server /etc/nginx/sites-enabled\n nginx -t\n systemctl restart nginx\n}\n\n### Install UFW and open the needed firewall ports\nufw allow 80,443/tcp\n\n### Install and configure VS Code Server\nget_code_server \"$USERNAME\" \"$VS_CODE_VER\"\nenable_code_service \"$VS_CODE_PASSWORD\" \"$USERNAME\"\ncheck_dns_propagation \"$FQDN\" \"$IP\"\ncertbot_standalone \"$SOA_EMAIL_ADDRESS\" \"$FQDN\"\nnginx_reverse_proxy \"$FQDN\"\n\n### Clean up\nstackscript_cleanup","user_defined_fields":[{"name":"vs_code_password","label":"The password to login to the VS Code Web UI"},{"name":"vs_code_ver","label":"The version of VS Code Server you'd like installed","default":"3.10.2"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"disable_root","label":"Would you like to disable root login over SSH? (Recommended)","oneof":"Yes,No","default":"Yes"},{"name":"token_password","label":"Your Linode API token - This is required for creating DNS records","default":""},{"name":"domain","label":"The domain for the Linode's DNS record (Requires API token)","default":""},{"name":"subdomain","label":"The subdomain for the Linode's DNS record (Requires API token and domain)","default":""},{"name":"soa_email_address","label":"Your email address for your VirtualHost configuration, DNS records (If Required), and SSL certificates (If Required)."},{"name":"ssl","label":"Would you like to use a free Let's Encrypt SSL certificate? (Uses the Linode's default rDNS if no domain is specified above","oneof":"Yes,No","default":"No"}]},{"id":923037,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"WarpSpeed One-Click","description":"WarpSpeed One-Click","ordinal":116,"logo_url":"assets/warpspeed.svg","images":["linode/ubuntu20.04"],"deployments_total":880,"deployments_active":17,"is_public":true,"mine":false,"created":"2021-10-18T01:12:49","updated":"2023-12-06T00:07:58","rev_note":"","script":"#!/bin/bash\nset -o errexit\nset -o nounset\nset -o pipefail\nset -o xtrace\n\n# \n# \n# \n# \n\n## REQUIRED IN EVERY MARKETPLACE SUBMISSION\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nexport DEBIAN_FRONTEND=\"noninteractive\"\napt-get \\\n -o 'Acquire::ForceIPv4=true' \\\n --yes \\\n update\n\napt-get \\\n -o 'DPkg::options::=--force-confdef' \\\n -o 'DPkg::options::=--force-confold' \\\n --yes \\\n install grub-pc\n\napt-get \\\n -o Acquire::ForceIPv4=true \\\n --yes \\\n update\n# # END OF REQUIRED CODE FOR MARKETPLACE SUBMISSION\n\n# Handle the arguments.\nWIRESPEED_ADMIN_EMAIL=\"$(echo -e \"${WIRESPEED_ADMIN_EMAIL}\" | tr --delete '[:space:]')\"\nWIRESPEED_HTTP_HOST=\"$(echo -e \"${WIRESPEED_HTTP_HOST}\" | tr --delete '[:space:]')\"\nWIRESPEED_HTTP_HOST=\"${WIRESPEED_HTTP_HOST//\\//}\"\nWIRESPEED_HTTP_HOST=\"${WIRESPEED_HTTP_HOST//https:/}\"\nWIRESPEED_HTTP_HOST=\"${WIRESPEED_HTTP_HOST//http:/}\"\n\nif [[ -z \"${WIRESPEED_ADMIN_EMAIL}\" ]]; then\n echo \"Missing required parameter: admin email\"\n exit 101\nfi\n\nif [[ -z \"${WIRESPEED_HTTP_HOST}\" ]]; then\n echo \"Missing required parameter: http host\"\n exit 102\nfi\n\nif [[ -z \"${WIRESPEED_DATA_DIR}\" ]]; then\n WIRESPEED_DATA_DIR=\"/wirespeed\"\nfi\n\n# Set hostname\nIP=\"$(hostname --all-ip-addresses | awk '{ print $1 }')\"\nhostnamectl set-hostname \"${WIRESPEED_HTTP_HOST}\"\necho \"${IP} ${WIRESPEED_HTTP_HOST}\" >>/etc/hosts\n\nwget https://bunker.services/wirespeed-installer.sh\nchmod +x wirespeed-installer.sh\n./wirespeed-installer.sh \\\n \"${WIRESPEED_HTTP_HOST}\" \\\n \"${WIRESPEED_DATA_DIR}\" \\\n \"${WIRESPEED_ADMIN_EMAIL}\" \\\n \"${WIRESPEED_ADMIN_PASSWORD}\" \\\n --non-interactive\n\n# Force IPv4 and noninteractive upgrade after script runs to prevent breaking nf_conntrack for UFW\necho 'Acquire::ForceIPv4 \"true\";' >/etc/apt/apt.conf.d/99force-ipv4\napt-get upgrade --yes\n\nfor file in /root/StackScript /root/ssinclude* /root/wirespeed-installer.sh; do\n rm \"${file}\"\ndone\n\necho 'WireSpeed Installation complete!'","user_defined_fields":[{"name":"wirespeed_admin_email","label":"Admin Email","default":"","example":"it@example.com"},{"name":"wirespeed_admin_password","label":"Admin Password","default":"","example":"Password"},{"name":"wirespeed_http_host","label":"DNS Name","default":"","example":"vpn.example.com"},{"name":"wirespeed_data_dir","label":"Data Directory","default":"/wirespeed","example":"/wirespeed"}]},{"id":913276,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Wazuh One-Click","description":"Wazuh One-Click","ordinal":117,"logo_url":"assets/wazuh.svg","images":["linode/ubuntu22.04"],"deployments_total":5412,"deployments_active":830,"is_public":true,"mine":false,"created":"2021-09-30T18:27:36","updated":"2023-12-12T15:54:43","rev_note":"","script":"#!/bin/bash\n\n# #\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings \n#\n#\n#\n\n## Enable logging\n# set -o pipefail\nset -x\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n## Import the Bash StackScript Library\nsource \n## Import the DNS/API Functions Library\nsource \n## Import the OCA Helper Functions\nsource \n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\n# UFW https://documentation.wazuh.com/current/getting-started/architecture.html\nufw allow 1514\nufw allow 1515\nufw allow 1516\nufw allow 514\nufw allow 55000\nufw allow 443\nufw allow 80\nufw allow 9200\nufw allow 9300\n\n# NGINX\napt install git nginx certbot python3-certbot-nginx -y\n\nmkdir -p /var/www/certs/.well-known\nchown -R www-data:www-data /var/www/certs/\ncat < /etc/nginx/sites-available/$FQDN\nserver {\n listen 80;\n listen [::]:80;\n server_name $FQDN;\n root /var/www/certs;\n location / {\n try_files \\$uri \\$uri/ =404;\n }\n# allow .well-known\n location ^~ /.well-known {\n allow all;\n auth_basic off;\n alias /var/www/certs/.well-known;\n }\n}\nEOF\nln -s /etc/nginx/sites-available/$FQDN /etc/nginx/sites-enabled/$FQDN\nunlink /etc/nginx/sites-enabled/default\nsystemctl restart nginx\n\n# SSL Certbot\n#certbot certonly --agree-tos --webroot --webroot-path=/var/www/certs -d $FQDN -m $SOA_EMAIL_ADDRESS\n\nfunction get_cert {\n if [ \"$1\" == \"dry_run\" ]; then\n certbot certonly --dry-run --agree-tos --non-interactive --no-eff-email --webroot --webroot-path=/var/www/certs -d $FQDN -m $SOA_EMAIL_ADDRESS\n return $?\n elif [ \"$1\" == \"run\" ]; then\n certbot certonly --agree-tos --non-interactive --no-eff-email --webroot --webroot-path=/var/www/certs -d $FQDN -m $SOA_EMAIL_ADDRESS\n return $?\n fi\n}\n\nfunction propagate {\n while [[ $count -le $retries ]]; do\n echo \"[Info] Let's Encrypt validation failed. Retrying...\"\n sleep 5\n count=$(( $count + 1 ))\n get_cert dry_run\n\n if [ $? -eq 0 ]; then\n echo \"[Info] Dry run successful..\"\n get_cert run\n return 0\n \n fi\n\n # no more retries left. Exit\n if [[ $count -eq $retries ]]; then\n echo \"[Error] Unable to get Let's Encrypt certificate for $FQDN\"\n return 1\n fi\n done\n}\n\ncount=1\nretries=24\nget_cert dry_run\nif [ $? -eq 0 ]; then\n echo \"[Info] Dry run successful. Getting certificate\"\n get_cert run\nelse\n propagate\nfi\n\n# reorder Wazuh script\ncurl -sO https://packages.wazuh.com/4.4/wazuh-install.sh && sudo bash ./wazuh-install.sh -a \ntar -O -xvf wazuh-install-files.tar wazuh-install-files/wazuh-passwords.txt >> .deployment-secrets.txt\n\n# Set Variables\nexport WAZUH_FULL=/etc/wazuh-dashboard/certs/wazuh-dashboard.pem\nexport WAZUH_PRIVKEY=/etc/wazuh-dashboard/certs/wazuh-dashboard-key.pem\nexport FULLCHAIN=/etc/letsencrypt/live/$FQDN/fullchain.pem\nexport PRIVKEY=/etc/letsencrypt/live/$FQDN/privkey.pem\n\n# Place certificates in /etc/wazuh-dashboard/certs/\ncat $FULLCHAIN > $WAZUH_FULL\ncat $PRIVKEY > $WAZUH_PRIVKEY\n\n# Restart Kibana\nservice wazuh-dashboard restart\n\n# Create Cert renewal cron script\ncat </root/certbot-renewal.sh\n#!/bin/bash\n#\n# Script to handle Certbot renewal & Kibana\n# Debug\n# set -xo pipefail\nexport WAZUH_FULL=/etc/wazuh-dashboard/certs/wazuh-dashboard.pem\nexport WAZUH_PRIVKEY=/etc/wazuh-dashboard/certs/wazuh-dashboard-key.pem\nexport FULLCHAIN=/etc/letsencrypt/live/$FQDN/fullchain.pem\nexport PRIVKEY=/etc/letsencrypt/live/$FQDN/privkey.pem\ncertbot renew\ncat $FULLCHAIN > $WAZUH_FULL\ncat $PRIVKEY > $WAZUH_PRIVKEY\nservice wazuh-dashboard restart\nEND\n\nchmod +x /root/certbot-renewal.sh\n\n# Setup Cron\ncrontab -l > cron\necho \"* 1 * * 1 bash /root/certbot-renewal.sh\" >> cron\ncrontab cron\nrm cron\n\n# Cleanup\nstackscript_cleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your WordPress server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":662116,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Webmin One-Click","description":"Webmin One-Click","ordinal":118,"logo_url":"assets/webmin.svg","images":["linode/debian10"],"deployments_total":1190,"deployments_active":34,"is_public":true,"mine":false,"created":"2020-08-12T15:41:21","updated":"2023-12-11T22:40:34","rev_note":"","script":"#!/usr/bin/env bash\n\n### UDF Variables for the StackScript\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n#\n#\n\n#Check if the script is being sourced by another script\n[[ $_ != $0 ]] && readonly SOURCED=1\n\n## Enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n## Import the Bash StackScript and API/DNS Libraries\nsource \nsource \n\n## Import the OCA Helper Functions\nsource \n\n## Run initial configuration tasks (DNS/SSH stuff, etc...)\nsource \n\nfunction webmin_install {\n # Install webmin\n echo \"deb http://download.webmin.com/download/repository sarge contrib\" >> /etc/apt/sources.list\n wget -q -O- http://www.webmin.com/jcameron-key.asc | sudo apt-key add\n system_update\n system_install_package \"webmin\"\n}\n\nfunction webmin_configure {\n local -r email_address=\"$1\"\n local -r fqdn=\"$2\"\n\n # Configure the Virtual Host\n cat < /etc/apache2/sites-available/\"${fqdn}.conf\"\n\n ServerAdmin ${email_address}\n ServerName ${fqdn}\n ProxyPass / http://localhost:10000/\n ProxyPassReverse / http://localhost:10000/\n\nEOF\n # Disable SSL in Webmin so Apache can handle it instead\n sed -i 's/^ssl=1/ssl=0/g' /etc/webmin/miniserv.conf\n\n # Add FQDN to the list of allowed domains\n echo \"referers=${fqdn}\" >> /etc/webmin/config\n\n # Restart Webmin\n systemctl restart webmin\n\n # Enable proxy_http module\n a2enmod proxy_http\n systemctl restart apache2\n\n # Enable the Virtual Host\n a2ensite \"${fqdn}\"\n systemctl reload apache2\n}\n\n\n# Open the needed firewall ports\nufw_install\nufw allow http\nufw allow https\nufw allow 10000\n\n# Make sure unzip is installed, or else the webmin install will fail\n[ ! -x /usr/bin/unzip ] && system_install_package \"unzip\"\n\n# \"${package_list[@]}\" contains a list of packages to be installed on the system\npackage_list=(\n \"gnupg1\" \\\n \"python\" \\\n \"apt-show-versions\" \\\n \"libapt-pkg-perl\" \\\n \"libauthen-pam-perl\" \\\n \"libio-pty-perl\" \\\n \"libnet-ssleay-perl\"\n)\n\n# Install all of the packages specified in ${package_list[@]}\nsystem_install_package \"${package_list[@]}\"\n\n# Intall Webmin\nwebmin_install\napache_install\nwebmin_configure \"$SOA_EMAIL_ADDRESS\" \"$FQDN\"\n\n# Install SSL Certificate - NOT READY YET\n#certbot_ssl \"$FQDN\" \"$SOA_EMAIL_ADDRESS\" 'apache'\n\n## Cleanup before exiting\nif [ \"$SOURCED\" -ne 1 ]; then\n stackscript_cleanup\nfi","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"pwless_sudo","label":"Enable passwordless sudo access for the limited user?","oneof":"Yes,No","default":"No"},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"auto_updates","label":"Configure automatic security updates?","oneof":"Yes,No","default":"No"},{"name":"fail2ban","label":"Use fail2ban to prevent automated instrusion attempts?","oneof":"Yes,No","default":"No"},{"name":"token_password","label":"Your Linode API token. This is needed to create your DNS records","default":""},{"name":"subdomain","label":"The subdomain for your server","default":""},{"name":"domain","label":"Your domain","default":""},{"name":"soa_email_address","label":"Admin Email for the server","default":""},{"name":"mx","label":"Do you need an MX record for this domain? (Yes if sending mail from this Linode)","oneof":"Yes,No","default":"No"},{"name":"spf","label":"Do you need an SPF record for this domain? (Yes if sending mail from this Linode)","oneof":"Yes,No","default":"No"}]},{"id":688902,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Webuzo One-Click","description":"Webuzo One-Click","ordinal":119,"logo_url":"assets/webuzo.svg","images":["linode/ubuntu20.04"],"deployments_total":907,"deployments_active":21,"is_public":true,"mine":false,"created":"2020-11-17T21:04:21","updated":"2023-12-10T23:22:04","rev_note":"","script":"#!/usr/bin/env bash\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n# Source the Bash StackScript Library & Helpers\nsource \nsource \nsource \nsource \n\n# Logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n# Set hostname, configure apt and perform update/upgrade\napt_setup_update\n\n# Install Prereq's & Services\napt install -y wget\nwget -N http://files.webuzo.com/install.sh\nchmod +x install.sh\n./install.sh\nsleep 2\nsystemctl start webuzo.service\n\n# firewall\nufw allow 25\nufw allow 53\nufw allow 587\nufw allow 2002\nufw allow 2003\nufw allow 2004\nufw allow 2005\n\n# Cleanup \nstackscript_cleanup\nreboot","user_defined_fields":[{"name":"username","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","default":""},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"}]},{"id":401706,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"WireGuard® One-Click","description":"WireGuard One-Click","ordinal":120,"logo_url":"assets/Wireguard.svg","images":["linode/ubuntu22.04"],"deployments_total":9394,"deployments_active":292,"is_public":true,"mine":false,"created":"2019-03-08T21:11:36","updated":"2023-12-12T13:28:24","rev_note":"","script":"#!/bin/bash\n\n# \n# \n# \n# \n# \n\nsource \n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\nset -o pipefail\n\n### Set hostname, Apt configuration and update/upgrade\n\nset_hostname\napt_setup_update\n\napt install wireguard wireguard-tools linux-headers-$(uname -r) -y\n\nif [[ \"$PORT\" != \"51820\" ]]; then\n PORT=\"$PORT\"\nfi\n\n# Wireguard\n\nwg genkey | tee ~/wg-private.key | wg pubkey > ~/wg-public.key\n\nPRIVATEKEY=`cat ~/wg-private.key`\n\ncat </etc/wireguard/wg0.conf\n[Interface]\nPrivateKey = $PRIVATEKEY\nAddress = $PRIVATEIP\nListenPort = $PORT\nPostUp = iptables -A FORWARD -i wg0 -j ACCEPT; \\\niptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; \\\nip6tables -A FORWARD -i wg0 -j ACCEPT; \\\nip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\nPostDown = iptables -D FORWARD -i wg0 -j ACCEPT; \\\niptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; \\\nip6tables -D FORWARD -i wg0 -j ACCEPT; \\\nip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE\nSaveConfig = true\n[Peer]\nPublicKey = $PEERPUBKEY\nAllowedIPs = $PRIVATEIP_CLIENT\nEndpoint = $ENDPOINT:$PORT\nEND\n\n### Enable Port Forwarding\nsed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf\nsysctl -p /etc/sysctl.conf\nsysctl --system\n\n### Services\n\n# wg-quick up wg0. #### Removed to let systemctl manage the service\nsystemctl enable wg-quick@wg0\nsystemctl start wg-quick@wg0\nwg show\nufw_install\nufw allow \"$PORT\"/udp\nufw enable\n\nsystemctl restart wg-quick@wg0\n\nstackscript_cleanup","user_defined_fields":[{"name":"port","label":"Port","example":"51820","default":"51820"},{"name":"privateip","label":"Tunnel IP","example":"10.0.0.1/24, 172.16.0.1/24, 192.168.1.1/24, etc","default":"10.0.1.1/24"},{"name":"peerpubkey","label":"WireGuard Public Key (Client)","default":""},{"name":"privateip_client","label":"Tunnel IP (Client)","example":"10.0.0.2/24, 172.16.0.2/24, 192.168.1.2/24 etc","default":"10.0.1.2/24"},{"name":"endpoint","label":"Endpoint IP (Client)","default":""}]},{"id":401708,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"WooCommerce One-Click","description":"WooCommerce One-Click","ordinal":121,"logo_url":"assets/WooCommerce.svg","images":["linode/ubuntu22.04"],"deployments_total":4330,"deployments_active":213,"is_public":true,"mine":false,"created":"2019-03-08T21:12:57","updated":"2023-12-12T09:55:21","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n## Wordpress Settings\n#\n#\n\n#\n#\n#\n#\n\n## Linode/SSH Security Settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\"\nexport MARKETPLACE_APP=\"apps/linode-marketplace-woocommerce\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n local web_stack=$(echo ${WEBSERVER_STACK} | tr [:upper:] [:lower:])\n sed 's/ //g' < ${group_vars}\n\n # deployment vars\n soa_email_address: ${SOA_EMAIL_ADDRESS}\n webserver_stack: ${web_stack}\n site_title: ${SITE_TITLE}\n wp_admin_user: ${WP_ADMIN_USER}\n wp_db_user: ${WP_DB_USER}\n wp_db_name: ${WP_DB_NAME}\nEOF\n\n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n #else echo \"No domain entered\";\n else echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n}\n\nfunction installation_complete {\n # dumping credentials\n egrep \"(*^wp_|*mysql)\" ${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars | awk {'print $1 $2'} > /root/.linode_credentials.txt\n cat << EOF\n#########################\n# INSTALLATION COMPLETE #\n############################################\n# The Mysql root password can be found at: #\n# - /root/.linode_credentials.txt #\n# #\n# * Hugs are worth more than handshakes * #\n############################################\nEOF\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"webserver_stack","label":"The stack you are looking to deploy Wordpress on","oneof":"LAMP,LEMP"},{"name":"site_title","label":"Website title","example":"My Blog"},{"name":"wp_admin_user","label":"Admin username","example":"admin"},{"name":"wp_db_user","label":"Wordpress database user","example":"wordpress"},{"name":"wp_db_name","label":"Wordpress database name","example":"wordpress"},{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your Linode's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record. `www` will be entered if no subdomain is supplied (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""}]},{"id":741207,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Yacht One-Click","description":"Yacht One-Click","ordinal":122,"logo_url":"assets/yacht.svg","images":["linode/debian11","linode/ubuntu22.04"],"deployments_total":972,"deployments_active":16,"is_public":true,"mine":false,"created":"2021-01-26T21:52:26","updated":"2023-12-12T15:36:16","rev_note":"","script":"#!/bin/bash\nset -e\ntrap \"cleanup $? $LINENO\" EXIT\n\n##Linode/SSH security settings\n#\n#\n#\n#\n\n## Domain Settings\n#\n#\n#\n#\n\n## Yacht Settings \n#\n#\n#\n\n# git repo\nexport GIT_REPO=\"https://github.com/akamai-compute-marketplace/marketplace-apps.git\"\nexport WORK_DIR=\"/tmp/marketplace-apps\" \nexport MARKETPLACE_APP=\"apps/linode-marketplace-yacht\"\n\n# enable logging\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\nfunction cleanup {\n if [ -d \"${WORK_DIR}\" ]; then\n rm -rf ${WORK_DIR}\n fi\n\n}\n\nfunction udf {\n local group_vars=\"${WORK_DIR}/${MARKETPLACE_APP}/group_vars/linode/vars\"\n echo \"webserver_stack: lemp\" >> ${group_vars};\n \n if [[ -n ${USER_NAME} ]]; then\n echo \"username: ${USER_NAME}\" >> ${group_vars};\n else echo \"No username entered\";\n fi\n\n if [ \"$DISABLE_ROOT\" = \"Yes\" ]; then\n echo \"disable_root: yes\" >> ${group_vars};\n else echo \"Leaving root login enabled\";\n fi\n\n if [[ -n ${PASSWORD} ]]; then\n echo \"password: ${PASSWORD}\" >> ${group_vars};\n else echo \"No password entered\";\n fi\n\n if [[ -n ${PUBKEY} ]]; then\n echo \"pubkey: ${PUBKEY}\" >> ${group_vars};\n else echo \"No pubkey entered\";\n fi\n\n # yacht vars\n \n if [[ -n ${YEMAIL} ]]; then\n echo \"yemail: ${YEMAIL}\" >> ${group_vars};\n fi\n\n if [[ -n ${COMPOSE_SUPPORT} ]]; then\n echo \"compose_support: ${COMPOSE_SUPPORT}\" >> ${group_vars};\n fi\n\n if [[ -n ${YTHEME} ]]; then\n echo \"yacht_theme: ${YTHEME}\" >> ${group_vars};\n fi\n\n if [[ -n ${SOA_EMAIL_ADDRESS} ]]; then\n echo \"soa_email_address: ${SOA_EMAIL_ADDRESS}\" >> ${group_vars};\n fi\n\n if [[ -n ${DOMAIN} ]]; then\n echo \"domain: ${DOMAIN}\" >> ${group_vars};\n else\n echo \"default_dns: $(hostname -I | awk '{print $1}'| tr '.' '-' | awk {'print $1 \".ip.linodeusercontent.com\"'})\" >> ${group_vars};\n fi\n\n if [[ -n ${SUBDOMAIN} ]]; then\n echo \"subdomain: ${SUBDOMAIN}\" >> ${group_vars};\n else echo \"subdomain: www\" >> ${group_vars};\n fi\n\n if [[ -n ${TOKEN_PASSWORD} ]]; then\n echo \"token_password: ${TOKEN_PASSWORD}\" >> ${group_vars};\n else echo \"No API token entered\";\n fi\n}\n\nfunction run {\n # install dependancies\n apt-get update\n apt-get install -y git python3 python3-pip\n\n # clone repo and set up ansible environment\n git -C /tmp clone ${GIT_REPO}\n # for a single testing branch\n # git -C /tmp clone -b ${BRANCH} ${GIT_REPO}\n\n # venv\n cd ${WORK_DIR}/${MARKETPLACE_APP}\n pip3 install virtualenv\n python3 -m virtualenv env\n source env/bin/activate\n pip install pip --upgrade\n pip install -r requirements.txt\n ansible-galaxy install -r collections.yml\n\n # populate group_vars\n udf\n # run playbooks\n for playbook in provision.yml site.yml; do ansible-playbook -v $playbook; done\n \n}\n\nfunction installation_complete {\n echo \"Installation Complete\"\n}\n# main\nrun && installation_complete\ncleanup","user_defined_fields":[{"name":"user_name","label":"The limited sudo user to be created for the Linode","default":""},{"name":"password","label":"The password for the limited sudo user","example":"an0th3r_s3cure_p4ssw0rd","default":""},{"name":"disable_root","label":"Disable root access over SSH?","oneof":"Yes,No","default":"No"},{"name":"pubkey","label":"The SSH Public Key that will be used to access the Linode (Recommended)","default":""},{"name":"token_password","label":"Your Linode API token. This is needed to create your server's DNS records","default":""},{"name":"subdomain","label":"Subdomain","example":"The subdomain for the DNS record: www (Requires Domain)","default":""},{"name":"domain","label":"Domain","example":"The domain for the DNS record: example.com (Requires API token)","default":""},{"name":"soa_email_address","label":"Email address (for the Let's Encrypt SSL certificate)","example":"user@domain.tld"},{"name":"yemail","label":"Yacht Email","example":"admin@yacht.local","default":"admin@yacht.local"},{"name":"compose_support","label":"Yacht Compose Support","example":"Yes","default":"Yes","oneof":"Yes,No"},{"name":"ytheme","label":"Yacht Theme","example":"Default","default":"Default","oneof":"Default,RED,OMV"}]},{"id":741208,"username":"linode","user_gravatar_id":"9d4d301385af69ceb7ad658aad09c142","label":"Zabbix One-Click","description":"Zabbix One-Click","ordinal":123,"logo_url":"assets/zabbix.svg","images":["linode/centos-stream8"],"deployments_total":1793,"deployments_active":81,"is_public":true,"mine":false,"created":"2021-01-26T21:56:54","updated":"2023-12-12T12:47:10","rev_note":"","script":"#!/bin/bash\n\n# \n\nsource \n\nsystem_set_hostname \"$HOSTNAME\"\n\nexec > >(tee /dev/ttyS0 /var/log/stackscript.log) 2>&1\n\n# Generate files\nmkdir -p /etc/my.cnf.d/\nmkdir -p /etc/nginx/conf.d/\nmkdir -p /etc/php-fpm.d/\nmkdir -p /etc/php.d/\n# mkdir -p /etc/profile.d/\nmkdir -p /etc/motd.d/\nmkdir -p /etc/zabbix/web/\nmkdir -p /var/lib/cloud/scripts/per-instance\n\ncat </etc/my.cnf.d/zabbix.cnf\n[mysqld]\nuser = mysql\nlocal_infile = 0\n\ndatadir = /var/lib/mysql/\n\ndefault-storage-engine = InnoDB\nskip-name-resolve\nkey_buffer_size = 32M\nmax_allowed_packet = 128M\ntable_open_cache = 1024\ntable_definition_cache = 1024\nmax_connections = 2000\njoin_buffer_size = 1M\nsort_buffer_size = 2M\nread_buffer_size = 256K\nread_rnd_buffer_size = 256K\nmyisam_sort_buffer_size = 1M\nthread_cache_size = 512\nopen_files_limit = 10000\nwait_timeout = 86400\n\noptimizer_switch=index_condition_pushdown=off\n\ntmp_table_size = 32M\nmax_heap_table_size = 32M\n\nbinlog_format=mixed\nbinlog_cache_size = 32M\nmax_binlog_size = 256M\nbinlog_expire_logs_seconds = 259200\n\n# innodb_page_size = 32K\ninnodb_buffer_pool_size = 512M\ninnodb_log_file_size = 256M\ninnodb_log_buffer_size = 64M\ninnodb_file_per_table = 1\ninnodb_flush_method = O_DIRECT\ninnodb_buffer_pool_instances = 4\ninnodb_write_io_threads = 4\ninnodb_read_io_threads = 4\ninnodb_adaptive_flushing = 1\ninnodb_lock_wait_timeout = 50\n\ninnodb_flush_log_at_trx_commit = 1\n\ninnodb_io_capacity = 300\ninnodb_io_capacity_max = 400\ninnodb_flush_neighbors = 0\n\ninnodb_doublewrite = 1\ninnodb_thread_concurrency = 0\n\ninnodb_purge_threads = 1\n\nserver_id = 1\nbinlog_checksum = crc32\n\ninnodb_lru_scan_depth = 512\n\ninnodb_stats_on_metadata = 0\n\nEND\n\ncat </etc/nginx/conf.d/zabbix_ssl.conf\nserver {\n listen 0.0.0.0:443 ssl http2;\n # server_name ;\n index index.php;\n\n root \\$webroot;\n charset utf8;\n set \\$webroot '/usr/share/zabbix';\n\n access_log /var/log/nginx/zabbix_access_ssl.log main;\n error_log /var/log/nginx/zabbix_error_ssl.log error;\n\n ssl_stapling on;\n ssl_stapling_verify on;\n\n #resolver 192.168.13.160 192.168.10.24;\n\n ssl_certificate /etc/ssl/certs/zabbix_example.crt;\n ssl_certificate_key /etc/ssl/private/zabbix_example.key;\n\n ssl_dhparam /etc/ssl/private/zabbix_dhparam.pem;\n\n ssl_protocols TLSv1.2 TLSv1.3;\n ssl_verify_depth 3;\n #ssl_ciphers HIGH:!aNULL:!MD5;\n ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;\n #ssl_session_cache shared:SSL:10m;\n ssl_session_cache shared:MozSSL:10m;\n ssl_session_timeout 1d;\n ssl_prefer_server_ciphers off;\n ssl_session_tickets off;\n\n add_header Strict-Transport-Security \"max-age=63072000\" always;\n add_header Content-Security-Policy-Report-Only \"default-src https:; script-src https: 'unsafe-eval' 'unsafe-inline'; style-src https: 'unsafe-inline'; img-src https: data:; font-src https: data:; report-uri /csp-report\";\n\n location = /favicon.ico {\n log_not_found off;\n }\n\n location / {\n index index.php;\n try_files \\$uri \\$uri/ =404;\n }\n\n location ~* ^.+.(js|css|png|jpg|jpeg|gif|ico)$ {\n access_log off;\n expires 10d;\n }\n\n location ~ /\\.ht {\n deny all;\n }\n\n location ~ /(api\\/|conf[^\\.]|include|locale) {\n deny all;\n return 404;\n }\n\n location ~ [^/]\\.php(/|$) {\n fastcgi_pass unix:/run/php-fpm/zabbix.sock;\n fastcgi_split_path_info ^(.+\\.php)(/.+)$;\n fastcgi_index index.php;\n\n fastcgi_param DOCUMENT_ROOT /usr/share/zabbix;\n fastcgi_param SCRIPT_FILENAME /usr/share/zabbix\\$fastcgi_script_name;\n fastcgi_param PATH_TRANSLATED /usr/share/zabbix\\$fastcgi_script_name;\n\n include fastcgi_params;\n fastcgi_param QUERY_STRING \\$query_string;\n fastcgi_param REQUEST_METHOD \\$request_method;\n fastcgi_param CONTENT_TYPE \\$content_type;\n fastcgi_param CONTENT_LENGTH \\$content_length;\n\n fastcgi_intercept_errors on;\n fastcgi_ignore_client_abort off;\n fastcgi_connect_timeout 60;\n fastcgi_send_timeout 180;\n fastcgi_read_timeout 180;\n fastcgi_buffer_size 128k;\n fastcgi_buffers 4 256k;\n fastcgi_busy_buffers_size 256k;\n fastcgi_temp_file_write_size 256k;\n }\n}\n\nEND\n\ncat </etc/nginx/conf.d/zabbix.conf\nserver {\n listen 0.0.0.0:80;\n # server_name zabbix;\n\n return 301 https://\\$host\\$request_uri;\n}\n\nEND\n\ncat </etc/nginx/nginx.conf\n# For more information on configuration, see:\n# * Official English Documentation: http://nginx.org/en/docs/\n# * Official Russian Documentation: http://nginx.org/ru/docs/\n\nuser nginx;\nworker_processes auto;\nworker_priority -5;\nworker_rlimit_nofile 256000;\n\nerror_log /var/log/nginx/error.log;\n\npid /run/nginx.pid;\n\n# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.\ninclude /usr/share/nginx/modules/*.conf;\n\nevents {\n worker_connections 5120;\n use epoll;\n multi_accept on;\n}\n\n\nhttp {\n include /etc/nginx/mime.types;\n default_type application/octet-stream;\n\n log_format main\n '\\$http_x_forwarded_for - \\$remote_user [\\$time_local] '\n '\"\\$request\" \\$status \\$bytes_sent '\n '\"\\$http_referer\" \"\\$http_user_agent\" '\n '\"\\$gzip_ratio\"';\n\n access_log /var/log/nginx/access.log main;\n\n open_file_cache max=200000 inactive=20s;\n open_file_cache_valid 30s;\n open_file_cache_min_uses 2;\n open_file_cache_errors on;\n\n limit_conn_zone \\$binary_remote_addr zone=perip:10m;\n limit_conn_zone \\$server_name zone=perserver:10m;\n\n client_header_timeout 5m;\n client_body_timeout 5m;\n send_timeout 5m;\n\n connection_pool_size 4096;\n client_header_buffer_size 4k;\n large_client_header_buffers 4 4k;\n request_pool_size 4k;\n\n reset_timedout_connection on;\n\n\n gzip on;\n gzip_min_length 100;\n gzip_buffers 4 8k;\n gzip_comp_level 5;\n gzip_types text/plain text/css text/xml application/x-javascript application/xml application/xhtml+xml;\n\n types_hash_max_size 2048;\n\n output_buffers 128 512k;\n postpone_output 1460;\n aio on;\n directio 512;\n\n sendfile on;\n client_max_body_size 8m;\n fastcgi_intercept_errors on;\n\n tcp_nopush on;\n tcp_nodelay on;\n\n keepalive_timeout 75 20;\n\n ignore_invalid_headers on;\n\n index index.php;\n server_tokens off;\n\n # Load modular configuration files from the /etc/nginx/conf.d directory.\n # See http://nginx.org/en/docs/ngx_core_module.html#include\n # for more information.\n include /etc/nginx/conf.d/*.conf;\n}\n\nEND\n\ncat </etc/php-fpm.d/zabbix.conf\n[zabbix]\nuser = apache\ngroup = apache\n\nlisten = /run/php-fpm/zabbix.sock\nlisten.acl_users = apache,nginx\nlisten.allowed_clients = 127.0.0.1\n\npm = dynamic\npm.max_children = 50\npm.start_servers = 5\npm.min_spare_servers = 5\npm.max_spare_servers = 35\n\nphp_value[session.save_handler] = files\nphp_value[session.save_path] = /var/lib/php/session\n\nphp_value[max_execution_time] = 300\nphp_value[memory_limit] = 128M\nphp_value[post_max_size] = 16M\nphp_value[upload_max_filesize] = 2M\nphp_value[max_input_time] = 300\nphp_value[max_input_vars] = 10000\n; php_value[date.timezone] = Europe/Riga\nEND\n\n# cat </etc/php.d/99-zabbix.ini\n# max_execution_time=300\n# memory_limit=128M\n# post_max_size=16M\n# upload_max_filesize=2M\n# max_input_time=300\n# always_populate_raw_post_data=-1\n# max_input_vars=10000\n# date.timezone=UTC\n# session.save_path=/var/lib/php/\n# END\n\n# cat </etc/profile.d/zabbix_welcome.sh\n# #!/bin/sh\n# #\n# myip=\\$(hostname -I | awk '{print\\$1}')\n# cat </etc/motd.d/zabbix\n********************************************************************************\n\nZabbix frontend credentials:\n\nUsername: Admin\n\nPassword: replace_password\n\n\nTo learn about available professional services, including technical suppport and training, please visit https://www.zabbix.com/services\n\nOfficial Zabbix documentation available at https://www.zabbix.com/documentation/current/\n\n\n********************************************************************************\nEND\n\n# cat </etc/systemd/system/zabbix-instance-init.service\n# [Unit]\n# After=mariadb.service\n\n# [Service]\n# ExecStart=/var/lib/cloud/scripts/per-instance/001-zabbix\n\n# [Install]\n# WantedBy=multi-user.target\n# END\n\n# cat </etc/yum.repos.d/MariaDB.repo\n# # MariaDB 10.3 CentOS repository list - created 2019-03-28 10:57 UTC\n# # http://downloads.mariadb.org/mariadb/repositories/\n# [mariadb]\n# name = MariaDB\n# baseurl = http://yum.mariadb.org/10.2/centos7-amd64\n# gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB\n# gpgcheck=1\n# END\n\ncat </etc/yum.repos.d/Nginx.repo\n[nginx-stable]\nname=nginx stable repo\nbaseurl=http://nginx.org/packages/centos/\\$releasever/\\$basearch/\ngpgcheck=1\nenabled=1\ngpgkey=https://nginx.org/keys/nginx_signing.key\nmodule_hotfixes=true\n\n[nginx-mainline]\nname=nginx mainline repo\nbaseurl=http://nginx.org/packages/mainline/centos/\\$releasever/\\$basearch/\ngpgcheck=1\nenabled=0\ngpgkey=https://nginx.org/keys/nginx_signing.key\nmodule_hotfixes=true\nEND\n\ncat </etc/zabbix/web/zabbix.conf.php\n 'http://localhost:9200',\n//\t'text' => 'http://localhost:9200'\n//];\n// Value types stored in Elasticsearch.\n//\\$HISTORY['types'] = ['uint', 'text'];\n\n// Used for SAML authentication.\n// Uncomment to override the default paths to SP private key, SP and IdP X.509 certificates, and to set extra settings.\n//\\$SSO['SP_KEY']\t\t\t= 'conf/certs/sp.key';\n//\\$SSO['SP_CERT']\t\t\t= 'conf/certs/sp.crt';\n//\\$SSO['IDP_CERT']\t\t= 'conf/certs/idp.crt';\n//\\$SSO['SETTINGS']\t\t= [];\nEND\n\ncat </tmp/zabbix_server_custom.te\nmodule zabbix_server_custom 1.2;\nrequire {\n type zabbix_var_run_t;\n type tmp_t;\n type zabbix_t;\n class sock_file { create unlink write };\n class unix_stream_socket connectto;\n class process setrlimit;\n class capability dac_override;\n}\n#============= zabbix_t ==============\n#!!!! This avc is allowed in the current policy\nallow zabbix_t self:process setrlimit;\n#!!!! This avc is allowed in the current policy\nallow zabbix_t self:unix_stream_socket connectto;\n#!!!! This avc is allowed in the current policy\nallow zabbix_t tmp_t:sock_file { create unlink write };\n#!!!! This avc is allowed in the current policy\nallow zabbix_t zabbix_var_run_t:sock_file { create unlink write };\n#!!!! This avc is allowed in the current policy\nallow zabbix_t self:capability dac_override;\nEND\n\n# Installing RPM packages\nyum makecache\nyum -y upgrade\nyum -y install wget\nwget https://dev.mysql.com/get/mysql80-community-release-el8-3.noarch.rpm\ndnf -y install mysql80-community-release-el8-3.noarch.rpm\ndnf -y module disable mysql\ndnf -y install https://repo.zabbix.com/zabbix/6.0/rhel/8/x86_64/zabbix-release-6.0-1.el8.noarch.rpm\ndnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm\ndnf -y install epel-release\ndnf -y module enable php:remi-8.1\nyum -y install cloud-init cloud-utils-growpart firewalld nginx php-fpm mysql-community-client mysql-community-server java-1.8.0-openjdk-headless zabbix-server-mysql zabbix-web-mysql zabbix-nginx-conf zabbix-sql-scripts zabbix-agent zabbix-get zabbix-sender zabbix-java-gateway zabbix-js\n\n\n# Configure firewalld\nsystemctl enable firewalld\nsystemctl start firewalld\nfirewall-cmd --permanent --add-service=ssh --zone=public\nfirewall-cmd --permanent --add-service=http --zone=public\nfirewall-cmd --permanent --add-service=https --zone=public\nfirewall-cmd --permanent --add-port=10051/tcp --zone=public\nfirewall-cmd --reload\n\n# Configure SELinux\nrm -rf /tmp/zabbix_server_custom.mod /tmp/zabbix_server_custom.pp\ncheckmodule -M -m -o /tmp/zabbix_server_custom.mod /tmp/zabbix_server_custom.te\nsemodule_package -o /tmp/zabbix_server_custom.pp -m /tmp/zabbix_server_custom.mod\nsemodule -i /tmp/zabbix_server_custom.pp\n\nsetsebool -P httpd_can_connect_zabbix=1\nsetsebool -P zabbix_can_network=1\n\n# Generate SSL certificate\nmkdir -p /etc/ssl/private\nopenssl dhparam -out /etc/ssl/private/zabbix_dhparam.pem 2048\n\nopenssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/zabbix_example.key \\\n -out /etc/ssl/certs/zabbix_example.crt -subj \"/C=LV/ST=Riga/L=Riga/O=Global Security/OU=IT Department/CN=example.zabbix.com\"\n\n# Configure Zabbix instance\nsystemctl enable mysqld\nsystemctl disable nginx\nsystemctl disable php-fpm\nsystemctl disable zabbix-server\nsystemctl enable zabbix-agent\nsystemctl enable zabbix-java-gateway\n\nsystemctl stop nginx php-fpm\n\necho \"Requires=multi-user.target\" >> /usr/lib/systemd/system/cloud-init.target\n\nsystemctl set-default cloud-init.target\n\nchown -R apache:apache /var/lib/php/\n\nchmod g+r /etc/zabbix/zabbix_server.conf\nchmod o+w /run/zabbix/\n\nchmod 755 /etc/my.cnf\nchmod -R 755 /etc/my.cnf.d/\n\nsed -i 's/^#PrintMotd yes/&\\nPrintMotd no/g' /etc/ssh/sshd_config\n\nsed -i '/^; php_value\\[date.timezone\\] /s/^; //' /etc/php-fpm.d/zabbix.conf\n\nsed -i 's/^# JavaGateway=.*/&\\nJavaGateway=127.0.0.1/g' /etc/zabbix/zabbix_server.conf\nsed -i 's/^# StartJavaPollers=.*/&\\nStartJavaPollers=5/g' /etc/zabbix/zabbix_server.conf\nsed -i 's/^# LISTEN_IP=.*/&\\nLISTEN_IP=\"127.0.0.1\"/g' /etc/zabbix/zabbix_java_gateway.conf\n\nescape_spec_char() {\n local var_value=$1\n\n var_value=\"${var_value//\\\\/\\\\\\\\}\"\n var_value=\"${var_value//[$'\\n']/}\"\n var_value=\"${var_value//\\//\\\\/}\"\n var_value=\"${var_value//./\\\\.}\"\n var_value=\"${var_value//\\*/\\\\*}\"\n var_value=\"${var_value//^/\\\\^}\"\n var_value=\"${var_value//\\$/\\\\$}\"\n var_value=\"${var_value//\\&/\\\\&}\"\n var_value=\"${var_value//\\[/\\\\[}\"\n var_value=\"${var_value//\\]/\\\\]}\"\n\n echo \"$var_value\"\n}\n\nsystemctl start mysqld\nsystemctl enable mysqld\nsystemctl enable nginx\nsystemctl enable php-fpm\nsystemctl enable zabbix-server\n\nDB_ROOT_TMP_PASS=$(grep 'temporary password' /var/log/mysqld.log | awk '{print $13}' | tail -1)\nWEB_PASS=$(openssl rand -base64 14)\nWEB_PASS=${WEB_PASS%?}\nINST_NAME=$(hostname)\n\nrm -f /root/.my.cnf\n\nDB_ROOT_PASS=$(MYSQL_PWD=\"$DB_ROOT_TMP_PASS\" mysql --connect-expired-password -s -N -e \"SET PASSWORD FOR root@localhost TO RANDOM;\" | awk '{print $3}')\nDB_ZBX_PASS=$(MYSQL_PWD=\"$DB_ROOT_PASS\" mysql -s -N -e \"CREATE USER 'zabbix_srv'@'localhost' IDENTIFIED WITH mysql_native_password BY RANDOM PASSWORD\" | awk '{print $3}')\nDB_ZBXWEB_PASS=$(MYSQL_PWD=\"$DB_ROOT_PASS\" mysql -s -N -e \"CREATE USER 'zabbix_web'@'localhost' IDENTIFIED WITH mysql_native_password BY RANDOM PASSWORD\" | awk '{print $3}')\n\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"CREATE DATABASE zabbix CHARACTER SET 'utf8' COLLATE 'utf8_bin'\"\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"GRANT SELECT, UPDATE, DELETE, INSERT, CREATE, DROP, ALTER, INDEX, REFERENCES ON zabbix.* TO 'zabbix_srv'@'localhost'\"\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"GRANT SELECT, UPDATE, DELETE, INSERT, CREATE, DROP ON zabbix.* TO 'zabbix_web'@'localhost'\"\n\ncat > /root/.my.cnf << EOF\n[client]\npassword=\"$DB_ROOT_PASS\"\nEOF\n\nzcat /usr/share/zabbix-sql-scripts/mysql/server.sql.gz | MYSQL_PWD=\"$DB_ROOT_PASS\" mysql -uroot zabbix\n\nMYSQL_PWD=\"$DB_ROOT_PASS\" mysql -u root -e \"UPDATE users SET passwd = MD5('$WEB_PASS') WHERE username = 'Admin'\" zabbix\n\nWEB_PASS=$(escape_spec_char \"$WEB_PASS\")\nsed -i \"s/replace_password/$WEB_PASS/g\" /etc/motd.d/zabbix\n\nsed -i \"s/replace_name/$INST_NAME/g\" /etc/zabbix/web/zabbix.conf.php\n\nDB_ZBX_PASS=$(escape_spec_char \"$DB_ZBX_PASS\")\nDB_ZBXWEB_PASS=$(escape_spec_char \"$DB_ZBXWEB_PASS\")\n\nsed -i \"s/^DBUser=.*/DBUser=zabbix_srv/g\" /etc/zabbix/zabbix_server.conf\nsed -i -e \"/^[#;] DBPassword=/s/.*/&\\nDBPassword=$DB_ZBX_PASS/\" /etc/zabbix/zabbix_server.conf\nsed -i \"s/replace_password/$DB_ZBXWEB_PASS/g\" /etc/zabbix/web/zabbix.conf.php\nsed -i \"s/replace_user/zabbix_web/g\" /etc/zabbix/web/zabbix.conf.php\n\n# Cleaning up remote machine\nrm -rf /etc/nginx/conf.d/default.conf\nrm -rf /tmp/* /var/tmp/*\nhistory -c\ncat /dev/null > /root/.bash_history\nunset HISTFILE\nfind /var/log -mtime -1 -type f ! -name 'stackscript.log' -exec truncate -s 0 {} \\;\n\n\n\nsystemctl start zabbix-server zabbix-agent zabbix-java-gateway\nsystemctl start nginx php-fpm\n\necho \"Installation complete!\"","user_defined_fields":[{"name":"hostname","label":"Hostname"}]}],"page":1,"pages":1,"results":129} \ No newline at end of file diff --git a/packages/manager/src/cachedData/regions.json b/packages/manager/src/cachedData/regions.json index e9f0ca7d333..3becff548ed 100644 --- a/packages/manager/src/cachedData/regions.json +++ b/packages/manager/src/cachedData/regions.json @@ -1 +1 @@ -{"data":[{"id":"ap-west","label":"Mumbai, IN","country":"in","capabilities":["Linodes","NodeBalancers","Block Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"172.105.34.5, 172.105.35.5, 172.105.36.5, 172.105.37.5, 172.105.38.5, 172.105.39.5, 172.105.40.5, 172.105.41.5, 172.105.42.5, 172.105.43.5","ipv6":"2400:8904::f03c:91ff:fea5:659, 2400:8904::f03c:91ff:fea5:9282, 2400:8904::f03c:91ff:fea5:b9b3, 2400:8904::f03c:91ff:fea5:925a, 2400:8904::f03c:91ff:fea5:22cb, 2400:8904::f03c:91ff:fea5:227a, 2400:8904::f03c:91ff:fea5:924c, 2400:8904::f03c:91ff:fea5:f7e2, 2400:8904::f03c:91ff:fea5:2205, 2400:8904::f03c:91ff:fea5:9207"}},{"id":"ca-central","label":"Toronto, CA","country":"ca","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"172.105.0.5, 172.105.3.5, 172.105.4.5, 172.105.5.5, 172.105.6.5, 172.105.7.5, 172.105.8.5, 172.105.9.5, 172.105.10.5, 172.105.11.5","ipv6":"2600:3c04::f03c:91ff:fea9:f63, 2600:3c04::f03c:91ff:fea9:f6d, 2600:3c04::f03c:91ff:fea9:f80, 2600:3c04::f03c:91ff:fea9:f0f, 2600:3c04::f03c:91ff:fea9:f99, 2600:3c04::f03c:91ff:fea9:fbd, 2600:3c04::f03c:91ff:fea9:fdd, 2600:3c04::f03c:91ff:fea9:fe2, 2600:3c04::f03c:91ff:fea9:f68, 2600:3c04::f03c:91ff:fea9:f4a"}},{"id":"ap-southeast","label":"Sydney, AU","country":"au","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"172.105.166.5, 172.105.169.5, 172.105.168.5, 172.105.172.5, 172.105.162.5, 172.105.170.5, 172.105.167.5, 172.105.171.5, 172.105.181.5, 172.105.161.5","ipv6":"2400:8907::f03c:92ff:fe6e:ec8, 2400:8907::f03c:92ff:fe6e:98e4, 2400:8907::f03c:92ff:fe6e:1c58, 2400:8907::f03c:92ff:fe6e:c299, 2400:8907::f03c:92ff:fe6e:c210, 2400:8907::f03c:92ff:fe6e:c219, 2400:8907::f03c:92ff:fe6e:1c5c, 2400:8907::f03c:92ff:fe6e:c24e, 2400:8907::f03c:92ff:fe6e:e6b, 2400:8907::f03c:92ff:fe6e:e3d"}},{"id":"us-iad","label":"Washington, DC","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Managed Databases","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"139.144.192.62, 139.144.192.60, 139.144.192.61, 139.144.192.53, 139.144.192.54, 139.144.192.67, 139.144.192.69, 139.144.192.66, 139.144.192.52, 139.144.192.68","ipv6":"2600:3c05::f03c:93ff:feb6:43b6, 2600:3c05::f03c:93ff:feb6:4365, 2600:3c05::f03c:93ff:feb6:43c2, 2600:3c05::f03c:93ff:feb6:e441, 2600:3c05::f03c:93ff:feb6:94ef, 2600:3c05::f03c:93ff:feb6:94ba, 2600:3c05::f03c:93ff:feb6:94a8, 2600:3c05::f03c:93ff:feb6:9413, 2600:3c05::f03c:93ff:feb6:9443, 2600:3c05::f03c:93ff:feb6:94e0"}},{"id":"us-ord","label":"Chicago, IL","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Managed Databases","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.0.17, 172.232.0.16, 172.232.0.21, 172.232.0.13, 172.232.0.22, 172.232.0.9, 172.232.0.19, 172.232.0.20, 172.232.0.15, 172.232.0.18","ipv6":"2600:3c06::f03c:93ff:fed0:e5fc, 2600:3c06::f03c:93ff:fed0:e54b, 2600:3c06::f03c:93ff:fed0:e572, 2600:3c06::f03c:93ff:fed0:e530, 2600:3c06::f03c:93ff:fed0:e597, 2600:3c06::f03c:93ff:fed0:e511, 2600:3c06::f03c:93ff:fed0:e5f2, 2600:3c06::f03c:93ff:fed0:e5bf, 2600:3c06::f03c:93ff:fed0:e529, 2600:3c06::f03c:93ff:fed0:e5a3"}},{"id":"fr-par","label":"Paris, FR","country":"fr","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Managed Databases","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.32.21, 172.232.32.23, 172.232.32.17, 172.232.32.18, 172.232.32.16, 172.232.32.22, 172.232.32.20, 172.232.32.14, 172.232.32.11, 172.232.32.12","ipv6":"2600:3c07::f03c:93ff:fef2:2e63, 2600:3c07::f03c:93ff:fef2:2ec7, 2600:3c07::f03c:93ff:fef2:0dee, 2600:3c07::f03c:93ff:fef2:0d25, 2600:3c07::f03c:93ff:fef2:0de0, 2600:3c07::f03c:93ff:fef2:2e29, 2600:3c07::f03c:93ff:fef2:0dda, 2600:3c07::f03c:93ff:fef2:0d82, 2600:3c07::f03c:93ff:fef2:b3ac, 2600:3c07::f03c:93ff:fef2:b3a8"}},{"id":"us-central","label":"Dallas, TX","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"72.14.179.5, 72.14.188.5, 173.255.199.5, 66.228.53.5, 96.126.122.5, 96.126.124.5, 96.126.127.5, 198.58.107.5, 198.58.111.5, 23.239.24.5","ipv6":"2600:3c00::2, 2600:3c00::9, 2600:3c00::7, 2600:3c00::5, 2600:3c00::3, 2600:3c00::8, 2600:3c00::6, 2600:3c00::4, 2600:3c00::c, 2600:3c00::b"}},{"id":"us-west","label":"Fremont, CA","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"173.230.145.5, 173.230.147.5, 173.230.155.5, 173.255.212.5, 173.255.219.5, 173.255.241.5, 173.255.243.5, 173.255.244.5, 74.207.241.5, 74.207.242.5","ipv6":"2600:3c01::2, 2600:3c01::9, 2600:3c01::5, 2600:3c01::7, 2600:3c01::3, 2600:3c01::8, 2600:3c01::4, 2600:3c01::b, 2600:3c01::c, 2600:3c01::6"}},{"id":"us-southeast","label":"Atlanta, GA","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"74.207.231.5, 173.230.128.5, 173.230.129.5, 173.230.136.5, 173.230.140.5, 66.228.59.5, 66.228.62.5, 50.116.35.5, 50.116.41.5, 23.239.18.5","ipv6":"2600:3c02::3, 2600:3c02::5, 2600:3c02::4, 2600:3c02::6, 2600:3c02::c, 2600:3c02::7, 2600:3c02::2, 2600:3c02::9, 2600:3c02::8, 2600:3c02::b"}},{"id":"us-east","label":"Newark, NJ","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Bare Metal","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"66.228.42.5, 96.126.106.5, 50.116.53.5, 50.116.58.5, 50.116.61.5, 50.116.62.5, 66.175.211.5, 97.107.133.4, 207.192.69.4, 207.192.69.5","ipv6":"2600:3c03::7, 2600:3c03::4, 2600:3c03::9, 2600:3c03::6, 2600:3c03::3, 2600:3c03::c, 2600:3c03::5, 2600:3c03::b, 2600:3c03::2, 2600:3c03::8"}},{"id":"eu-west","label":"London, UK","country":"gb","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"178.79.182.5, 176.58.107.5, 176.58.116.5, 176.58.121.5, 151.236.220.5, 212.71.252.5, 212.71.253.5, 109.74.192.20, 109.74.193.20, 109.74.194.20","ipv6":"2a01:7e00::9, 2a01:7e00::3, 2a01:7e00::c, 2a01:7e00::5, 2a01:7e00::6, 2a01:7e00::8, 2a01:7e00::b, 2a01:7e00::4, 2a01:7e00::7, 2a01:7e00::2"}},{"id":"ap-south","label":"Singapore, SG","country":"sg","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"139.162.11.5, 139.162.13.5, 139.162.14.5, 139.162.15.5, 139.162.16.5, 139.162.21.5, 139.162.27.5, 103.3.60.18, 103.3.60.19, 103.3.60.20","ipv6":"2400:8901::5, 2400:8901::4, 2400:8901::b, 2400:8901::3, 2400:8901::9, 2400:8901::2, 2400:8901::8, 2400:8901::7, 2400:8901::c, 2400:8901::6"}},{"id":"eu-central","label":"Frankfurt, DE","country":"de","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5","ipv6":"2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8"}},{"id":"ap-northeast","label":"Tokyo, JP","country":"jp","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"139.162.66.5, 139.162.67.5, 139.162.68.5, 139.162.69.5, 139.162.70.5, 139.162.71.5, 139.162.72.5, 139.162.73.5, 139.162.74.5, 139.162.75.5","ipv6":"2400:8902::3, 2400:8902::6, 2400:8902::c, 2400:8902::4, 2400:8902::2, 2400:8902::8, 2400:8902::7, 2400:8902::5, 2400:8902::b, 2400:8902::9"}},{"id": "id-cgk","label": "Jakarta, ID","country": "id","capabilities": ["Linodes","NodeBalancers", "Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Premium Plans"],"status": "ok","resolvers": {"ipv4": "172.232.224.23, 172.232.224.32, 172.232.224.26, 172.232.224.27, 172.232.224.21, 172.232.224.24, 172.232.224.22, 172.232.224.20, 172.232.224.31, 172.232.224.28","ipv6": "2600:3c0c::f03c:93ff:feed:a90b, 2600:3c0c::f03c:93ff:feed:a9a5, 2600:3c0c::f03c:93ff:feed:a935, 2600:3c0c::f03c:93ff:feed:a930, 2600:3c0c::f03c:93ff:feed:a95c, 2600:3c0c::f03c:93ff:feed:a9ad, 2600:3c0c::f03c:93ff:feed:a9f2, 2600:3c0c::f03c:93ff:feed:a9ff, 2600:3c0c::f03c:93ff:feed:a9c8, 2600:3c0c::f03c:93ff:feed:a96b"}}, {"id": "br-gru","label": "Sao Paulo, BR","country": "br","capabilities": ["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Premium Plans"],"status": "ok","resolvers": {"ipv4": "172.233.0.4, 172.233.0.9, 172.233.0.7, 172.233.0.12, 172.233.0.5, 172.233.0.13, 172.233.0.10, 172.233.0.6, 172.233.0.8, 172.233.0.11","ipv6": "2600:3c0d::f03c:93ff:fe3d:51cb, 2600:3c0d::f03c:93ff:fe3d:51a7, 2600:3c0d::f03c:93ff:fe3d:51a9, 2600:3c0d::f03c:93ff:fe3d:5119, 2600:3c0d::f03c:93ff:fe3d:51fe, 2600:3c0d::f03c:93ff:fe3d:517c, 2600:3c0d::f03c:93ff:fe3d:5144, 2600:3c0d::f03c:93ff:fe3d:5170, 2600:3c0d::f03c:93ff:fe3d:51cc, 2600:3c0d::f03c:93ff:fe3d:516c"}}],"page":1,"pages":1,"results":14} \ No newline at end of file +{"data":[{"id":"ap-west","label":"Mumbai, IN","country":"in","capabilities":["Linodes","NodeBalancers","Block Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"172.105.34.5, 172.105.35.5, 172.105.36.5, 172.105.37.5, 172.105.38.5, 172.105.39.5, 172.105.40.5, 172.105.41.5, 172.105.42.5, 172.105.43.5","ipv6":"2400:8904::f03c:91ff:fea5:659, 2400:8904::f03c:91ff:fea5:9282, 2400:8904::f03c:91ff:fea5:b9b3, 2400:8904::f03c:91ff:fea5:925a, 2400:8904::f03c:91ff:fea5:22cb, 2400:8904::f03c:91ff:fea5:227a, 2400:8904::f03c:91ff:fea5:924c, 2400:8904::f03c:91ff:fea5:f7e2, 2400:8904::f03c:91ff:fea5:2205, 2400:8904::f03c:91ff:fea5:9207"}},{"id":"ca-central","label":"Toronto, CA","country":"ca","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"172.105.0.5, 172.105.3.5, 172.105.4.5, 172.105.5.5, 172.105.6.5, 172.105.7.5, 172.105.8.5, 172.105.9.5, 172.105.10.5, 172.105.11.5","ipv6":"2600:3c04::f03c:91ff:fea9:f63, 2600:3c04::f03c:91ff:fea9:f6d, 2600:3c04::f03c:91ff:fea9:f80, 2600:3c04::f03c:91ff:fea9:f0f, 2600:3c04::f03c:91ff:fea9:f99, 2600:3c04::f03c:91ff:fea9:fbd, 2600:3c04::f03c:91ff:fea9:fdd, 2600:3c04::f03c:91ff:fea9:fe2, 2600:3c04::f03c:91ff:fea9:f68, 2600:3c04::f03c:91ff:fea9:f4a"}},{"id":"ap-southeast","label":"Sydney, AU","country":"au","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"172.105.166.5, 172.105.169.5, 172.105.168.5, 172.105.172.5, 172.105.162.5, 172.105.170.5, 172.105.167.5, 172.105.171.5, 172.105.181.5, 172.105.161.5","ipv6":"2400:8907::f03c:92ff:fe6e:ec8, 2400:8907::f03c:92ff:fe6e:98e4, 2400:8907::f03c:92ff:fe6e:1c58, 2400:8907::f03c:92ff:fe6e:c299, 2400:8907::f03c:92ff:fe6e:c210, 2400:8907::f03c:92ff:fe6e:c219, 2400:8907::f03c:92ff:fe6e:1c5c, 2400:8907::f03c:92ff:fe6e:c24e, 2400:8907::f03c:92ff:fe6e:e6b, 2400:8907::f03c:92ff:fe6e:e3d"}},{"id":"us-iad","label":"Washington, DC","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Managed Databases","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"139.144.192.62, 139.144.192.60, 139.144.192.61, 139.144.192.53, 139.144.192.54, 139.144.192.67, 139.144.192.69, 139.144.192.66, 139.144.192.52, 139.144.192.68","ipv6":"2600:3c05::f03c:93ff:feb6:43b6, 2600:3c05::f03c:93ff:feb6:4365, 2600:3c05::f03c:93ff:feb6:43c2, 2600:3c05::f03c:93ff:feb6:e441, 2600:3c05::f03c:93ff:feb6:94ef, 2600:3c05::f03c:93ff:feb6:94ba, 2600:3c05::f03c:93ff:feb6:94a8, 2600:3c05::f03c:93ff:feb6:9413, 2600:3c05::f03c:93ff:feb6:9443, 2600:3c05::f03c:93ff:feb6:94e0"}},{"id":"us-ord","label":"Chicago, IL","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Managed Databases","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.0.17, 172.232.0.16, 172.232.0.21, 172.232.0.13, 172.232.0.22, 172.232.0.9, 172.232.0.19, 172.232.0.20, 172.232.0.15, 172.232.0.18","ipv6":"2600:3c06::f03c:93ff:fed0:e5fc, 2600:3c06::f03c:93ff:fed0:e54b, 2600:3c06::f03c:93ff:fed0:e572, 2600:3c06::f03c:93ff:fed0:e530, 2600:3c06::f03c:93ff:fed0:e597, 2600:3c06::f03c:93ff:fed0:e511, 2600:3c06::f03c:93ff:fed0:e5f2, 2600:3c06::f03c:93ff:fed0:e5bf, 2600:3c06::f03c:93ff:fed0:e529, 2600:3c06::f03c:93ff:fed0:e5a3"}},{"id":"fr-par","label":"Paris, FR","country":"fr","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Managed Databases","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.32.21, 172.232.32.23, 172.232.32.17, 172.232.32.18, 172.232.32.16, 172.232.32.22, 172.232.32.20, 172.232.32.14, 172.232.32.11, 172.232.32.12","ipv6":"2600:3c07::f03c:93ff:fef2:2e63, 2600:3c07::f03c:93ff:fef2:2ec7, 2600:3c07::f03c:93ff:fef2:0dee, 2600:3c07::f03c:93ff:fef2:0d25, 2600:3c07::f03c:93ff:fef2:0de0, 2600:3c07::f03c:93ff:fef2:2e29, 2600:3c07::f03c:93ff:fef2:0dda, 2600:3c07::f03c:93ff:fef2:0d82, 2600:3c07::f03c:93ff:fef2:b3ac, 2600:3c07::f03c:93ff:fef2:b3a8"}},{"id":"us-sea","label":"Seattle, WA","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.160.19, 172.232.160.21, 172.232.160.17, 172.232.160.15, 172.232.160.18, 172.232.160.8, 172.232.160.12, 172.232.160.11, 172.232.160.14, 172.232.160.16","ipv6":"2600:3c0a::f03c:93ff:fe54:c6da, 2600:3c0a::f03c:93ff:fe54:c691, 2600:3c0a::f03c:93ff:fe54:c68d, 2600:3c0a::f03c:93ff:fe54:c61e, 2600:3c0a::f03c:93ff:fe54:c653, 2600:3c0a::f03c:93ff:fe54:c64c, 2600:3c0a::f03c:93ff:fe54:c68a, 2600:3c0a::f03c:93ff:fe54:c697, 2600:3c0a::f03c:93ff:fe54:c60f, 2600:3c0a::f03c:93ff:fe54:c6a0"}},{"id":"br-gru","label":"Sao Paulo, BR","country":"br","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.233.0.4, 172.233.0.9, 172.233.0.7, 172.233.0.12, 172.233.0.5, 172.233.0.13, 172.233.0.10, 172.233.0.6, 172.233.0.8, 172.233.0.11","ipv6":"2600:3c0d::f03c:93ff:fe3d:51cb, 2600:3c0d::f03c:93ff:fe3d:51a7, 2600:3c0d::f03c:93ff:fe3d:51a9, 2600:3c0d::f03c:93ff:fe3d:5119, 2600:3c0d::f03c:93ff:fe3d:51fe, 2600:3c0d::f03c:93ff:fe3d:517c, 2600:3c0d::f03c:93ff:fe3d:5144, 2600:3c0d::f03c:93ff:fe3d:5170, 2600:3c0d::f03c:93ff:fe3d:51cc, 2600:3c0d::f03c:93ff:fe3d:516c"}},{"id":"nl-ams","label":"Amsterdam, NL","country":"nl","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.233.33.36, 172.233.33.38, 172.233.33.35, 172.233.33.39, 172.233.33.34, 172.233.33.33, 172.233.33.31, 172.233.33.30, 172.233.33.37, 172.233.33.32","ipv6":"2600:3c0e::f03c:93ff:fe9d:2d10, 2600:3c0e::f03c:93ff:fe9d:2d89, 2600:3c0e::f03c:93ff:fe9d:2d79, 2600:3c0e::f03c:93ff:fe9d:2d96, 2600:3c0e::f03c:93ff:fe9d:2da5, 2600:3c0e::f03c:93ff:fe9d:2d34, 2600:3c0e::f03c:93ff:fe9d:2d68, 2600:3c0e::f03c:93ff:fe9d:2d17, 2600:3c0e::f03c:93ff:fe9d:2d45, 2600:3c0e::f03c:93ff:fe9d:2d5c"}},{"id":"se-sto","label":"Stockholm, SE","country":"se","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.128.24, 172.232.128.26, 172.232.128.20, 172.232.128.22, 172.232.128.25, 172.232.128.19, 172.232.128.23, 172.232.128.18, 172.232.128.21, 172.232.128.27","ipv6":"2600:3c09::f03c:93ff:fea9:4dbe, 2600:3c09::f03c:93ff:fea9:4d63, 2600:3c09::f03c:93ff:fea9:4dce, 2600:3c09::f03c:93ff:fea9:4dbb, 2600:3c09::f03c:93ff:fea9:4d99, 2600:3c09::f03c:93ff:fea9:4d26, 2600:3c09::f03c:93ff:fea9:4de0, 2600:3c09::f03c:93ff:fea9:4d69, 2600:3c09::f03c:93ff:fea9:4dbf, 2600:3c09::f03c:93ff:fea9:4da6"}},{"id":"in-maa","label":"Chennai, IN","country":"in","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.96.17, 172.232.96.26, 172.232.96.19, 172.232.96.20, 172.232.96.25, 172.232.96.21, 172.232.96.18, 172.232.96.22, 172.232.96.23, 172.232.96.24","ipv6":"2600:3c08::f03c:93ff:fe7c:1135, 2600:3c08::f03c:93ff:fe7c:11f8, 2600:3c08::f03c:93ff:fe7c:11d2, 2600:3c08::f03c:93ff:fe7c:11a7, 2600:3c08::f03c:93ff:fe7c:11ad, 2600:3c08::f03c:93ff:fe7c:110a, 2600:3c08::f03c:93ff:fe7c:11f9, 2600:3c08::f03c:93ff:fe7c:1137, 2600:3c08::f03c:93ff:fe7c:11db, 2600:3c08::f03c:93ff:fe7c:1164"}},{"id":"jp-osa","label":"Osaka, JP","country":"jp","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.233.64.44, 172.233.64.43, 172.233.64.37, 172.233.64.40, 172.233.64.46, 172.233.64.41, 172.233.64.39, 172.233.64.42, 172.233.64.45, 172.233.64.38","ipv6":"2400:8905::f03c:93ff:fe9d:b085, 2400:8905::f03c:93ff:fe9d:b012, 2400:8905::f03c:93ff:fe9d:b09b, 2400:8905::f03c:93ff:fe9d:b0d8, 2400:8905::f03c:93ff:fe9d:259f, 2400:8905::f03c:93ff:fe9d:b006, 2400:8905::f03c:93ff:fe9d:b084, 2400:8905::f03c:93ff:fe9d:b0ce, 2400:8905::f03c:93ff:fe9d:25ea, 2400:8905::f03c:93ff:fe9d:b086"}},{"id":"it-mil","label":"Milan, IT","country":"it","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.192.19, 172.232.192.18, 172.232.192.16, 172.232.192.20, 172.232.192.24, 172.232.192.21, 172.232.192.22, 172.232.192.17, 172.232.192.15, 172.232.192.23","ipv6":"2600:3c0b::f03c:93ff:feba:d513, 2600:3c0b::f03c:93ff:feba:d5c3, 2600:3c0b::f03c:93ff:feba:d597, 2600:3c0b::f03c:93ff:feba:d5fb, 2600:3c0b::f03c:93ff:feba:d51f, 2600:3c0b::f03c:93ff:feba:d58e, 2600:3c0b::f03c:93ff:feba:d5d5, 2600:3c0b::f03c:93ff:feba:d534, 2600:3c0b::f03c:93ff:feba:d57c, 2600:3c0b::f03c:93ff:feba:d529"}},{"id":"us-mia","label":"Miami, FL","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.233.160.34, 172.233.160.27, 172.233.160.30, 172.233.160.29, 172.233.160.32, 172.233.160.28, 172.233.160.33, 172.233.160.26, 172.233.160.25, 172.233.160.31","ipv6":"2a01:7e04::f03c:93ff:fead:d31f, 2a01:7e04::f03c:93ff:fead:d37f, 2a01:7e04::f03c:93ff:fead:d30c, 2a01:7e04::f03c:93ff:fead:d318, 2a01:7e04::f03c:93ff:fead:d316, 2a01:7e04::f03c:93ff:fead:d339, 2a01:7e04::f03c:93ff:fead:d367, 2a01:7e04::f03c:93ff:fead:d395, 2a01:7e04::f03c:93ff:fead:d3d0, 2a01:7e04::f03c:93ff:fead:d38e"}},{"id":"id-cgk","label":"Jakarta, ID","country":"id","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.232.224.23, 172.232.224.32, 172.232.224.26, 172.232.224.27, 172.232.224.21, 172.232.224.24, 172.232.224.22, 172.232.224.20, 172.232.224.31, 172.232.224.28","ipv6":"2600:3c0c::f03c:93ff:feed:a90b, 2600:3c0c::f03c:93ff:feed:a9a5, 2600:3c0c::f03c:93ff:feed:a935, 2600:3c0c::f03c:93ff:feed:a930, 2600:3c0c::f03c:93ff:feed:a95c, 2600:3c0c::f03c:93ff:feed:a9ad, 2600:3c0c::f03c:93ff:feed:a9f2, 2600:3c0c::f03c:93ff:feed:a9ff, 2600:3c0c::f03c:93ff:feed:a9c8, 2600:3c0c::f03c:93ff:feed:a96b"}},{"id":"us-lax","label":"Los Angeles, CA","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","Kubernetes","Cloud Firewall","Vlans","Metadata","Premium Plans"],"status":"ok","resolvers":{"ipv4":"172.233.128.45, 172.233.128.38, 172.233.128.53, 172.233.128.37, 172.233.128.34, 172.233.128.36, 172.233.128.33, 172.233.128.39, 172.233.128.43, 172.233.128.44","ipv6":"2a01:7e03::f03c:93ff:feb1:b789, 2a01:7e03::f03c:93ff:feb1:b717, 2a01:7e03::f03c:93ff:feb1:b707, 2a01:7e03::f03c:93ff:feb1:b7ab, 2a01:7e03::f03c:93ff:feb1:b7e2, 2a01:7e03::f03c:93ff:feb1:b709, 2a01:7e03::f03c:93ff:feb1:b7a6, 2a01:7e03::f03c:93ff:feb1:b750, 2a01:7e03::f03c:93ff:feb1:b76e, 2a01:7e03::f03c:93ff:feb1:b7a2"}},{"id":"us-central","label":"Dallas, TX","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"72.14.179.5, 72.14.188.5, 173.255.199.5, 66.228.53.5, 96.126.122.5, 96.126.124.5, 96.126.127.5, 198.58.107.5, 198.58.111.5, 23.239.24.5","ipv6":"2600:3c00::2, 2600:3c00::9, 2600:3c00::7, 2600:3c00::5, 2600:3c00::3, 2600:3c00::8, 2600:3c00::6, 2600:3c00::4, 2600:3c00::c, 2600:3c00::b"}},{"id":"us-west","label":"Fremont, CA","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"173.230.145.5, 173.230.147.5, 173.230.155.5, 173.255.212.5, 173.255.219.5, 173.255.241.5, 173.255.243.5, 173.255.244.5, 74.207.241.5, 74.207.242.5","ipv6":"2600:3c01::2, 2600:3c01::9, 2600:3c01::5, 2600:3c01::7, 2600:3c01::3, 2600:3c01::8, 2600:3c01::4, 2600:3c01::b, 2600:3c01::c, 2600:3c01::6"}},{"id":"us-southeast","label":"Atlanta, GA","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"74.207.231.5, 173.230.128.5, 173.230.129.5, 173.230.136.5, 173.230.140.5, 66.228.59.5, 66.228.62.5, 50.116.35.5, 50.116.41.5, 23.239.18.5","ipv6":"2600:3c02::3, 2600:3c02::5, 2600:3c02::4, 2600:3c02::6, 2600:3c02::c, 2600:3c02::7, 2600:3c02::2, 2600:3c02::9, 2600:3c02::8, 2600:3c02::b"}},{"id":"us-east","label":"Newark, NJ","country":"us","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Bare Metal","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"66.228.42.5, 96.126.106.5, 50.116.53.5, 50.116.58.5, 50.116.61.5, 50.116.62.5, 66.175.211.5, 97.107.133.4, 207.192.69.4, 207.192.69.5","ipv6":"2600:3c03::7, 2600:3c03::4, 2600:3c03::9, 2600:3c03::6, 2600:3c03::3, 2600:3c03::c, 2600:3c03::5, 2600:3c03::b, 2600:3c03::2, 2600:3c03::8"}},{"id":"eu-west","label":"London, UK","country":"gb","capabilities":["Linodes","NodeBalancers","Block Storage","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"178.79.182.5, 176.58.107.5, 176.58.116.5, 176.58.121.5, 151.236.220.5, 212.71.252.5, 212.71.253.5, 109.74.192.20, 109.74.193.20, 109.74.194.20","ipv6":"2a01:7e00::9, 2a01:7e00::3, 2a01:7e00::c, 2a01:7e00::5, 2a01:7e00::6, 2a01:7e00::8, 2a01:7e00::b, 2a01:7e00::4, 2a01:7e00::7, 2a01:7e00::2"}},{"id":"ap-south","label":"Singapore, SG","country":"sg","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"139.162.11.5, 139.162.13.5, 139.162.14.5, 139.162.15.5, 139.162.16.5, 139.162.21.5, 139.162.27.5, 103.3.60.18, 103.3.60.19, 103.3.60.20","ipv6":"2400:8901::5, 2400:8901::4, 2400:8901::b, 2400:8901::3, 2400:8901::9, 2400:8901::2, 2400:8901::8, 2400:8901::7, 2400:8901::c, 2400:8901::6"}},{"id":"eu-central","label":"Frankfurt, DE","country":"de","capabilities":["Linodes","NodeBalancers","Block Storage","Object Storage","GPU Linodes","Kubernetes","Cloud Firewall","Vlans","Block Storage Migrations","Managed Databases"],"status":"ok","resolvers":{"ipv4":"139.162.130.5, 139.162.131.5, 139.162.132.5, 139.162.133.5, 139.162.134.5, 139.162.135.5, 139.162.136.5, 139.162.137.5, 139.162.138.5, 139.162.139.5","ipv6":"2a01:7e01::5, 2a01:7e01::9, 2a01:7e01::7, 2a01:7e01::c, 2a01:7e01::2, 2a01:7e01::4, 2a01:7e01::3, 2a01:7e01::6, 2a01:7e01::b, 2a01:7e01::8"}}],"page":1,"pages":1,"results":23} \ No newline at end of file diff --git a/packages/manager/src/cachedData/typesLegacy.json b/packages/manager/src/cachedData/typesLegacy.json index 5b57f35e381..2afeb52418e 100644 --- a/packages/manager/src/cachedData/typesLegacy.json +++ b/packages/manager/src/cachedData/typesLegacy.json @@ -1 +1 @@ -{"data":[{"id":"standard-1","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"addons":{"backups":{"price":{"hourly":0.008,"monthly":5}}},"memory":512,"disk":24576,"transfer":2000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-2"},{"id":"standard-2","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.054,"monthly":36},"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5}}},"memory":768,"disk":36864,"transfer":3000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-3-s"},{"id":"standard-3","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"addons":{"backups":{"price":{"hourly":0.015,"monthly":10}}},"memory":1024,"disk":49152,"transfer":4000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4"},{"id":"standard-4","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"addons":{"backups":{"price":{"hourly":0.024,"monthly":15}}},"memory":1536,"disk":73728,"transfer":6000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4-s"},{"id":"standard-5","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"addons":{"backups":{"price":{"hourly":0.03,"monthly":20}}},"memory":2048,"disk":98304,"transfer":8000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-6"},{"id":"standard-6","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"addons":{"backups":{"price":{"hourly":0.06,"monthly":40}}},"memory":4096,"disk":196608,"transfer":16000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-8"},{"id":"standard-7","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"addons":{"backups":{"price":{"hourly":0.12,"monthly":80}}},"memory":8192,"disk":393216,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-16"},{"id":"standard-8","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"addons":{"backups":{"price":{"hourly":0.18,"monthly":120}}},"memory":12288,"disk":589824,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20"},{"id":"standard-9","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"addons":{"backups":{"price":{"hourly":0.24,"monthly":160}}},"memory":16384,"disk":786432,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-24"},{"id":"standard-10","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"addons":{"backups":{"price":{"hourly":0.3,"monthly":200}}},"memory":20480,"disk":983040,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20-s"},{"id":"standard-46","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"addons":{"backups":{"price":{"hourly":0.008,"monthly":5}}},"memory":1024,"disk":24576,"transfer":2000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-2"},{"id":"standard-47","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5}}},"memory":1536,"disk":36864,"transfer":3000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-3-s"},{"id":"standard-48","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"addons":{"backups":{"price":{"hourly":0.015,"monthly":10}}},"memory":2048,"disk":49152,"transfer":4000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4"},{"id":"standard-49","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"addons":{"backups":{"price":{"hourly":0.024,"monthly":15}}},"memory":3072,"disk":73728,"transfer":6000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4-s"},{"id":"standard-50","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"addons":{"backups":{"price":{"hourly":0.03,"monthly":20}}},"memory":4096,"disk":98304,"transfer":8000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-6"},{"id":"standard-51","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"addons":{"backups":{"price":{"hourly":0.06,"monthly":40}}},"memory":8192,"disk":196608,"transfer":16000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-8"},{"id":"standard-52","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.6,"monthly":384},"addons":{"backups":{"price":{"hourly":0.12,"monthly":80}}},"memory":16384,"disk":393216,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-16"},{"id":"standard-53","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"addons":{"backups":{"price":{"hourly":0.18,"monthly":120}}},"memory":24576,"disk":589824,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20"},{"id":"standard-54","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"addons":{"backups":{"price":{"hourly":0.24,"monthly":160}}},"memory":32768,"disk":786432,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-24"},{"id":"standard-55","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"addons":{"backups":{"price":{"hourly":0.3,"monthly":200}}},"memory":40960,"disk":983040,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20-s"},{"id":"standard-92","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"addons":{"backups":{"price":{"hourly":0.008,"monthly":5}}},"memory":1024,"disk":49152,"transfer":2000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-2"},{"id":"standard-93","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5}}},"memory":1536,"disk":73728,"transfer":3000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-3-s"},{"id":"standard-94","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"addons":{"backups":{"price":{"hourly":0.015,"monthly":10}}},"memory":2048,"disk":98304,"transfer":4000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4"},{"id":"standard-95","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"addons":{"backups":{"price":{"hourly":0.024,"monthly":15}}},"memory":3072,"disk":147456,"transfer":6000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4-s"},{"id":"standard-96","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"addons":{"backups":{"price":{"hourly":0.03,"monthly":20}}},"memory":4096,"disk":196608,"transfer":8000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-6"},{"id":"standard-97","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"addons":{"backups":{"price":{"hourly":0.06,"monthly":40}}},"memory":8192,"disk":393216,"transfer":16000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-8"},{"id":"standard-98","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"addons":{"backups":{"price":{"hourly":0.12,"monthly":80}}},"memory":16384,"disk":786432,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-16"},{"id":"standard-99","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"addons":{"backups":{"price":{"hourly":0.18,"monthly":120}}},"memory":24576,"disk":1179648,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20"},{"id":"standard-100","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"addons":{"backups":{"price":{"hourly":0.24,"monthly":160}}},"memory":32768,"disk":1572864,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-24"},{"id":"standard-101","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"addons":{"backups":{"price":{"hourly":0.3,"monthly":200}}},"memory":40960,"disk":1966080,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20-s"},{"id":"g4-standard-1","label":"Linode 2GB (pending upgrade)","price":{"hourly":0.018,"monthly":12},"addons":{"backups":{"price":{"hourly":0.004,"monthly":2.5}}},"memory":1024,"disk":24576,"transfer":2000,"vcpus":1,"gpus":0,"network_out":125,"class":"standard","successor":"g6-standard-1"},{"id":"g4-standard-2","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"addons":{"backups":{"price":{"hourly":0.008,"monthly":5}}},"memory":2048,"disk":49152,"transfer":3000,"vcpus":2,"gpus":0,"network_out":250,"class":"standard","successor":"g6-standard-2"},{"id":"g4-standard-3-2","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5}}},"memory":3072,"disk":73728,"transfer":3000,"vcpus":3,"gpus":0,"network_out":375,"class":"standard","successor":"g6-standard-3-s"},{"id":"g4-standard-4","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"addons":{"backups":{"price":{"hourly":0.015,"monthly":10}}},"memory":4096,"disk":98304,"transfer":4000,"vcpus":4,"gpus":0,"network_out":500,"class":"standard","successor":"g6-standard-4"},{"id":"g4-standard-4-s","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"addons":{"backups":{"price":{"hourly":0.024,"monthly":15}}},"memory":6144,"disk":147456,"transfer":6000,"vcpus":4,"gpus":0,"network_out":750,"class":"standard","successor":"g6-standard-4-s"},{"id":"g4-standard-6","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"addons":{"backups":{"price":{"hourly":0.03,"monthly":20}}},"memory":8192,"disk":196608,"transfer":8000,"vcpus":6,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-6"},{"id":"g4-standard-8","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"addons":{"backups":{"price":{"hourly":0.06,"monthly":40}}},"memory":16384,"disk":393216,"transfer":16000,"vcpus":8,"gpus":0,"network_out":2000,"class":"standard","successor":"g6-standard-8"},{"id":"g4-standard-12","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"addons":{"backups":{"price":{"hourly":0.12,"monthly":80}}},"memory":32768,"disk":786432,"transfer":20000,"vcpus":12,"gpus":0,"network_out":4000,"class":"standard","successor":"g6-standard-16"},{"id":"g4-standard-16","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"addons":{"backups":{"price":{"hourly":0.18,"monthly":120}}},"memory":49152,"disk":1179648,"transfer":20000,"vcpus":16,"gpus":0,"network_out":6000,"class":"standard","successor":"g6-standard-20"},{"id":"g4-standard-20","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"addons":{"backups":{"price":{"hourly":0.24,"monthly":160}}},"memory":65536,"disk":1572864,"transfer":20000,"vcpus":20,"gpus":0,"network_out":8000,"class":"standard","successor":"g6-standard-24"},{"id":"g4-standard-20-s1","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"addons":{"backups":{"price":{"hourly":0.3,"monthly":200}}},"memory":81920,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-20-s"},{"id":"g4-standard-20-s2","label":"Linode 192GB (pending upgrade)","price":{"hourly":1.728,"monthly":1152},"addons":{"backups":{"price":{"hourly":0.3,"monthly":200}}},"memory":98304,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-32"},{"id":"g5-nanode-1","label":"Nanode 1GB (pending upgrade)","price":{"hourly":0.0075,"monthly":5},"addons":{"backups":{"price":{"hourly":0.003,"monthly":2}}},"memory":1024,"disk":20480,"transfer":1000,"vcpus":1,"gpus":0,"network_out":1000,"class":"nanode","successor":"g6-nanode-1"},{"id":"g5-standard-1","label":"Linode 2GB (pending upgrade)","price":{"hourly":0.018,"monthly":12},"addons":{"backups":{"price":{"hourly":0.004,"monthly":2.5}}},"memory":2048,"disk":30720,"transfer":2000,"vcpus":1,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-1"},{"id":"g5-standard-2","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"addons":{"backups":{"price":{"hourly":0.008,"monthly":5}}},"memory":4096,"disk":49152,"transfer":3000,"vcpus":2,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-2"},{"id":"g5-standard-3-s","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5}}},"memory":6144,"disk":73728,"transfer":3000,"vcpus":3,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-3-s"},{"id":"g5-standard-4","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"addons":{"backups":{"price":{"hourly":0.015,"monthly":10}}},"memory":8192,"disk":98304,"transfer":4000,"vcpus":4,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-4"},{"id":"g5-standard-4-s","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"addons":{"backups":{"price":{"hourly":0.024,"monthly":15}}},"memory":10240,"disk":147456,"transfer":6000,"vcpus":4,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-4-s"},{"id":"g5-standard-6","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"addons":{"backups":{"price":{"hourly":0.03,"monthly":20}}},"memory":12288,"disk":196608,"transfer":8000,"vcpus":6,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-6"},{"id":"g5-standard-8","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"addons":{"backups":{"price":{"hourly":0.06,"monthly":40}}},"memory":24576,"disk":393216,"transfer":16000,"vcpus":8,"gpus":0,"network_out":2000,"class":"standard","successor":"g6-standard-8"},{"id":"g5-standard-12","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"addons":{"backups":{"price":{"hourly":0.12,"monthly":80}}},"memory":49152,"disk":786432,"transfer":20000,"vcpus":12,"gpus":0,"network_out":4000,"class":"standard","successor":"g6-standard-16"},{"id":"g5-standard-16","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"addons":{"backups":{"price":{"hourly":0.18,"monthly":120}}},"memory":65536,"disk":1179648,"transfer":20000,"vcpus":16,"gpus":0,"network_out":6000,"class":"standard","successor":"g6-standard-20"},{"id":"g5-standard-20","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"addons":{"backups":{"price":{"hourly":0.24,"monthly":160}}},"memory":81920,"disk":1572864,"transfer":20000,"vcpus":20,"gpus":0,"network_out":8000,"class":"standard","successor":"g6-standard-24"},{"id":"g5-standard-20-s1","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"addons":{"backups":{"price":{"hourly":0.3,"monthly":200}}},"memory":102400,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-20-s"},{"id":"g5-standard-20-s2","label":"Linode 192GB (pending upgrade)","price":{"hourly":1.728,"monthly":1152},"addons":{"backups":{"price":{"hourly":0.3,"monthly":200}}},"memory":122880,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-32"},{"id":"g5-highmem-1","label":"Linode 24GB (pending upgrade)","price":{"hourly":0.09,"monthly":60},"addons":{"backups":{"price":{"hourly":0.008,"monthly":5}}},"memory":16384,"disk":20480,"transfer":5000,"vcpus":1,"gpus":0,"network_out":1000,"class":"highmem","successor":"g6-highmem-1"},{"id":"g5-highmem-2","label":"Linode 48GB (pending upgrade)","price":{"hourly":0.18,"monthly":120},"addons":{"backups":{"price":{"hourly":0.015,"monthly":10}}},"memory":32768,"disk":40960,"transfer":6000,"vcpus":2,"gpus":0,"network_out":1500,"class":"highmem","successor":"g6-highmem-2"},{"id":"g5-highmem-4","label":"Linode 90GB (pending upgrade)","price":{"hourly":0.36,"monthly":240},"addons":{"backups":{"price":{"hourly":0.03,"monthly":20}}},"memory":61440,"disk":92160,"transfer":7000,"vcpus":4,"gpus":0,"network_out":3000,"class":"highmem","successor":"g6-highmem-4"},{"id":"g5-highmem-8","label":"Linode 150GB (pending upgrade)","price":{"hourly":0.72,"monthly":480},"addons":{"backups":{"price":{"hourly":0.06,"monthly":40}}},"memory":102400,"disk":204800,"transfer":8000,"vcpus":8,"gpus":0,"network_out":6000,"class":"highmem","successor":"g6-highmem-8"},{"id":"g5-highmem-16","label":"Linode 300GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"addons":{"backups":{"price":{"hourly":0.09,"monthly":60}}},"memory":204800,"disk":348160,"transfer":9000,"vcpus":16,"gpus":0,"network_out":10000,"class":"highmem","successor":"g6-highmem-16"},{"id":"g6-highmem-1","label":"Linode 24GB (pending upgrade)","price":{"hourly":0.09,"monthly":60},"addons":{"backups":{"price":{"hourly":0.0075,"monthly":5}}},"memory":24576,"disk":20480,"transfer":5000,"vcpus":1,"gpus":0,"network_out":5000,"class":"highmem","successor":"g7-highmem-1"},{"id":"g6-highmem-2","label":"Linode 48GB (pending upgrade)","price":{"hourly":0.18,"monthly":120},"addons":{"backups":{"price":{"hourly":0.015,"monthly":10}}},"memory":49152,"disk":40960,"transfer":6000,"vcpus":2,"gpus":0,"network_out":6000,"class":"highmem","successor":"g7-highmem-2"},{"id":"g6-highmem-4","label":"Linode 90GB (pending upgrade)","price":{"hourly":0.36,"monthly":240},"addons":{"backups":{"price":{"hourly":0.03,"monthly":20}}},"memory":92160,"disk":92160,"transfer":7000,"vcpus":4,"gpus":0,"network_out":7000,"class":"highmem","successor":"g7-highmem-4"},{"id":"g6-highmem-8","label":"Linode 150GB (pending upgrade)","price":{"hourly":0.72,"monthly":480},"addons":{"backups":{"price":{"hourly":0.06,"monthly":40}}},"memory":153600,"disk":204800,"transfer":8000,"vcpus":8,"gpus":0,"network_out":8000,"class":"highmem","successor":"g7-highmem-8"},{"id":"g6-highmem-16","label":"Linode 300GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"addons":{"backups":{"price":{"hourly":0.12,"monthly":80}}},"memory":307200,"disk":348160,"transfer":9000,"vcpus":16,"gpus":0,"network_out":9000,"class":"highmem","successor":"g7-highmem-16"}],"page":1,"pages":1,"results":65} \ No newline at end of file +{"data":[{"id":"standard-1","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"region_prices":[{"id":"id-cgk","hourly":0.043,"monthly":29},{"id":"br-gru","hourly":0.05,"monthly":34}],"addons":{"backups":{"price":{"hourly":0.008,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.01,"monthly":7}]}},"memory":512,"disk":24576,"transfer":2000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-2"},{"id":"standard-2","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.054,"monthly":36},"region_prices":[{"id":"id-cgk","hourly":0.065,"monthly":43},{"id":"br-gru","hourly":0.076,"monthly":50}],"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5},"region_prices":[{"id":"id-cgk","hourly":0.013,"monthly":9},{"id":"br-gru","hourly":0.016,"monthly":11}]}},"memory":768,"disk":36864,"transfer":3000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-3-s"},{"id":"standard-3","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"region_prices":[{"id":"id-cgk","hourly":0.086,"monthly":58},{"id":"br-gru","hourly":0.101,"monthly":67}],"addons":{"backups":{"price":{"hourly":0.015,"monthly":10},"region_prices":[{"id":"id-cgk","hourly":0.018,"monthly":12},{"id":"br-gru","hourly":0.021,"monthly":14}]}},"memory":1024,"disk":49152,"transfer":4000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4"},{"id":"standard-4","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"region_prices":[{"id":"id-cgk","hourly":0.13,"monthly":86},{"id":"br-gru","hourly":0.151,"monthly":101}],"addons":{"backups":{"price":{"hourly":0.024,"monthly":15},"region_prices":[{"id":"id-cgk","hourly":0.027,"monthly":18},{"id":"br-gru","hourly":0.031,"monthly":21}]}},"memory":1536,"disk":73728,"transfer":6000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4-s"},{"id":"standard-5","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"region_prices":[{"id":"id-cgk","hourly":0.173,"monthly":115},{"id":"br-gru","hourly":0.202,"monthly":134}],"addons":{"backups":{"price":{"hourly":0.03,"monthly":20},"region_prices":[{"id":"id-cgk","hourly":0.036,"monthly":24},{"id":"br-gru","hourly":0.042,"monthly":28}]}},"memory":2048,"disk":98304,"transfer":8000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-6"},{"id":"standard-6","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"region_prices":[{"id":"id-cgk","hourly":0.346,"monthly":230},{"id":"br-gru","hourly":0.403,"monthly":269}],"addons":{"backups":{"price":{"hourly":0.06,"monthly":40},"region_prices":[{"id":"id-cgk","hourly":0.072,"monthly":48},{"id":"br-gru","hourly":0.084,"monthly":56}]}},"memory":4096,"disk":196608,"transfer":16000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-8"},{"id":"standard-7","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"region_prices":[{"id":"id-cgk","hourly":0.691,"monthly":461},{"id":"br-gru","hourly":0.806,"monthly":538}],"addons":{"backups":{"price":{"hourly":0.12,"monthly":80},"region_prices":[{"id":"id-cgk","hourly":0.144,"monthly":96},{"id":"br-gru","hourly":0.168,"monthly":112}]}},"memory":8192,"disk":393216,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-16"},{"id":"standard-8","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"region_prices":[{"id":"id-cgk","hourly":1.037,"monthly":691},{"id":"br-gru","hourly":1.21,"monthly":806}],"addons":{"backups":{"price":{"hourly":0.18,"monthly":120},"region_prices":[{"id":"id-cgk","hourly":0.216,"monthly":144},{"id":"br-gru","hourly":0.252,"monthly":168}]}},"memory":12288,"disk":589824,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20"},{"id":"standard-9","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"region_prices":[{"id":"id-cgk","hourly":1.382,"monthly":922},{"id":"br-gru","hourly":1.613,"monthly":1075}],"addons":{"backups":{"price":{"hourly":0.24,"monthly":160},"region_prices":[{"id":"id-cgk","hourly":0.288,"monthly":192},{"id":"br-gru","hourly":0.336,"monthly":224}]}},"memory":16384,"disk":786432,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-24"},{"id":"standard-10","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"region_prices":[{"id":"id-cgk","hourly":1.728,"monthly":1152},{"id":"br-gru","hourly":2.02,"monthly":1344}],"addons":{"backups":{"price":{"hourly":0.3,"monthly":200},"region_prices":[{"id":"id-cgk","hourly":0.36,"monthly":240},{"id":"br-gru","hourly":0.42,"monthly":280}]}},"memory":20480,"disk":983040,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20-s"},{"id":"standard-46","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"region_prices":[{"id":"id-cgk","hourly":0.043,"monthly":28.8},{"id":"br-gru","hourly":0.05,"monthly":34}],"addons":{"backups":{"price":{"hourly":0.008,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.01,"monthly":7}]}},"memory":1024,"disk":24576,"transfer":2000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-2"},{"id":"standard-47","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"region_prices":[{"id":"id-cgk","hourly":0.065,"monthly":43.2},{"id":"br-gru","hourly":0.076,"monthly":50}],"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5},"region_prices":[{"id":"id-cgk","hourly":0.013,"monthly":9},{"id":"br-gru","hourly":0.016,"monthly":10.5}]}},"memory":1536,"disk":36864,"transfer":3000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-3-s"},{"id":"standard-48","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"region_prices":[{"id":"id-cgk","hourly":0.086,"monthly":57.6},{"id":"br-gru","hourly":0.101,"monthly":67}],"addons":{"backups":{"price":{"hourly":0.015,"monthly":10},"region_prices":[{"id":"id-cgk","hourly":0.018,"monthly":12},{"id":"br-gru","hourly":0.021,"monthly":14}]}},"memory":2048,"disk":49152,"transfer":4000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4"},{"id":"standard-49","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"region_prices":[{"id":"id-cgk","hourly":0.13,"monthly":86.4},{"id":"br-gru","hourly":0.151,"monthly":101}],"addons":{"backups":{"price":{"hourly":0.024,"monthly":15},"region_prices":[{"id":"id-cgk","hourly":0.027,"monthly":18},{"id":"br-gru","hourly":0.031,"monthly":21}]}},"memory":3072,"disk":73728,"transfer":6000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4-s"},{"id":"standard-50","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"region_prices":[{"id":"id-cgk","hourly":0.173,"monthly":115.2},{"id":"br-gru","hourly":0.202,"monthly":134}],"addons":{"backups":{"price":{"hourly":0.03,"monthly":20},"region_prices":[{"id":"id-cgk","hourly":0.036,"monthly":24},{"id":"br-gru","hourly":0.042,"monthly":28}]}},"memory":4096,"disk":98304,"transfer":8000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-6"},{"id":"standard-51","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"region_prices":[{"id":"id-cgk","hourly":0.346,"monthly":230.4},{"id":"br-gru","hourly":0.403,"monthly":269}],"addons":{"backups":{"price":{"hourly":0.06,"monthly":40},"region_prices":[{"id":"id-cgk","hourly":0.072,"monthly":48},{"id":"br-gru","hourly":0.084,"monthly":56}]}},"memory":8192,"disk":196608,"transfer":16000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-8"},{"id":"standard-52","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.6,"monthly":384},"region_prices":[{"id":"id-cgk","hourly":0.691,"monthly":460.8},{"id":"br-gru","hourly":0.806,"monthly":538}],"addons":{"backups":{"price":{"hourly":0.12,"monthly":80},"region_prices":[{"id":"id-cgk","hourly":0.144,"monthly":96},{"id":"br-gru","hourly":0.168,"monthly":112}]}},"memory":16384,"disk":393216,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-16"},{"id":"standard-53","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"region_prices":[{"id":"id-cgk","hourly":1.037,"monthly":691.2},{"id":"br-gru","hourly":1.21,"monthly":806}],"addons":{"backups":{"price":{"hourly":0.18,"monthly":120},"region_prices":[{"id":"id-cgk","hourly":0.216,"monthly":144},{"id":"br-gru","hourly":0.252,"monthly":168}]}},"memory":24576,"disk":589824,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20"},{"id":"standard-54","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"region_prices":[{"id":"id-cgk","hourly":1.382,"monthly":921.6},{"id":"br-gru","hourly":1.613,"monthly":1075}],"addons":{"backups":{"price":{"hourly":0.24,"monthly":160},"region_prices":[{"id":"id-cgk","hourly":0.288,"monthly":192},{"id":"br-gru","hourly":0.336,"monthly":224}]}},"memory":32768,"disk":786432,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-24"},{"id":"standard-55","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"region_prices":[{"id":"id-cgk","hourly":1.728,"monthly":1152},{"id":"br-gru","hourly":2.016,"monthly":1344}],"addons":{"backups":{"price":{"hourly":0.3,"monthly":200},"region_prices":[{"id":"id-cgk","hourly":0.36,"monthly":240},{"id":"br-gru","hourly":0.42,"monthly":280}]}},"memory":40960,"disk":983040,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20-s"},{"id":"standard-92","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"region_prices":[{"id":"id-cgk","hourly":0.043,"monthly":28.8},{"id":"br-gru","hourly":0.05,"monthly":33.6}],"addons":{"backups":{"price":{"hourly":0.008,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.01,"monthly":7}]}},"memory":1024,"disk":49152,"transfer":2000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-2"},{"id":"standard-93","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"region_prices":[{"id":"id-cgk","hourly":0.065,"monthly":43.2},{"id":"br-gru","hourly":0.076,"monthly":50.4}],"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5},"region_prices":[{"id":"id-cgk","hourly":0.013,"monthly":9},{"id":"br-gru","hourly":0.016,"monthly":10.5}]}},"memory":1536,"disk":73728,"transfer":3000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-3-s"},{"id":"standard-94","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"region_prices":[{"id":"id-cgk","hourly":0.086,"monthly":57.6},{"id":"br-gru","hourly":0.101,"monthly":67.2}],"addons":{"backups":{"price":{"hourly":0.015,"monthly":10},"region_prices":[{"id":"id-cgk","hourly":0.018,"monthly":12},{"id":"br-gru","hourly":0.021,"monthly":14}]}},"memory":2048,"disk":98304,"transfer":4000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4"},{"id":"standard-95","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"region_prices":[{"id":"id-cgk","hourly":0.13,"monthly":86.4},{"id":"br-gru","hourly":0.151,"monthly":100.8}],"addons":{"backups":{"price":{"hourly":0.024,"monthly":15},"region_prices":[{"id":"id-cgk","hourly":0.027,"monthly":18},{"id":"br-gru","hourly":0.031,"monthly":21}]}},"memory":3072,"disk":147456,"transfer":6000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-4-s"},{"id":"standard-96","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"region_prices":[{"id":"id-cgk","hourly":0.173,"monthly":115.2},{"id":"br-gru","hourly":0.202,"monthly":134.4}],"addons":{"backups":{"price":{"hourly":0.03,"monthly":20},"region_prices":[{"id":"id-cgk","hourly":0.036,"monthly":24},{"id":"br-gru","hourly":0.042,"monthly":28}]}},"memory":4096,"disk":196608,"transfer":8000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-6"},{"id":"standard-97","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"region_prices":[{"id":"id-cgk","hourly":0.346,"monthly":230.4},{"id":"br-gru","hourly":0.403,"monthly":268.8}],"addons":{"backups":{"price":{"hourly":0.06,"monthly":40},"region_prices":[{"id":"id-cgk","hourly":0.072,"monthly":48},{"id":"br-gru","hourly":0.084,"monthly":56}]}},"memory":8192,"disk":393216,"transfer":16000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-8"},{"id":"standard-98","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"region_prices":[{"id":"id-cgk","hourly":0.691,"monthly":460.8},{"id":"br-gru","hourly":0.806,"monthly":537.6}],"addons":{"backups":{"price":{"hourly":0.12,"monthly":80},"region_prices":[{"id":"id-cgk","hourly":0.144,"monthly":96},{"id":"br-gru","hourly":0.168,"monthly":112}]}},"memory":16384,"disk":786432,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-16"},{"id":"standard-99","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"region_prices":[{"id":"id-cgk","hourly":1.037,"monthly":691.2},{"id":"br-gru","hourly":1.21,"monthly":806.4}],"addons":{"backups":{"price":{"hourly":0.18,"monthly":120},"region_prices":[{"id":"id-cgk","hourly":0.216,"monthly":144},{"id":"br-gru","hourly":0.252,"monthly":168}]}},"memory":24576,"disk":1179648,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20"},{"id":"standard-100","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"region_prices":[{"id":"id-cgk","hourly":1.382,"monthly":921.6},{"id":"br-gru","hourly":1.613,"monthly":1075.2}],"addons":{"backups":{"price":{"hourly":0.24,"monthly":160},"region_prices":[{"id":"id-cgk","hourly":0.288,"monthly":192},{"id":"br-gru","hourly":0.336,"monthly":224}]}},"memory":32768,"disk":1572864,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-24"},{"id":"standard-101","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"region_prices":[{"id":"id-cgk","hourly":1.728,"monthly":1152},{"id":"br-gru","hourly":2.016,"monthly":1344}],"addons":{"backups":{"price":{"hourly":0.3,"monthly":200},"region_prices":[{"id":"id-cgk","hourly":0.36,"monthly":240},{"id":"br-gru","hourly":0.42,"monthly":280}]}},"memory":40960,"disk":1966080,"transfer":20000,"vcpus":8,"gpus":0,"network_out":250,"class":null,"successor":"g6-standard-20-s"},{"id":"g4-standard-1","label":"Linode 2GB (pending upgrade)","price":{"hourly":0.018,"monthly":12},"region_prices":[{"id":"id-cgk","hourly":0.022,"monthly":14.4},{"id":"br-gru","hourly":0.025,"monthly":16.8}],"addons":{"backups":{"price":{"hourly":0.004,"monthly":2.5},"region_prices":[{"id":"id-cgk","hourly":0.004,"monthly":3},{"id":"br-gru","hourly":0.005,"monthly":3.5}]}},"memory":1024,"disk":24576,"transfer":2000,"vcpus":1,"gpus":0,"network_out":125,"class":"standard","successor":"g6-standard-1"},{"id":"g4-standard-2","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"region_prices":[{"id":"id-cgk","hourly":0.043,"monthly":28.8},{"id":"br-gru","hourly":0.05,"monthly":33.6}],"addons":{"backups":{"price":{"hourly":0.008,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.01,"monthly":7}]}},"memory":2048,"disk":49152,"transfer":3000,"vcpus":2,"gpus":0,"network_out":250,"class":"standard","successor":"g6-standard-2"},{"id":"g4-standard-3-2","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"region_prices":[{"id":"id-cgk","hourly":0.065,"monthly":43.2},{"id":"br-gru","hourly":0.076,"monthly":50.4}],"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5},"region_prices":[{"id":"id-cgk","hourly":0.013,"monthly":9},{"id":"br-gru","hourly":0.016,"monthly":10.5}]}},"memory":3072,"disk":73728,"transfer":3000,"vcpus":3,"gpus":0,"network_out":375,"class":"standard","successor":"g6-standard-3-s"},{"id":"g4-standard-4","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"region_prices":[{"id":"id-cgk","hourly":0.086,"monthly":57.6},{"id":"br-gru","hourly":0.101,"monthly":67.2}],"addons":{"backups":{"price":{"hourly":0.015,"monthly":10},"region_prices":[{"id":"id-cgk","hourly":0.018,"monthly":12},{"id":"br-gru","hourly":0.021,"monthly":14}]}},"memory":4096,"disk":98304,"transfer":4000,"vcpus":4,"gpus":0,"network_out":500,"class":"standard","successor":"g6-standard-4"},{"id":"g4-standard-4-s","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"region_prices":[{"id":"id-cgk","hourly":0.13,"monthly":86.4},{"id":"br-gru","hourly":0.151,"monthly":101}],"addons":{"backups":{"price":{"hourly":0.024,"monthly":15},"region_prices":[{"id":"id-cgk","hourly":0.027,"monthly":18},{"id":"br-gru","hourly":0.031,"monthly":21}]}},"memory":6144,"disk":147456,"transfer":6000,"vcpus":4,"gpus":0,"network_out":750,"class":"standard","successor":"g6-standard-4-s"},{"id":"g4-standard-6","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"region_prices":[{"id":"id-cgk","hourly":0.173,"monthly":115.2},{"id":"br-gru","hourly":0.202,"monthly":134.4}],"addons":{"backups":{"price":{"hourly":0.03,"monthly":20},"region_prices":[{"id":"id-cgk","hourly":0.036,"monthly":24},{"id":"br-gru","hourly":0.042,"monthly":28}]}},"memory":8192,"disk":196608,"transfer":8000,"vcpus":6,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-6"},{"id":"g4-standard-8","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"region_prices":[{"id":"id-cgk","hourly":0.346,"monthly":230.4},{"id":"br-gru","hourly":0.403,"monthly":268.8}],"addons":{"backups":{"price":{"hourly":0.06,"monthly":40},"region_prices":[{"id":"id-cgk","hourly":0.072,"monthly":48},{"id":"br-gru","hourly":0.084,"monthly":56}]}},"memory":16384,"disk":393216,"transfer":16000,"vcpus":8,"gpus":0,"network_out":2000,"class":"standard","successor":"g6-standard-8"},{"id":"g4-standard-12","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"region_prices":[{"id":"id-cgk","hourly":0.691,"monthly":460.8},{"id":"br-gru","hourly":0.806,"monthly":537.6}],"addons":{"backups":{"price":{"hourly":0.12,"monthly":80},"region_prices":[{"id":"id-cgk","hourly":0.144,"monthly":96},{"id":"br-gru","hourly":0.168,"monthly":112}]}},"memory":32768,"disk":786432,"transfer":20000,"vcpus":12,"gpus":0,"network_out":4000,"class":"standard","successor":"g6-standard-16"},{"id":"g4-standard-16","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"region_prices":[{"id":"id-cgk","hourly":1.037,"monthly":691.2},{"id":"br-gru","hourly":1.21,"monthly":806.4}],"addons":{"backups":{"price":{"hourly":0.18,"monthly":120},"region_prices":[{"id":"id-cgk","hourly":0.216,"monthly":144},{"id":"br-gru","hourly":0.252,"monthly":168}]}},"memory":49152,"disk":1179648,"transfer":20000,"vcpus":16,"gpus":0,"network_out":6000,"class":"standard","successor":"g6-standard-20"},{"id":"g4-standard-20","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"region_prices":[{"id":"id-cgk","hourly":1.382,"monthly":921.6},{"id":"br-gru","hourly":1.613,"monthly":1075.2}],"addons":{"backups":{"price":{"hourly":0.24,"monthly":160},"region_prices":[{"id":"id-cgk","hourly":0.288,"monthly":192},{"id":"br-gru","hourly":0.336,"monthly":224}]}},"memory":65536,"disk":1572864,"transfer":20000,"vcpus":20,"gpus":0,"network_out":8000,"class":"standard","successor":"g6-standard-24"},{"id":"g4-standard-20-s1","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"region_prices":[{"id":"id-cgk","hourly":1.728,"monthly":1152},{"id":"br-gru","hourly":2.016,"monthly":1344}],"addons":{"backups":{"price":{"hourly":0.3,"monthly":200},"region_prices":[{"id":"id-cgk","hourly":0.36,"monthly":240},{"id":"br-gru","hourly":0.42,"monthly":280}]}},"memory":81920,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-20-s"},{"id":"g4-standard-20-s2","label":"Linode 192GB (pending upgrade)","price":{"hourly":1.728,"monthly":1152},"region_prices":[{"id":"id-cgk","hourly":2.074,"monthly":1382.4},{"id":"br-gru","hourly":2.419,"monthly":1612.8}],"addons":{"backups":{"price":{"hourly":0.3,"monthly":200},"region_prices":[{"id":"id-cgk","hourly":0.36,"monthly":240},{"id":"br-gru","hourly":0.42,"monthly":280}]}},"memory":98304,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-32"},{"id":"g5-nanode-1","label":"Nanode 1GB (pending upgrade)","price":{"hourly":0.0075,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.0105,"monthly":7}],"addons":{"backups":{"price":{"hourly":0.003,"monthly":2},"region_prices":[{"id":"id-cgk","hourly":0.004,"monthly":2.4},{"id":"br-gru","hourly":0.004,"monthly":2.8}]}},"memory":1024,"disk":20480,"transfer":1000,"vcpus":1,"gpus":0,"network_out":1000,"class":"nanode","successor":"g6-nanode-1"},{"id":"g5-standard-1","label":"Linode 2GB (pending upgrade)","price":{"hourly":0.018,"monthly":12},"region_prices":[{"id":"id-cgk","hourly":0.022,"monthly":14.4},{"id":"br-gru","hourly":0.025,"monthly":16.8}],"addons":{"backups":{"price":{"hourly":0.004,"monthly":2.5},"region_prices":[{"id":"id-cgk","hourly":0.004,"monthly":3},{"id":"br-gru","hourly":0.005,"monthly":3.5}]}},"memory":2048,"disk":30720,"transfer":2000,"vcpus":1,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-1"},{"id":"g5-standard-2","label":"Linode 4GB (pending upgrade)","price":{"hourly":0.036,"monthly":24},"region_prices":[{"id":"id-cgk","hourly":0.043,"monthly":28.8},{"id":"br-gru","hourly":0.05,"monthly":33.6}],"addons":{"backups":{"price":{"hourly":0.008,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.01,"monthly":7}]}},"memory":4096,"disk":49152,"transfer":3000,"vcpus":2,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-2"},{"id":"g5-standard-3-s","label":"Linode 6GB (pending upgrade)","price":{"hourly":0.06,"monthly":36},"region_prices":[{"id":"id-cgk","hourly":0.065,"monthly":43.2},{"id":"br-gru","hourly":0.076,"monthly":50.4}],"addons":{"backups":{"price":{"hourly":0.012,"monthly":7.5},"region_prices":[{"id":"id-cgk","hourly":0.013,"monthly":9},{"id":"br-gru","hourly":0.016,"monthly":10.5}]}},"memory":6144,"disk":73728,"transfer":3000,"vcpus":3,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-3-s"},{"id":"g5-standard-4","label":"Linode 8GB (pending upgrade)","price":{"hourly":0.072,"monthly":48},"region_prices":[{"id":"id-cgk","hourly":0.086,"monthly":57.6},{"id":"br-gru","hourly":0.101,"monthly":67.2}],"addons":{"backups":{"price":{"hourly":0.015,"monthly":10},"region_prices":[{"id":"id-cgk","hourly":0.018,"monthly":12},{"id":"br-gru","hourly":0.021,"monthly":14}]}},"memory":8192,"disk":98304,"transfer":4000,"vcpus":4,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-4"},{"id":"g5-standard-4-s","label":"Linode 10GB (pending upgrade)","price":{"hourly":0.108,"monthly":72},"region_prices":[{"id":"id-cgk","hourly":0.13,"monthly":86.4},{"id":"br-gru","hourly":0.151,"monthly":100.8}],"addons":{"backups":{"price":{"hourly":0.024,"monthly":15},"region_prices":[{"id":"id-cgk","hourly":0.027,"monthly":18},{"id":"br-gru","hourly":0.031,"monthly":21}]}},"memory":10240,"disk":147456,"transfer":6000,"vcpus":4,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-4-s"},{"id":"g5-standard-6","label":"Linode 16GB (pending upgrade)","price":{"hourly":0.144,"monthly":96},"region_prices":[{"id":"id-cgk","hourly":0.173,"monthly":115.2},{"id":"br-gru","hourly":0.202,"monthly":134.4}],"addons":{"backups":{"price":{"hourly":0.03,"monthly":20},"region_prices":[{"id":"id-cgk","hourly":0.036,"monthly":24},{"id":"br-gru","hourly":0.042,"monthly":28}]}},"memory":12288,"disk":196608,"transfer":8000,"vcpus":6,"gpus":0,"network_out":1000,"class":"standard","successor":"g6-standard-6"},{"id":"g5-standard-8","label":"Linode 32GB (pending upgrade)","price":{"hourly":0.288,"monthly":192},"region_prices":[{"id":"id-cgk","hourly":0.346,"monthly":230.4},{"id":"br-gru","hourly":0.403,"monthly":268.8}],"addons":{"backups":{"price":{"hourly":0.06,"monthly":40},"region_prices":[{"id":"id-cgk","hourly":0.072,"monthly":48},{"id":"br-gru","hourly":0.084,"monthly":56}]}},"memory":24576,"disk":393216,"transfer":16000,"vcpus":8,"gpus":0,"network_out":2000,"class":"standard","successor":"g6-standard-8"},{"id":"g5-standard-12","label":"Linode 64GB (pending upgrade)","price":{"hourly":0.576,"monthly":384},"region_prices":[{"id":"id-cgk","hourly":0.691,"monthly":460.8},{"id":"br-gru","hourly":0.806,"monthly":537.6}],"addons":{"backups":{"price":{"hourly":0.12,"monthly":80},"region_prices":[{"id":"id-cgk","hourly":0.144,"monthly":96},{"id":"br-gru","hourly":0.168,"monthly":112}]}},"memory":49152,"disk":786432,"transfer":20000,"vcpus":12,"gpus":0,"network_out":4000,"class":"standard","successor":"g6-standard-16"},{"id":"g5-standard-16","label":"Linode 96GB (pending upgrade)","price":{"hourly":0.864,"monthly":576},"region_prices":[{"id":"id-cgk","hourly":1.037,"monthly":691.2},{"id":"br-gru","hourly":1.21,"monthly":806.4}],"addons":{"backups":{"price":{"hourly":0.18,"monthly":120},"region_prices":[{"id":"id-cgk","hourly":0.216,"monthly":144},{"id":"br-gru","hourly":0.252,"monthly":168}]}},"memory":65536,"disk":1179648,"transfer":20000,"vcpus":16,"gpus":0,"network_out":6000,"class":"standard","successor":"g6-standard-20"},{"id":"g5-standard-20","label":"Linode 128GB (pending upgrade)","price":{"hourly":1.152,"monthly":768},"region_prices":[{"id":"id-cgk","hourly":1.382,"monthly":921.6},{"id":"br-gru","hourly":1.613,"monthly":1075.2}],"addons":{"backups":{"price":{"hourly":0.24,"monthly":160},"region_prices":[{"id":"id-cgk","hourly":0.288,"monthly":192},{"id":"br-gru","hourly":0.336,"monthly":224}]}},"memory":81920,"disk":1572864,"transfer":20000,"vcpus":20,"gpus":0,"network_out":8000,"class":"standard","successor":"g6-standard-24"},{"id":"g5-standard-20-s1","label":"Linode 160GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"region_prices":[{"id":"id-cgk","hourly":1.728,"monthly":1152},{"id":"br-gru","hourly":2.016,"monthly":1344}],"addons":{"backups":{"price":{"hourly":0.3,"monthly":200},"region_prices":[{"id":"id-cgk","hourly":0.36,"monthly":240},{"id":"br-gru","hourly":0.42,"monthly":280}]}},"memory":102400,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-20-s"},{"id":"g5-standard-20-s2","label":"Linode 192GB (pending upgrade)","price":{"hourly":1.728,"monthly":1152},"region_prices":[{"id":"id-cgk","hourly":2.074,"monthly":1382.4},{"id":"br-gru","hourly":2.419,"monthly":1612.8}],"addons":{"backups":{"price":{"hourly":0.3,"monthly":200},"region_prices":[{"id":"id-cgk","hourly":0.36,"monthly":240},{"id":"br-gru","hourly":0.42,"monthly":280}]}},"memory":122880,"disk":1966080,"transfer":20000,"vcpus":20,"gpus":0,"network_out":10000,"class":"standard","successor":"g6-standard-32"},{"id":"g5-highmem-1","label":"Linode 24GB (pending upgrade)","price":{"hourly":0.09,"monthly":60},"region_prices":[{"id":"id-cgk","hourly":0.108,"monthly":72},{"id":"br-gru","hourly":0.126,"monthly":84}],"addons":{"backups":{"price":{"hourly":0.008,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.01,"monthly":7}]}},"memory":16384,"disk":20480,"transfer":5000,"vcpus":1,"gpus":0,"network_out":1000,"class":"highmem","successor":"g6-highmem-1"},{"id":"g5-highmem-2","label":"Linode 48GB (pending upgrade)","price":{"hourly":0.18,"monthly":120},"region_prices":[{"id":"id-cgk","hourly":0.216,"monthly":144},{"id":"br-gru","hourly":0.252,"monthly":168}],"addons":{"backups":{"price":{"hourly":0.015,"monthly":10},"region_prices":[{"id":"id-cgk","hourly":0.018,"monthly":12},{"id":"br-gru","hourly":0.021,"monthly":14}]}},"memory":32768,"disk":40960,"transfer":6000,"vcpus":2,"gpus":0,"network_out":1500,"class":"highmem","successor":"g6-highmem-2"},{"id":"g5-highmem-4","label":"Linode 90GB (pending upgrade)","price":{"hourly":0.36,"monthly":240},"region_prices":[{"id":"id-cgk","hourly":0.432,"monthly":288},{"id":"br-gru","hourly":0.504,"monthly":336}],"addons":{"backups":{"price":{"hourly":0.03,"monthly":20},"region_prices":[{"id":"id-cgk","hourly":0.036,"monthly":24},{"id":"br-gru","hourly":0.042,"monthly":28}]}},"memory":61440,"disk":92160,"transfer":7000,"vcpus":4,"gpus":0,"network_out":3000,"class":"highmem","successor":"g6-highmem-4"},{"id":"g5-highmem-8","label":"Linode 150GB (pending upgrade)","price":{"hourly":0.72,"monthly":480},"region_prices":[{"id":"id-cgk","hourly":0.864,"monthly":576},{"id":"br-gru","hourly":1.008,"monthly":672}],"addons":{"backups":{"price":{"hourly":0.06,"monthly":40},"region_prices":[{"id":"id-cgk","hourly":0.072,"monthly":48},{"id":"br-gru","hourly":0.084,"monthly":56}]}},"memory":102400,"disk":204800,"transfer":8000,"vcpus":8,"gpus":0,"network_out":6000,"class":"highmem","successor":"g6-highmem-8"},{"id":"g5-highmem-16","label":"Linode 300GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"region_prices":[{"id":"id-cgk","hourly":1.728,"monthly":1152},{"id":"br-gru","hourly":2.016,"monthly":1344}],"addons":{"backups":{"price":{"hourly":0.09,"monthly":60},"region_prices":[{"id":"id-cgk","hourly":0.108,"monthly":72},{"id":"br-gru","hourly":0.126,"monthly":84}]}},"memory":204800,"disk":348160,"transfer":9000,"vcpus":16,"gpus":0,"network_out":10000,"class":"highmem","successor":"g6-highmem-16"},{"id":"g6-highmem-1","label":"Linode 24GB (pending upgrade)","price":{"hourly":0.09,"monthly":60},"region_prices":[{"id":"id-cgk","hourly":0.108,"monthly":72},{"id":"br-gru","hourly":0.126,"monthly":84}],"addons":{"backups":{"price":{"hourly":0.0075,"monthly":5},"region_prices":[{"id":"id-cgk","hourly":0.009,"monthly":6},{"id":"br-gru","hourly":0.0105,"monthly":7}]}},"memory":24576,"disk":20480,"transfer":5000,"vcpus":1,"gpus":0,"network_out":5000,"class":"highmem","successor":"g7-highmem-1"},{"id":"g6-highmem-2","label":"Linode 48GB (pending upgrade)","price":{"hourly":0.18,"monthly":120},"region_prices":[{"id":"id-cgk","hourly":0.216,"monthly":144},{"id":"br-gru","hourly":0.252,"monthly":168}],"addons":{"backups":{"price":{"hourly":0.015,"monthly":10},"region_prices":[{"id":"id-cgk","hourly":0.018,"monthly":12},{"id":"br-gru","hourly":0.021,"monthly":14}]}},"memory":49152,"disk":40960,"transfer":6000,"vcpus":2,"gpus":0,"network_out":6000,"class":"highmem","successor":"g7-highmem-2"},{"id":"g6-highmem-4","label":"Linode 90GB (pending upgrade)","price":{"hourly":0.36,"monthly":240},"region_prices":[{"id":"id-cgk","hourly":0.432,"monthly":288},{"id":"br-gru","hourly":0.504,"monthly":336}],"addons":{"backups":{"price":{"hourly":0.03,"monthly":20},"region_prices":[{"id":"id-cgk","hourly":0.036,"monthly":24},{"id":"br-gru","hourly":0.042,"monthly":28}]}},"memory":92160,"disk":92160,"transfer":7000,"vcpus":4,"gpus":0,"network_out":7000,"class":"highmem","successor":"g7-highmem-4"},{"id":"g6-highmem-8","label":"Linode 150GB (pending upgrade)","price":{"hourly":0.72,"monthly":480},"region_prices":[{"id":"id-cgk","hourly":0.864,"monthly":576},{"id":"br-gru","hourly":1.008,"monthly":672}],"addons":{"backups":{"price":{"hourly":0.06,"monthly":40},"region_prices":[{"id":"id-cgk","hourly":0.072,"monthly":48},{"id":"br-gru","hourly":0.084,"monthly":56}]}},"memory":153600,"disk":204800,"transfer":8000,"vcpus":8,"gpus":0,"network_out":8000,"class":"highmem","successor":"g7-highmem-8"},{"id":"g6-highmem-16","label":"Linode 300GB (pending upgrade)","price":{"hourly":1.44,"monthly":960},"region_prices":[{"id":"id-cgk","hourly":1.728,"monthly":1152},{"id":"br-gru","hourly":2.016,"monthly":1344}],"addons":{"backups":{"price":{"hourly":0.12,"monthly":80},"region_prices":[{"id":"id-cgk","hourly":0.144,"monthly":96},{"id":"br-gru","hourly":0.168,"monthly":112}]}},"memory":307200,"disk":348160,"transfer":9000,"vcpus":16,"gpus":0,"network_out":9000,"class":"highmem","successor":"g7-highmem-16"}],"page":1,"pages":1,"results":65} \ No newline at end of file diff --git a/packages/manager/src/components/AreaChart.tsx b/packages/manager/src/components/AreaChart.tsx new file mode 100644 index 00000000000..d88aff1a691 --- /dev/null +++ b/packages/manager/src/components/AreaChart.tsx @@ -0,0 +1,138 @@ +import { Typography, useTheme } from '@mui/material'; +import { styled } from '@mui/material/styles'; +import { DateTime } from 'luxon'; +import React from 'react'; +import { + AreaChart as _AreaChart, + Area, + CartesianGrid, + ResponsiveContainer, + Tooltip, + TooltipProps, + XAxis, + YAxis, +} from 'recharts'; + +import { Paper } from 'src/components/Paper'; +import { roundTo } from 'src/utilities/roundTo'; + +interface AreaProps { + color: string; + dataKey: string; +} + +interface XAxisProps { + tickFormat: string; + tickGap: number; +} + +interface AreaChartProps { + areas: AreaProps[]; + data: any; + height: number; + timezone: string; + unit: string; + xAxis: XAxisProps; +} + +const humanizeLargeData = (value: number) => { + if (value >= 1000000) { + return value / 1000000 + 'M'; + } + if (value >= 1000) { + return value / 1000 + 'K'; + } + return `${value}`; +}; + +export const AreaChart = (props: AreaChartProps) => { + const { areas, data, height, timezone, unit, xAxis } = props; + + const theme = useTheme(); + + const xAxisTickFormatter = (t: number) => { + return DateTime.fromMillis(t, { zone: timezone }).toFormat( + xAxis.tickFormat + ); + }; + + const tooltipLabelFormatter = (t: number) => { + return DateTime.fromMillis(t, { zone: timezone }).toFormat( + 'LLL dd, yyyy, h:mm a' + ); + }; + + const tooltipValueFormatter = (value: number) => + `${roundTo(value)} ${unit}/s`; + + const CustomTooltip = ({ + active, + label, + payload, + }: TooltipProps) => { + if (active && payload && payload.length) { + return ( + + {tooltipLabelFormatter(label)} + {payload.map((item) => ( + + {item.dataKey}: {tooltipValueFormatter(item.value)} + + ))} + + ); + } + + return null; + }; + + return ( + + <_AreaChart data={data}> + + + + } + /> + {areas.map(({ color, dataKey }) => ( + + ))} + + + ); +}; + +const StyledPaper = styled(Paper, { + label: 'StyledPaper', +})(({ theme }) => ({ + border: `1px solid ${theme.color.border2}`, + padding: theme.spacing(1), +})); diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.tsx index 923efc6d703..013314d5235 100644 --- a/packages/manager/src/components/Autocomplete/Autocomplete.tsx +++ b/packages/manager/src/components/Autocomplete/Autocomplete.tsx @@ -106,6 +106,7 @@ export const Autocomplete = < loading={loading} noMarginTop={noMarginTop} placeholder={placeholder || 'Select an option'} + required={textFieldProps?.InputProps?.required} {...params} {...textFieldProps} InputProps={{ @@ -128,7 +129,9 @@ export const Autocomplete = < flexGrow: 1, }} > - {option.label} + {rest.getOptionLabel + ? rest.getOptionLabel(option) + : option.label} @@ -148,7 +151,7 @@ export const Autocomplete = < multiple={multiple} noOptionsText={noOptionsText || You have no options to choose from} onBlur={onBlur} - options={multiple ? optionsWithSelectAll : options} + options={multiple && options.length > 0 ? optionsWithSelectAll : options} popupIcon={} value={value} {...rest} diff --git a/packages/manager/src/components/CheckoutSummary/CheckoutSummary.tsx b/packages/manager/src/components/CheckoutSummary/CheckoutSummary.tsx index 40ad820d84f..ada8a14e6bb 100644 --- a/packages/manager/src/components/CheckoutSummary/CheckoutSummary.tsx +++ b/packages/manager/src/components/CheckoutSummary/CheckoutSummary.tsx @@ -1,9 +1,9 @@ import { useTheme } from '@mui/material'; +import Grid2 from '@mui/material/Unstable_Grid2/Grid2'; import { Theme, styled } from '@mui/material/styles'; import useMediaQuery from '@mui/material/useMediaQuery'; import * as React from 'react'; -import { Grid } from '../Grid'; import { Paper } from '../Paper'; import { Typography } from '../Typography'; import { SummaryItem } from './SummaryItem'; @@ -62,7 +62,7 @@ const StyledHeading = styled(Typography)(({ theme }) => ({ marginBottom: theme.spacing(3), })); -const StyledSummary = styled(Grid)(({ theme }) => ({ +const StyledSummary = styled(Grid2)(({ theme }) => ({ [theme.breakpoints.up('md')]: { '& > div': { '&:last-child': { diff --git a/packages/manager/src/components/CheckoutSummary/SummaryItem.tsx b/packages/manager/src/components/CheckoutSummary/SummaryItem.tsx index 096b2b3c47a..1797684864a 100644 --- a/packages/manager/src/components/CheckoutSummary/SummaryItem.tsx +++ b/packages/manager/src/components/CheckoutSummary/SummaryItem.tsx @@ -1,13 +1,13 @@ import { styled } from '@mui/material/styles'; import React from 'react'; -import { Grid } from '../Grid'; +import Grid2 from '@mui/material/Unstable_Grid2/Grid2'; import { Typography } from '../Typography'; import { SummaryItem as Props } from './CheckoutSummary'; export const SummaryItem = ({ details, title }: Props) => { return ( - + {title ? ( <> { ); }; -const StyledGrid = styled(Grid)(({ theme }) => ({ +const StyledGrid = styled(Grid2)(({ theme }) => ({ marginBottom: `${theme.spacing()} !important`, marginTop: `${theme.spacing()} !important`, paddingBottom: '0 !important', diff --git a/packages/manager/src/components/CircleProgress/CircleProgress.stories.mdx b/packages/manager/src/components/CircleProgress/CircleProgress.stories.mdx deleted file mode 100644 index cb82e380a0b..00000000000 --- a/packages/manager/src/components/CircleProgress/CircleProgress.stories.mdx +++ /dev/null @@ -1,35 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs'; -import { CircleProgress } from './CircleProgress'; - - - -# Circle Progress - -Use for short, indeterminate activities requiring user attention. - -export const Template = (args) => ; - - - - {Template.bind()} - - - - diff --git a/packages/manager/src/components/CircleProgress/CircleProgress.stories.tsx b/packages/manager/src/components/CircleProgress/CircleProgress.stories.tsx new file mode 100644 index 00000000000..28b1e392d38 --- /dev/null +++ b/packages/manager/src/components/CircleProgress/CircleProgress.stories.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import { CircleProgress } from './CircleProgress'; + +import type { Meta, StoryObj } from '@storybook/react'; + +type Story = StoryObj; + +export const Default: Story = { + render: (args) => , +}; + +const meta: Meta = { + component: CircleProgress, + title: 'Components/Loading States/Circle Progress', +}; + +export default meta; diff --git a/packages/manager/src/components/CircleProgress/CircleProgress.test.tsx b/packages/manager/src/components/CircleProgress/CircleProgress.test.tsx new file mode 100644 index 00000000000..b9416f0f1e6 --- /dev/null +++ b/packages/manager/src/components/CircleProgress/CircleProgress.test.tsx @@ -0,0 +1,54 @@ +import React from 'react'; + +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { CircleProgress } from './CircleProgress'; + +const CONTENT_LOADING = 'Content is loading'; + +describe('CircleProgress', () => { + it('renders a CircleProgress properly', () => { + const screen = renderWithTheme(); + + const circleProgress = screen.getByLabelText(CONTENT_LOADING); + expect(circleProgress).toBeVisible(); + const circle = screen.getByTestId('circle-progress'); + expect(circle).toBeInTheDocument(); + expect(circle).toHaveStyle('width: 124px; height: 124px;'); + const innerCircle = screen.getByTestId('inner-circle-progress'); + expect(innerCircle).toBeInTheDocument(); + }); + + it('renders a mini CircleProgress', () => { + const screen = renderWithTheme(); + + const circleProgress = screen.getByLabelText(CONTENT_LOADING); + expect(circleProgress).toBeVisible(); + expect(circleProgress).toHaveStyle('width: 40px; height: 40px;'); + }); + + it('sets a mini CircleProgress with no padding', () => { + const screen = renderWithTheme(); + + const circleProgress = screen.getByLabelText(CONTENT_LOADING); + expect(circleProgress).toBeVisible(); + expect(circleProgress).toHaveStyle('width: 22px; height: 22px;'); + }); + + it('sets a mini CircleProgress with a custom size', () => { + const screen = renderWithTheme(); + + const circleProgress = screen.getByLabelText(CONTENT_LOADING); + expect(circleProgress).toBeVisible(); + expect(circleProgress).toHaveStyle('width: 25px; height: 25px;'); + }); + + it('renders a CircleProgress without the inner circle', () => { + const screen = renderWithTheme(); + + const circleProgress = screen.getByLabelText(CONTENT_LOADING); + expect(circleProgress).toBeVisible(); + const innerCircle = screen.queryByTestId('inner-circle-progress'); + expect(innerCircle).not.toBeInTheDocument(); + }); +}); diff --git a/packages/manager/src/components/CircleProgress/CircleProgress.tsx b/packages/manager/src/components/CircleProgress/CircleProgress.tsx index 308a5d61219..24fe6e240fb 100644 --- a/packages/manager/src/components/CircleProgress/CircleProgress.tsx +++ b/packages/manager/src/components/CircleProgress/CircleProgress.tsx @@ -9,26 +9,37 @@ import { import { omittedProps } from 'src/utilities/omittedProps'; interface CircleProgressProps extends CircularProgressProps { + /** + * Additional child elements to pass in + */ children?: JSX.Element; - className?: string; + /** + * Displays a smaller version of the circle progress. + */ mini?: boolean; + /** + * If true, will not show an inner circle beneath the spinning circle + */ noInner?: boolean; + /** + * Removes the padding for `mini` circle progresses only. + */ noPadding?: boolean; + /** + * To be primarily used with mini and noPadding. Set spinner to a custom size. + */ size?: number; + /** + * Additional styles to apply to the root element. + */ sx?: SxProps; } +/** + * Use for short, indeterminate activities requiring user attention. + */ const CircleProgress = (props: CircleProgressProps) => { - const { - children, - className, - mini, - noInner, - noPadding, - size, - sx, - ...rest - } = props; + const { children, mini, noInner, noPadding, size, sx, ...rest } = props; const variant = typeof props.value === 'number' ? 'determinate' : 'indeterminate'; @@ -48,16 +59,12 @@ const CircleProgress = (props: CircleProgressProps) => { } return ( - + {children !== undefined && ( {children} )} {noInner !== true && ( - + )} diff --git a/packages/manager/src/components/ColorPalette/ColorPalette.stories.mdx b/packages/manager/src/components/ColorPalette/ColorPalette.stories.mdx deleted file mode 100644 index 4e741748053..00000000000 --- a/packages/manager/src/components/ColorPalette/ColorPalette.stories.mdx +++ /dev/null @@ -1,21 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs'; -import { ColorPalette } from './ColorPalette'; - - - -# Color Palette - -Add a new color to the palette, especially another tint of gray or blue, only after exhausting the option of using an existing color. - -- Colors used in light mode are located in `foundations/light.ts` -- Colors used in dark mode are located in `foundations/dark.ts` - -If a color does not exist in the current palette and is only used once, consider applying the color conditionally: - -`theme.name === 'light' ? '#fff' : '#000'` - - - - - - diff --git a/packages/manager/src/components/ColorPalette/ColorPalette.stories.tsx b/packages/manager/src/components/ColorPalette/ColorPalette.stories.tsx new file mode 100644 index 00000000000..ea406d68902 --- /dev/null +++ b/packages/manager/src/components/ColorPalette/ColorPalette.stories.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +import { ColorPalette } from './ColorPalette'; + +import type { Meta, StoryObj } from '@storybook/react'; + +export const Default: StoryObj = { + render: () => , +}; + +const meta: Meta = { + component: ColorPalette, + title: 'Design System/Color Palette', +}; + +export default meta; diff --git a/packages/manager/src/components/ColorPalette/ColorPalette.test.tsx b/packages/manager/src/components/ColorPalette/ColorPalette.test.tsx new file mode 100644 index 00000000000..a9f6024520e --- /dev/null +++ b/packages/manager/src/components/ColorPalette/ColorPalette.test.tsx @@ -0,0 +1,132 @@ +import React from 'react'; + +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { ColorPalette } from './ColorPalette'; + +describe('Color Palette', () => { + it('renders the Color Palette', () => { + const { getAllByText, getByText } = renderWithTheme(); + + // primary colors + getByText('Primary Colors'); + getByText('theme.palette.primary.main'); + const mainHash = getAllByText('#3683dc'); + expect(mainHash).toHaveLength(2); + getByText('theme.palette.primary.light'); + getByText('#4d99f1'); + getByText('theme.palette.primary.dark'); + getByText('#2466b3'); + getByText('theme.palette.text.primary'); + const primaryHash = getAllByText('#606469'); + expect(primaryHash).toHaveLength(3); + getByText('theme.color.headline'); + const headlineHash = getAllByText('#32363c'); + expect(headlineHash).toHaveLength(2); + getByText('theme.palette.divider'); + const dividerHash = getAllByText('#f4f4f4'); + expect(dividerHash).toHaveLength(2); + const whiteColor = getAllByText('theme.color.white'); + expect(whiteColor).toHaveLength(2); + const whiteHash = getAllByText('#fff'); + expect(whiteHash).toHaveLength(3); + + // etc + getByText('Etc.'); + getByText('theme.color.red'); + getByText('#ca0813'); + getByText('theme.color.orange'); + getByText('#ffb31a'); + getByText('theme.color.yellow'); + getByText('#fecf2f'); + getByText('theme.color.green'); + getByText('#00b159'); + getByText('theme.color.teal'); + getByText('#17cf73'); + getByText('theme.color.border2'); + getByText('#c5c6c8'); + getByText('theme.color.border3'); + getByText('#eee'); + getByText('theme.color.grey1'); + getByText('#abadaf'); + getByText('theme.color.grey2'); + getByText('#e7e7e7'); + getByText('theme.color.grey3'); + getByText('#ccc'); + getByText('theme.color.grey4'); + getByText('#8C929D'); + getByText('theme.color.grey5'); + getByText('#f5f5f5'); + getByText('theme.color.grey6'); + const borderGreyHash = getAllByText('#e3e5e8'); + expect(borderGreyHash).toHaveLength(3); + getByText('theme.color.grey7'); + getByText('#e9eaef'); + getByText('theme.color.grey8'); + getByText('#dbdde1'); + getByText('theme.color.grey9'); + const borderGrey9Hash = getAllByText('#f4f5f6'); + expect(borderGrey9Hash).toHaveLength(3); + getByText('theme.color.black'); + getByText('#222'); + getByText('theme.color.offBlack'); + getByText('#444'); + getByText('theme.color.boxShadow'); + getByText('#ddd'); + getByText('theme.color.boxShadowDark'); + getByText('#aaa'); + getByText('theme.color.blueDTwhite'); + getByText('theme.color.tableHeaderText'); + getByText('rgba(0, 0, 0, 0.54)'); + getByText('theme.color.drawerBackdrop'); + getByText('rgba(255, 255, 255, 0.5)'); + getByText('theme.color.label'); + getByText('#555'); + getByText('theme.color.disabledText'); + getByText('#c9cacb'); + getByText('theme.color.tagButton'); + getByText('#f1f7fd'); + getByText('theme.color.tagIcon'); + getByText('#7daee8'); + + // background colors + getByText('Background Colors'); + getByText('theme.bg.app'); + getByText('theme.bg.main'); + getByText('theme.bg.offWhite'); + getByText('#fbfbfb'); + getByText('theme.bg.lightBlue1'); + getByText('#f0f7ff'); + getByText('theme.bg.lightBlue2'); + getByText('#e5f1ff'); + getByText('theme.bg.white'); + getByText('theme.bg.tableHeader'); + getByText('#f9fafa'); + getByText('theme.bg.primaryNavPaper'); + getByText('#3a3f46'); + getByText('theme.bg.mainContentBanner'); + getByText('#33373d'); + getByText('theme.bg.bgPaper'); + getByText('#ffffff'); + getByText('theme.bg.bgAccessRow'); + getByText('#fafafa'); + getByText('theme.bg.bgAccessRowTransparentGradient'); + getByText('rgb(255, 255, 255, .001)'); + + // typography colors + getByText('Typography Colors'); + getByText('theme.textColors.linkActiveLight'); + getByText('#2575d0'); + getByText('theme.textColors.headlineStatic'); + getByText('theme.textColors.tableHeader'); + getByText('#888f91'); + getByText('theme.textColors.tableStatic'); + getByText('theme.textColors.textAccessTable'); + + // border colors + getByText('Border Colors'); + getByText('theme.borderColors.borderTypography'); + getByText('theme.borderColors.borderTable'); + getByText('theme.borderColors.divider'); + }); +}); diff --git a/packages/manager/src/components/ColorPalette/ColorPalette.tsx b/packages/manager/src/components/ColorPalette/ColorPalette.tsx index a6f04adfa4d..a3bfaadb121 100644 --- a/packages/manager/src/components/ColorPalette/ColorPalette.tsx +++ b/packages/manager/src/components/ColorPalette/ColorPalette.tsx @@ -42,6 +42,16 @@ const useStyles = makeStyles()((theme: Theme) => ({ }, })); +/** + * Add a new color to the palette, especially another tint of gray or blue, only after exhausting the option of using an existing color. + * + * - Colors used in light mode are located in `foundations/light.ts + * - Colors used in dark mode are located in `foundations/dark.ts` + * + * If a color does not exist in the current palette and is only used once, consider applying the color conditionally: + * + * `theme.name === 'light' ? '#fff' : '#000'` + */ export const ColorPalette = () => { const { classes } = useStyles(); const theme = useTheme(); diff --git a/packages/manager/src/components/CopyableAndDownloadableTextField.tsx b/packages/manager/src/components/CopyableAndDownloadableTextField.tsx index 753928e69e0..a3efa809511 100644 --- a/packages/manager/src/components/CopyableAndDownloadableTextField.tsx +++ b/packages/manager/src/components/CopyableAndDownloadableTextField.tsx @@ -1,5 +1,5 @@ import { Theme } from '@mui/material/styles'; -import { makeStyles } from '@mui/styles'; +import { makeStyles } from 'tss-react/mui'; import snakeCase from 'lodash/snakeCase'; import * as React from 'react'; @@ -7,7 +7,7 @@ import { CopyTooltip } from 'src/components/CopyTooltip/CopyTooltip'; import { DownloadTooltip } from 'src/components/DownloadTooltip'; import { TextField, TextFieldProps } from 'src/components/TextField'; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles()((theme: Theme) => ({ copyIcon: { '& svg': { height: 14, @@ -32,7 +32,7 @@ type Props = TextFieldProps & { }; export const CopyableAndDownloadableTextField = (props: Props) => { - const classes = useStyles(); + const { classes } = useStyles(); const { className, hideIcon, value, ...restProps } = props; const fileName = props.fileName ?? snakeCase(props.label); diff --git a/packages/manager/src/components/Currency/Currency.stories.mdx b/packages/manager/src/components/Currency/Currency.stories.mdx deleted file mode 100644 index 0a20c11b0a4..00000000000 --- a/packages/manager/src/components/Currency/Currency.stories.mdx +++ /dev/null @@ -1,34 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs'; -import { Currency } from './Currency'; - - - -export const CurrencyTemplate = (args) => ; - -# Currency - - - - {CurrencyTemplate.bind({})} - - - - diff --git a/packages/manager/src/components/Currency/Currency.stories.tsx b/packages/manager/src/components/Currency/Currency.stories.tsx new file mode 100644 index 00000000000..dd58ddca5fa --- /dev/null +++ b/packages/manager/src/components/Currency/Currency.stories.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; + +import { Currency } from './Currency'; + +import type { Meta, StoryObj } from '@storybook/react'; + +type Story = StoryObj; + +export const Default: Story = { + args: { + decimalPlaces: 2, + quantity: 4.0, + wrapInParentheses: false, + }, + render: (args) => , +}; + +const meta: Meta = { + argTypes: { + decimalPlaces: { + control: { + min: 0, + }, + }, + }, + component: Currency, + title: 'Components/Typography/Currency', +}; + +export default meta; diff --git a/packages/manager/src/components/Currency/Currency.test.tsx b/packages/manager/src/components/Currency/Currency.test.tsx index 806407dc601..0b46d8a8410 100644 --- a/packages/manager/src/components/Currency/Currency.test.tsx +++ b/packages/manager/src/components/Currency/Currency.test.tsx @@ -61,4 +61,16 @@ describe('Currency Component', () => { rerender(); getByText('$100,000.00'); }); + + it('displays --.-- when passed in as a quantity', () => { + const { getByText } = renderWithTheme(); + getByText('$--.--'); + }); + + it('applies the passed in data attributes', () => { + const { getByTestId } = renderWithTheme( + + ); + getByTestId('currency-test'); + }); }); diff --git a/packages/manager/src/components/Currency/Currency.tsx b/packages/manager/src/components/Currency/Currency.tsx index f57cb03d511..f91d1bf7103 100644 --- a/packages/manager/src/components/Currency/Currency.tsx +++ b/packages/manager/src/components/Currency/Currency.tsx @@ -2,9 +2,21 @@ import { isNumber } from 'lodash'; import * as React from 'react'; interface CurrencyFormatterProps { + /** + * Additional data attributes to pass in. For example, a data-testid + */ dataAttrs?: Record; + /** + * The number of decimal places to display. + */ decimalPlaces?: number; + /** + * The amount (of money) to display in a currency format. + */ quantity: '--.--' | number; + /** + * A boolean used to wrap the currency in parenthesis. This is normally done to indicate a negative amount or balance. + */ wrapInParentheses?: boolean; } diff --git a/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.stories.mdx b/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.stories.mdx deleted file mode 100644 index b59fda074ff..00000000000 --- a/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.stories.mdx +++ /dev/null @@ -1,45 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs'; -import { DateTime } from 'luxon'; -import { DateTimeDisplay } from './DateTimeDisplay'; - - - -export const DateTimeDisplayTemplate = (args) => ; - -# Date Time Display - - - - {DateTimeDisplayTemplate.bind({})} - - - - diff --git a/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.stories.tsx b/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.stories.tsx new file mode 100644 index 00000000000..e2770307f19 --- /dev/null +++ b/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.stories.tsx @@ -0,0 +1,30 @@ +import { DateTime } from 'luxon'; +import * as React from 'react'; + +import { DateTimeDisplay } from './DateTimeDisplay'; + +import type { Meta, StoryObj } from '@storybook/react'; + +type Story = StoryObj; + +export const Default: Story = { + args: { + displayTime: true, + value: DateTime.now().minus({ day: 3 }).toISO(), + }, + render: (args) => , +}; + +const meta: Meta = { + argTypes: { + value: { + control: { + type: 'date', + }, + }, + }, + component: DateTimeDisplay, + title: 'Components/Typography/Date Time Display', +}; + +export default meta; diff --git a/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.test.tsx b/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.test.tsx index 464dcace431..86c393f0c56 100644 --- a/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.test.tsx +++ b/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.test.tsx @@ -10,6 +10,38 @@ vi.mock('../../utilities/getUserTimezone'); const APIDate = '2018-07-20T04:23:17'; describe('DateTimeDisplay component', () => { + it('should not display the time', () => { + const props = { displayTime: false, value: APIDate }; + const { getByText } = renderWithTheme(); + + getByText('2018-07-20'); + }); + + it('should display the time', () => { + const props = { displayTime: true, value: APIDate }; + const { getByText } = renderWithTheme(); + + getByText('2018-07-20 04:23'); + }); + + it('should format the time based on the specified format only', () => { + const props = { + displayTime: false, + format: 'MM-dd-yyyy HH:mm', + value: APIDate, + }; + const { getByText } = renderWithTheme(); + + getByText('07-20-2018 04:23'); + }); + + it('should format the time based on the specified format only pt2', () => { + const props = { displayTime: true, format: 'MM-dd-yyyy', value: APIDate }; + const { getByText } = renderWithTheme(); + + getByText('07-20-2018'); + }); + describe('Non-humanized dates', () => { it('should be displayed in 24-hour ISO format', () => { const props = { humanizeCutoff: undefined, value: APIDate }; diff --git a/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.tsx b/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.tsx index e230c285dcd..d40e6deabb7 100644 --- a/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.tsx +++ b/packages/manager/src/components/DateTimeDisplay/DateTimeDisplay.tsx @@ -5,11 +5,25 @@ import { useProfile } from 'src/queries/profile'; import { TimeInterval, formatDate } from 'src/utilities/formatDate'; export interface DateTimeDisplayProps { + /** + * Additional styles to apply to the root element + */ className?: string; + /** + * If true displays time component of the date and time provided + */ displayTime?: boolean; + /** + * String that specifies a luxon compatible format to use + */ format?: string; + /** + * If the date and time provided is within the designated time frame then the date is displayed as a relative date + */ humanizeCutoff?: TimeInterval; - styles?: React.CSSProperties; + /** + * The date and time string to display + */ value: string; } @@ -17,7 +31,7 @@ const DateTimeDisplay = (props: DateTimeDisplayProps) => { const { className, displayTime, format, humanizeCutoff, value } = props; const { data: profile } = useProfile(); return ( - + {formatDate(value, { displayTime, format, diff --git a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.stories.mdx b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.stories.mdx deleted file mode 100644 index da7bda23c47..00000000000 --- a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.stories.mdx +++ /dev/null @@ -1,44 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs'; -import TextFieldExample from './StoryComponents/TextFieldExample'; - - - -export const list = [ - 'apples', - 'oranges', - 'grapes', - 'walruses', - 'keyboards', - 'chairs', - 'speakers', - 'ecumenical council number two', -]; - -export const Template = (args) => { - return ( - - ); - }; - -# Search -### Text Field - - - {Template.bind({})} - - - - diff --git a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.stories.tsx b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.stories.tsx new file mode 100644 index 00000000000..42e8d540205 --- /dev/null +++ b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.stories.tsx @@ -0,0 +1,94 @@ +import { action } from '@storybook/addon-actions'; +import * as React from 'react'; + +import { DebouncedSearchTextField } from './DebouncedSearchTextField'; + +import type { Meta, StoryObj } from '@storybook/react'; + +type Story = StoryObj; + +const SEARCH_FOR_SOMETHING = 'Search for something'; + +const exampleList = [ + 'apples', + 'oranges', + 'grapes', + 'walruses', + 'keyboards', + 'chairs', + 'speakers', + 'ecumenical council number two', +]; + +export const Default: Story = { + args: { + debounceTime: 400, + hideLabel: true, + isSearching: true, + label: SEARCH_FOR_SOMETHING, + onSearch: action('searching'), + placeholder: SEARCH_FOR_SOMETHING, + value: 'searching', + }, + render: (args) => , +}; + +export const LiveSearchExample: Story = { + render: () => { + const SearchTextFieldWrapper = () => { + const [list, setList] = React.useState([...exampleList]); + const [isSearching, setIsSearching] = React.useState(false); + + const handleSearch = async (value: string) => { + setIsSearching(true); + action('searching')(value); + const res: string[] = await new Promise((resolve) => { + setTimeout(() => { + if (!value.trim()) { + return resolve(exampleList); + } + const filteredList = list.filter((eachVal: string) => + eachVal.includes(value.toLowerCase()) + ); + return resolve(filteredList); + }, 800); + }); + action('result')(res); + setIsSearching(false); + setList(res); + }; + + return ( + <> + +
    + {list.map((eachThing: string) => { + return ( +
  • + {eachThing} +
  • + ); + })} +
+ + ); + }; + + return ; + }, +}; + +const meta: Meta = { + component: DebouncedSearchTextField, + title: 'Components/Search', +}; + +export default meta; diff --git a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx index 4b3c4d47a00..fa8759bf210 100644 --- a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx +++ b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextField.tsx @@ -7,12 +7,22 @@ import { InputAdornment } from 'src/components/InputAdornment'; import { TextField, TextFieldProps } from 'src/components/TextField'; import { usePrevious } from 'src/hooks/usePrevious'; -interface DebouncedSearchProps extends TextFieldProps { +export interface DebouncedSearchProps extends TextFieldProps { className?: string; + /** + * Interval in milliseconds of time that passes before search queries are accepted. + * @default 400 + */ debounceTime?: number; defaultValue?: string; hideLabel?: boolean; + /** + * Determines if the textbox is currently searching for inputted query + */ isSearching?: boolean; + /** + * Function to perform when searching for query + */ onSearch: (query: string) => void; placeholder?: string; } diff --git a/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextfield.test.tsx b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextfield.test.tsx new file mode 100644 index 00000000000..99d1b375924 --- /dev/null +++ b/packages/manager/src/components/DebouncedSearchTextField/DebouncedSearchTextfield.test.tsx @@ -0,0 +1,87 @@ +import userEvent from '@testing-library/user-event'; +import { debounce } from 'lodash'; +import * as React from 'react'; + +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { DebouncedSearchTextField } from './DebouncedSearchTextField'; + +vi.useFakeTimers(); + +const labelVal = 'Search textfield label'; +const textfieldId = 'textfield-input'; +const props = { + isSearching: false, + label: labelVal, + onSearch: vi.fn(), +}; + +describe('Debounced Search Text Field', () => { + it('renders the search field', () => { + const screen = renderWithTheme(); + + const label = screen.getByText(labelVal); + const textfield = screen.getByTestId(textfieldId); + const searchIcon = screen.getByTestId('SearchIcon'); + + expect(label).toBeVisible(); + expect(textfield).toBeVisible(); + expect(textfield).toEqual( + screen.container.querySelector('[placeholder="Filter by query"]') + ); + expect(searchIcon).toBeVisible(); + + // circle icon is not visible + const circleIcon = screen.queryByTestId('circle-progress'); + expect(circleIcon).not.toBeInTheDocument(); + }); + + it('renders a loading icon if isSearching is true', () => { + const screen = renderWithTheme( + + ); + + const circleIcon = screen.queryByTestId('circle-progress'); + expect(circleIcon).toBeInTheDocument(); + }); + + it('calls isSearching', () => { + const debouncedOnSearch = debounce(props.onSearch, 250); + const screen = renderWithTheme( + + ); + + const textfield = screen.getByTestId(textfieldId); + userEvent.type(textfield, 'test'); + vi.runAllTimers(); + expect(props.onSearch).toHaveBeenCalled(); + }); + + it('renders the expected placeholder', () => { + const screen = renderWithTheme( + + ); + + const placeholderTextfield = screen.container.querySelector( + '[placeholder="this is a placeholder"]' + ); + expect(placeholderTextfield).toEqual(screen.getByTestId(textfieldId)); + }); + + it('hides the label', () => { + const screen = renderWithTheme( + + ); + + const label = screen.queryByText(labelVal); + expect(label).toBeInTheDocument(); + expect(label?.className).toContain('visually-hidden'); + }); +}); diff --git a/packages/manager/src/components/DebouncedSearchTextField/StoryComponents/TextFieldExample.tsx b/packages/manager/src/components/DebouncedSearchTextField/StoryComponents/TextFieldExample.tsx deleted file mode 100644 index 535422e06ee..00000000000 --- a/packages/manager/src/components/DebouncedSearchTextField/StoryComponents/TextFieldExample.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { action } from '@storybook/addon-actions'; -import * as React from 'react'; - -import { DebouncedSearchTextField } from '../DebouncedSearchTextField'; - -interface Props { - list: string[]; -} - -interface State { - isSearching: boolean; - list: string[]; -} - -class Example extends React.Component { - render() { - return ( - - -
    - {this.state.list.map((eachThing: string) => { - return ( -
  • - {eachThing} -
  • - ); - })} -
-
- ); - } - - handleSearch = (value: string) => { - this.setState({ isSearching: true }); - const { list } = this.state; - action('searching')(value); - return new Promise((resolve) => { - setTimeout(() => { - if (!value.trim()) { - return resolve(this.props.list); - } - const filteredList = list.filter((eachVal) => - eachVal.includes(value.toLowerCase()) - ); - return resolve(filteredList); - }, 800); - }).then((res: string[]) => { - action('result')(res); - this.setState({ - isSearching: false, - list: res, - }); - }); - }; - - state: State = { - isSearching: false, - list: this.props.list, - }; -} - -export default Example; diff --git a/packages/manager/src/components/DownloadTooltip.tsx b/packages/manager/src/components/DownloadTooltip.tsx index dbc5834a67c..1b8a543f3ed 100644 --- a/packages/manager/src/components/DownloadTooltip.tsx +++ b/packages/manager/src/components/DownloadTooltip.tsx @@ -1,6 +1,5 @@ import { Theme } from '@mui/material/styles'; -import { makeStyles } from '@mui/styles'; -import classNames from 'classnames'; +import { makeStyles } from 'tss-react/mui'; import * as React from 'react'; import FileDownload from 'src/assets/icons/download.svg'; @@ -32,7 +31,7 @@ interface Props { text: string; } -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles()((theme: Theme) => ({ displayText: { color: theme.textColors.linkActiveLight, marginLeft: 6, @@ -65,7 +64,7 @@ const useStyles = makeStyles((theme: Theme) => ({ })); export const DownloadTooltip = (props: Props) => { - const classes = useStyles(); + const { classes, cx } = useStyles(); const { className, displayText, fileName, onClickCallback, text } = props; @@ -79,10 +78,13 @@ export const DownloadTooltip = (props: Props) => { return ( + + setQuery('')} + size="small" + sx={{ padding: 'unset' }} + > + + + + ), + }} + hideLabel + inputId={`configuration-${configurationIndex}-service-target-filter`} + label="Filter" + onChange={(e) => setQuery(e.target.value)} + placeholder="Filter" + value={query} + /> + + + + + Service Target Label + Endpoints + Algorithm + Health Checks + + + + + {configuration.service_targets.length === 0 && ( + + )} + {configuration.service_targets + .filter((serviceTarget) => { + if (query) { + return serviceTarget.label.includes(query); + } + return true; + }) + .map((serviceTarget, index) => ( + + {serviceTarget.label} + + {serviceTarget.endpoints.length === 0 ? ( + 0 + ) : ( + + {serviceTarget.endpoints.map( + ({ ip, port }, index) => ( + + {ip}:{port} + + ) + )} + + } + displayText={String(serviceTarget.endpoints.length)} + minWidth={100} + /> + )} + + + {serviceTarget.load_balancing_policy.replace('_', ' ')} + + + {serviceTarget.healthcheck ? 'Yes' : 'No'} + + + + handlers.handleEditServiceTarget( + index, + configurationIndex + ), + title: 'Edit', + }, + { + onClick: () => handleRemoveServiceTarget(index), + title: 'Remove', + }, + ]} + ariaLabel={`Action Menu for Service Target ${serviceTarget.label}`} + /> + + + ))} + +
+ + + ); +}; diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/EditRouteDrawer.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/EditRouteDrawer.tsx index e1d49a0170f..e66b51d24e3 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/EditRouteDrawer.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/EditRouteDrawer.tsx @@ -1,4 +1,5 @@ import { UpdateRoutePayload } from '@linode/api-v4'; +import { UpdateRouteSchema } from '@linode/validation'; import { useFormik, yupToFormErrors } from 'formik'; import React from 'react'; @@ -16,7 +17,6 @@ import { capitalize } from 'src/utilities/capitalize'; import { getFormikErrorsFromAPIErrors } from 'src/utilities/formikErrorUtils'; import type { Route } from '@linode/api-v4'; -import { UpdateRouteSchema } from '@linode/validation'; interface Props { loadbalancerId: number; diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RouteSelect.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RouteSelect.tsx index a599fcdfedf..c12db1e1d08 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RouteSelect.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RouteSelect.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { useLoadBalancerRoutesInfiniteQuery } from 'src/queries/aglb/routes'; +import { pluralize } from 'src/utilities/pluralize'; import type { Filter, Route } from '@linode/api-v4'; @@ -68,6 +69,13 @@ export const RouteSelect = (props: Props) => { ListboxProps={{ onScroll, }} + getOptionLabel={({ label, protocol, rules }) => + `${label} (${protocol.toUpperCase()} - ${pluralize( + 'rule', + 'rules', + rules.length + )})` + } onInputChange={(_, value, reason) => { if (reason === 'input') { setInputValue(value); diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.test.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.test.tsx new file mode 100644 index 00000000000..95491443e02 --- /dev/null +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.test.tsx @@ -0,0 +1,78 @@ +import React from 'react'; + +import { routeFactory } from 'src/factories'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { RuleDrawer } from './RuleDrawer'; + +const props = { + loadbalancerId: 1, + onClose: vi.fn(), + open: true, + route: routeFactory.build({ + protocol: 'http', + rules: [ + { + match_condition: { + hostname: 'www.acme.com', + match_field: 'path_prefix', + match_value: '/A/*', + session_stickiness_cookie: 'my-cookie', + session_stickiness_ttl: 8, + }, + service_targets: [ + { + id: 1, + label: 'my-service-target', + percentage: 100, + }, + ], + }, + ], + }), +}; + +describe('RuleDrawer', () => { + it('should be in create mode when no rule index is passed', () => { + const { getByText } = renderWithTheme( + + ); + + expect(getByText('Add Rule', { selector: 'h2' })).toBeVisible(); + }); + it('should be in edit mode when a serviceTarget is passed', () => { + const { getByText } = renderWithTheme( + + ); + + expect(getByText('Edit Rule')).toBeVisible(); + }); + it('should populate fields if we are editing', () => { + const { getByLabelText } = renderWithTheme( + + ); + + const hostnameField = getByLabelText('Hostname (optional)'); + expect(hostnameField).toHaveDisplayValue( + props.route.rules[0].match_condition.hostname! + ); + + const matchTypeField = getByLabelText('Match Type'); + expect(matchTypeField).toHaveDisplayValue('Path'); + + const matchValueField = getByLabelText('Match Value'); + expect(matchValueField).toHaveDisplayValue( + props.route.rules[0].match_condition.match_value + ); + + const cookieField = getByLabelText('Cookie Key'); + expect(cookieField).toHaveDisplayValue( + props.route.rules[0].match_condition.session_stickiness_cookie! + ); + + const ttlField = getByLabelText('Stickiness TTL'); + expect(ttlField).toHaveDisplayValue( + String(props.route.rules[0].match_condition.session_stickiness_ttl) + ); + }); +}); diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx index fee6152e6c2..d204c638a17 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/RuleDrawer.tsx @@ -27,6 +27,7 @@ import { TimeUnit, defaultServiceTarget, defaultTTL, + defaultTTLUnit, getIsSessionStickinessEnabled, getNormalizedRulePayload, initialValues, @@ -74,7 +75,7 @@ export const RuleDrawer = (props: Props) => { reset, } = useLoadBalancerRouteUpdateMutation(loadbalancerId, route?.id ?? -1); - const [ttlUnit, setTTLUnit] = useState('hour'); + const [ttlUnit, setTTLUnit] = useState(defaultTTLUnit); const formik = useFormik({ enableReinitialize: true, @@ -121,7 +122,7 @@ export const RuleDrawer = (props: Props) => { _onClose(); formik.resetForm(); reset(); - setTTLUnit('hour'); + setTTLUnit(defaultTTLUnit); }; const onAddServiceTarget = () => { @@ -463,11 +464,9 @@ export const RuleDrawer = (props: Props) => { /> { - const currentTTLUnit = ttlUnit; - const factor = timeUnitFactorMap[option.key] / - timeUnitFactorMap[currentTTLUnit]; + timeUnitFactorMap[ttlUnit]; setTTLUnit(option.key); @@ -504,6 +503,7 @@ export const RuleDrawer = (props: Props) => { primaryButtonProps={{ label: isEditMode ? 'Save' : 'Add Rule', loading: formik.isSubmitting || isLoading, + disabled: isEditMode && !formik.dirty, type: 'submit', }} secondaryButtonProps={{ diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts index 1367c26260d..21d71f52f08 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Routes/utils.ts @@ -43,6 +43,8 @@ export const defaultServiceTarget = { percentage: 100, }; +export const defaultTTLUnit = 'second'; + export const initialValues = { match_condition: { hostname: '', @@ -76,11 +78,10 @@ export const getNormalizedRulePayload = (rule: RulePayload) => ({ }); export const timeUnitFactorMap = { - millisecond: 1, - second: 1000, - minute: 60000, - hour: 3_600_000, - day: 86_400_000, + second: 1, + minute: 60, + hour: 3_600, + day: 86_400, }; export type TimeUnit = keyof typeof timeUnitFactorMap; @@ -93,7 +94,7 @@ export const timeUnitOptions = Object.keys(timeUnitFactorMap).map( }) ); -export const defaultTTL = timeUnitFactorMap['hour'] * 8; +export const defaultTTL = timeUnitFactorMap['hour'] * 1; /** * Routes can be `http` or `tcp`. diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.test.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.test.tsx new file mode 100644 index 00000000000..6378f95333b --- /dev/null +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.test.tsx @@ -0,0 +1,39 @@ +import React from 'react'; + +import { serviceTargetFactory } from 'src/factories'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { ServiceTargetDrawer } from './ServiceTargetDrawer'; + +const props = { + loadbalancerId: 1, + onClose: vi.fn(), + open: true, +}; + +describe('ServiceTargetDrawer', () => { + it('should be in create mode when no serviceTarget is passed', () => { + const { getByText } = renderWithTheme(); + + expect(getByText('Add a Service Target')).toBeVisible(); + }); + it('should be in edit mode when a serviceTarget is passed', () => { + const serviceTarget = serviceTargetFactory.build(); + + const { getByText } = renderWithTheme( + + ); + + expect(getByText(`Edit ${serviceTarget.label}`)).toBeVisible(); + }); + it('should populate TextFields with data if we are editing', () => { + const serviceTarget = serviceTargetFactory.build(); + + const { getByLabelText } = renderWithTheme( + + ); + + const labelTextField = getByLabelText('Service Target Label'); + expect(labelTextField).toHaveDisplayValue(serviceTarget.label); + }); +}); diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx index bdcf878bdf5..cd02f396ccd 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetDrawer.tsx @@ -224,23 +224,29 @@ export const ServiceTargetDrawer = (props: Props) => { onRemove={onRemoveEndpoint} /> - - - Service Target CA Certificate - - - - formik.setFieldValue('certificate_id', cert?.id ?? null) - } - errorText={formik.errors.certificate_id} - filter={{ type: 'ca' }} - loadbalancerId={loadbalancerId} - value={formik.values.certificate_id} - /> + {formik.values.protocol === 'https' && ( + <> + + + + Service Target CA Certificate + + + + + formik.setFieldValue('certificate_id', cert?.id ?? null) + } + errorText={formik.errors.certificate_id} + filter={{ type: 'ca' }} + loadbalancerId={loadbalancerId} + value={formik.values.certificate_id} + /> + + )} Health Checks diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetSelect.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetSelect.tsx index 139159599f9..b9055069296 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetSelect.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/ServiceTargetSelect.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { Autocomplete } from 'src/components/Autocomplete/Autocomplete'; import { TextFieldProps } from 'src/components/TextField'; import { useLoadBalancerServiceTargetsInfiniteQuery } from 'src/queries/aglb/serviceTargets'; +import { pluralize } from 'src/utilities/pluralize'; import type { Filter, ServiceTarget } from '@linode/api-v4'; import type { SxProps } from '@mui/material'; @@ -87,6 +88,13 @@ export const ServiceTargetSelect = (props: Props) => { ListboxProps={{ onScroll, }} + getOptionLabel={({ endpoints, label, protocol }) => + `${label} (${protocol.toUpperCase()} - ${pluralize( + 'endpoint', + 'endpoints', + endpoints.length + )})` + } inputValue={ selectedServiceTarget ? selectedServiceTarget.label : inputValue } @@ -96,6 +104,7 @@ export const ServiceTargetSelect = (props: Props) => { } }} errorText={error?.[0].reason ?? errorText} + filterOptions={(x) => x} label={label ?? 'Service Target'} loading={isLoading} noMarginTop diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/constants.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/constants.tsx index e8e0b5d6590..a53a2314102 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/constants.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/ServiceTargets/constants.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { Box } from 'src/components/Box'; import { Stack } from 'src/components/Stack'; import { Typography } from 'src/components/Typography'; @@ -133,13 +134,13 @@ export const SERVICE_TARGET_COPY = { 'The number of consecutive health checks that must fail to consider a service target as unhealthy. Minimum value is 1.', }, Protocol: ( - + The protocol this target is configured to serve.
  • The HTTP and TCP protocols do not support TLS certificates.
  • HTTPS requires TLS certificates.
-
+ ), }, }; diff --git a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Label.tsx b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Label.tsx index c46f29ae780..77276e4062b 100644 --- a/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Label.tsx +++ b/packages/manager/src/features/LoadBalancers/LoadBalancerDetail/Settings/Label.tsx @@ -1,10 +1,10 @@ -import { Stack } from 'src/components/Stack'; import { useFormik } from 'formik'; import React from 'react'; import { Box } from 'src/components/Box'; import { Button } from 'src/components/Button/Button'; import { Paper } from 'src/components/Paper'; +import { Stack } from 'src/components/Stack'; import { TextField } from 'src/components/TextField'; import { useLoadBalancerMutation, @@ -44,7 +44,12 @@ export const Label = ({ loadbalancerId }: Props) => { value={formik.values.label} /> - diff --git a/packages/manager/src/features/LoadBalancers/constants.ts b/packages/manager/src/features/LoadBalancers/constants.ts index f5fa62d1ad4..063070fcd9e 100644 --- a/packages/manager/src/features/LoadBalancers/constants.ts +++ b/packages/manager/src/features/LoadBalancers/constants.ts @@ -12,6 +12,7 @@ export const AGLB_DOCS_TLS_CERTIFICATE = 'https://deploy-preview-14--roaring-gelato-12dc9e.netlify.app/docs/products/networking/global-loadbalancer/guides/certificates/'; export const AGLB_DOCS = { + Certificates: `${AGLB_DOCS_URL}/docs/products/networking/global-loadbalancer/guides/certificates/#service-target-certificates`, Developers: `${AGLB_DOCS_URL}/docs/products/networking/global-loadbalancer/developers`, GettingStarted: `${AGLB_DOCS_URL}/docs/products/networking/global-loadbalancer/get-started`, Guides: `${AGLB_DOCS_URL}/docs/products/networking/global-loadbalancer/guides`, diff --git a/packages/manager/src/features/Longview/LongviewLanding/LongviewClientInstructions.tsx b/packages/manager/src/features/Longview/LongviewLanding/LongviewClientInstructions.tsx index fcd31e2f2be..945e0062d64 100644 --- a/packages/manager/src/features/Longview/LongviewLanding/LongviewClientInstructions.tsx +++ b/packages/manager/src/features/Longview/LongviewLanding/LongviewClientInstructions.tsx @@ -1,14 +1,14 @@ +import Grid from '@mui/material/Unstable_Grid2/Grid2'; import { useTheme } from '@mui/material/styles'; import * as React from 'react'; import { EditableEntityLabel } from 'src/components/EditableEntityLabel/EditableEntityLabel'; -import { Grid } from 'src/components/Grid'; import { Paper } from 'src/components/Paper'; import { DispatchProps } from 'src/containers/longview.container'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import { InstallationInstructions } from '../shared/InstallationInstructions'; -import { LongviewActionMenu, ActionHandlers } from './LongviewActionMenu'; +import { ActionHandlers, LongviewActionMenu } from './LongviewActionMenu'; import { RestrictedUserLabel } from './RestrictedUserLabel'; interface Props extends ActionHandlers { @@ -51,49 +51,43 @@ export const LongviewClientInstructions = (props: Props) => { return ( - - - - {userCanModifyClient ? ( - - ) : ( - - )} - - - + + {userCanModifyClient ? ( + - + ) : ( + + )} + + + - + - + ({ - boxSizing: 'border-box', - margin: 0, - padding: theme.spacing(1), - [theme.breakpoints.down('md')]: { - marginBottom: 30, - }, - }) -); diff --git a/packages/manager/src/features/Longview/LongviewLanding/LongviewClientRow.tsx b/packages/manager/src/features/Longview/LongviewLanding/LongviewClientRow.tsx index 81067596e43..4e2c6d9b3a4 100644 --- a/packages/manager/src/features/Longview/LongviewLanding/LongviewClientRow.tsx +++ b/packages/manager/src/features/Longview/LongviewLanding/LongviewClientRow.tsx @@ -1,9 +1,8 @@ import { Grant } from '@linode/api-v4/lib/account'; -import { useTheme } from '@mui/material/styles'; +import { default as Grid } from '@mui/material/Unstable_Grid2/Grid2'; import * as React from 'react'; import { compose } from 'recompose'; -import { Grid } from 'src/components/Grid'; import { Paper } from 'src/components/Paper'; import withLongviewClients, { DispatchProps, @@ -20,10 +19,9 @@ import { NetworkGauge } from './Gauges/Network'; import { RAMGauge } from './Gauges/RAM'; import { StorageGauge } from './Gauges/Storage'; import { SwapGauge } from './Gauges/Swap'; -import { LongviewActionMenu, ActionHandlers } from './LongviewActionMenu'; +import { ActionHandlers, LongviewActionMenu } from './LongviewActionMenu'; import { LongviewClientHeader } from './LongviewClientHeader'; import { LongviewClientInstructions } from './LongviewClientInstructions'; -import { StyledGrid } from './LongviewClientRow.styles'; interface Props extends ActionHandlers { clientAPIKey: string; @@ -36,8 +34,6 @@ interface Props extends ActionHandlers { type CombinedProps = Props & LVDataProps & DispatchProps & GrantProps; const LongviewClientRow = (props: CombinedProps) => { - const theme = useTheme(); - const { clientAPIKey, clientID, @@ -88,11 +84,12 @@ const LongviewClientRow = (props: CombinedProps) => { return ( { + return { + marginBottom: theme.spacing(4), + }; }} + data-testid={clientID} > { container data-testid="longview-client-row" justifyContent="space-between" + padding={1} spacing={2} wrap="nowrap" > - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - + + diff --git a/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx b/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx index 82df424ddaf..8b8a871790a 100644 --- a/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx +++ b/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx @@ -56,7 +56,7 @@ const LinodePubKey = () => { const errorMessage = getErrorStringOrDefault(error); return ( - + ); } diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx index dc0a7959987..f503d36e2c0 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx @@ -4,13 +4,16 @@ import * as React from 'react'; import { useParams } from 'react-router-dom'; import PendingIcon from 'src/assets/icons/pending.svg'; +import { AreaChart } from 'src/components/AreaChart'; +import { Box } from 'src/components/Box'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; import { LineGraph } from 'src/components/LineGraph/LineGraph'; import MetricsDisplay from 'src/components/LineGraph/MetricsDisplay'; -import { Typography } from 'src/components/Typography'; import { Paper } from 'src/components/Paper'; +import { Typography } from 'src/components/Typography'; import { formatBitsPerSecond } from 'src/features/Longview/shared/utilities'; +import { useFlags } from 'src/hooks/useFlags'; import { NODEBALANCER_STATS_NOT_READY_API_MESSAGE, useNodeBalancerQuery, @@ -37,6 +40,8 @@ export const TablesPanel = () => { nodebalancer?.created ); + const flags = useFlags(); + const statsErrorString = error ? getAPIErrorOrDefault(error, 'Unable to load stats')[0].reason : undefined; @@ -80,24 +85,58 @@ export const TablesPanel = () => { const metrics = getMetrics(data); + let timeData = []; + // @TODO recharts: remove conditional code and delete old chart when we decide recharts is stable + if (flags.recharts) { + timeData = data.reduce((acc: any, point: any) => { + acc.push({ + Connections: point[1], + t: point[0], + }); + return acc; + }, []); + } + return ( - - - + {flags.recharts ? ( + + + + ) : ( + + + + )} { const renderTrafficChart = () => { const trafficIn = stats?.data.traffic.in ?? []; const trafficOut = stats?.data.traffic.out ?? []; + const timeData = []; + + // @TODO recharts: remove conditional code and delete old chart when we decide recharts is stable + if (flags.recharts && trafficIn) { + for (let i = 0; i < trafficIn.length; i++) { + timeData.push({ + 'Traffic In': trafficIn[i][1], + 'Traffic Out': trafficOut[i][1], + t: trafficIn[i][0], + }); + } + } if (statsNotReadyError) { return ( @@ -152,26 +203,52 @@ export const TablesPanel = () => { return ( - + {flags.recharts ? ( + + + + ) : ( + + )} { return ( - - Graphs - + Graphs Connections (CXN/s, 5 min avg.) @@ -223,9 +298,14 @@ const StyledHeader = styled(Typography, { const StyledTitle = styled(Typography, { label: 'StyledTitle', })(({ theme }) => ({ + alignItems: 'center', + display: 'flex', [theme.breakpoints.down('lg')]: { marginLeft: theme.spacing(), }, + [theme.breakpoints.up('md')]: { + margin: `${theme.spacing(2)} 0`, + }, })); const StyledChart = styled('div', { @@ -240,21 +320,9 @@ const StyledBottomLegend = styled('div', { label: 'StyledBottomLegend', })(({ theme }) => ({ backgroundColor: theme.bg.offWhite, - border: `1px solid ${theme.color.border3}`, color: '#777', fontSize: 14, margin: `${theme.spacing(2)} ${theme.spacing(1)} ${theme.spacing(1)}`, - padding: 10, -})); - -const StyledgGraphControls = styled(Typography, { - label: 'StyledgGraphControls', -})(({ theme }) => ({ - alignItems: 'center', - display: 'flex', - [theme.breakpoints.up('md')]: { - margin: `${theme.spacing(2)} 0`, - }, })); const StyledPanel = styled(Paper, { diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.test.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.test.tsx index 6d59d3a05b6..4ab0ea4a8ab 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.test.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.test.tsx @@ -99,7 +99,9 @@ describe('NodeBalancerSelect', () => { await waitFor(() => { // The default no options message should be displayed when noOptionsMessage prop is not provided - expect(screen.getByText('No options')).toBeInTheDocument(); + expect( + screen.getByText('No available NodeBalancers') + ).toBeInTheDocument(); }); }); diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.tsx index 0fc3edd6a6d..100c84b6cf2 100644 --- a/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.tsx +++ b/packages/manager/src/features/NodeBalancers/NodeBalancerSelect.tsx @@ -150,6 +150,7 @@ export const NodeBalancerSelect = ( ChipProps={{ deleteIcon: }} PopperComponent={CustomPopper} clearOnBlur={false} + data-testid="add-nodebalancer-autocomplete" disableClearable={!clearable} disableCloseOnSelect={multiple} disablePortal={true} @@ -180,6 +181,6 @@ const getDefaultNoOptionsMessage = ( } else if (loading) { return 'Loading your NodeBalancers...'; } else { - return 'No options'; + return 'No available NodeBalancers'; } }; diff --git a/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx b/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx index 27a66428446..bf76d4729c7 100644 --- a/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx +++ b/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx @@ -22,6 +22,7 @@ import { TableBody } from 'src/components/TableBody'; import { TableCell } from 'src/components/TableCell'; import { TableHead } from 'src/components/TableHead'; import { TableRow } from 'src/components/TableRow'; +import { ObjectUploader } from 'src/components/Uploaders/ObjectUploader/ObjectUploader'; import { OBJECT_STORAGE_DELIMITER } from 'src/constants'; import { prefixToQueryKey, @@ -33,7 +34,6 @@ import { sendDownloadObjectEvent } from 'src/utilities/analytics'; import { getQueryParamFromQueryString } from 'src/utilities/queryParams'; import { truncateMiddle } from 'src/utilities/truncate'; -import { ObjectUploader } from '../ObjectUploader/ObjectUploader'; import { deleteObject as _deleteObject } from '../requests'; import { displayName, diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRegions.test.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRegions.test.tsx new file mode 100644 index 00000000000..81062f8a955 --- /dev/null +++ b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRegions.test.tsx @@ -0,0 +1,60 @@ +import { screen } from '@testing-library/react'; +import React from 'react'; + +import { regionFactory } from 'src/factories'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { BucketRegions } from './BucketRegions'; + +// Mock the useRegionsQuery function +const mockRegions = { + data: [ + regionFactory.build({ + capabilities: ['Linodes'], + country: 'us', + id: 'us-1', + label: 'US Location', + }), + , + regionFactory.build({ + capabilities: ['Linodes'], + country: 'us', + id: 'us-2', + label: 'US Location 2', + }), + ], + // Mock data as needed + error: null, +}; +vi.mock('src/queries/regions', () => ({ + useRegionsQuery: vi.fn(() => mockRegions), +})); + +describe('BucketRegions', () => { + it('renders correctly', () => { + renderWithTheme( + + ); + + // Add assertions based on your component's expected behavior + expect(screen.getByLabelText('Region')).toBeInTheDocument(); + expect(screen.getByPlaceholderText('Select a Region')).toBeInTheDocument(); + }); + + it('displays an error message', () => { + renderWithTheme( + + ); + + expect(screen.getByText('Some error message')).toBeInTheDocument(); + }); +}); diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRegions.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRegions.tsx new file mode 100644 index 00000000000..634b01790e7 --- /dev/null +++ b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRegions.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; + +import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; +import { useRegionsQuery } from 'src/queries/regions'; + +interface Props { + disabled?: boolean; + error?: string; + onBlur: (e: any) => void; + onChange: (value: string) => void; + required?: boolean; + selectedRegion: null | string; +} + +export const BucketRegions = (props: Props) => { + const { disabled, error, onBlur, onChange, required, selectedRegion } = props; + + const { data: regions, error: regionsError } = useRegionsQuery(); + + // Error could be: 1. General Regions error, 2. Field error, 3. Nothing + const errorText = error || regionsError?.[0]?.reason; + + return ( + onChange(id)} + isClearable={false} + label="Region" + onBlur={onBlur} + placeholder="Select a Region" + regions={regions ?? []} + required={required} + selectedId={selectedRegion} + /> + ); +}; diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketTable.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketTable.tsx index 6864ec79246..f5fd6bdea87 100644 --- a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketTable.tsx +++ b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketTable.tsx @@ -137,10 +137,10 @@ const RenderData: React.FC = (props) => { return ( // eslint-disable-next-line react/jsx-no-useless-fragment <> - {data.map((bucket) => ( + {data.map((bucket, index) => ( onDetails(bucket)} onRemove={() => onRemove(bucket)} /> diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/OMC_CreateBucketDrawer.styles.ts b/packages/manager/src/features/ObjectStorage/BucketLanding/OMC_CreateBucketDrawer.styles.ts new file mode 100644 index 00000000000..89b3f7a8667 --- /dev/null +++ b/packages/manager/src/features/ObjectStorage/BucketLanding/OMC_CreateBucketDrawer.styles.ts @@ -0,0 +1,10 @@ +import { styled } from '@mui/material/styles'; + +import { EUAgreementCheckbox } from 'src/features/Account/Agreements/EUAgreementCheckbox'; + +export const StyledEUAgreementCheckbox = styled(EUAgreementCheckbox, { + label: 'StyledEUAgreementCheckbox', +})(({ theme }) => ({ + marginButton: theme.spacing(3), + marginTop: theme.spacing(3), +})); diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/OMC_CreateBucketDrawer.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/OMC_CreateBucketDrawer.tsx new file mode 100644 index 00000000000..c1d09d8b7ab --- /dev/null +++ b/packages/manager/src/features/ObjectStorage/BucketLanding/OMC_CreateBucketDrawer.tsx @@ -0,0 +1,180 @@ +import { useFormik } from 'formik'; +import * as React from 'react'; + +import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; +import { Drawer } from 'src/components/Drawer'; +import { Notice } from 'src/components/Notice/Notice'; +import { TextField } from 'src/components/TextField'; +import { + reportAgreementSigningError, + useAccountAgreements, + useMutateAccountAgreements, +} from 'src/queries/accountAgreements'; +import { useAccountSettings } from 'src/queries/accountSettings'; +import { + useCreateBucketMutation, + useObjectStorageBuckets, + useObjectStorageClusters, +} from 'src/queries/objectStorage'; +import { useProfile } from 'src/queries/profile'; +import { useRegionsQuery } from 'src/queries/regions'; +import { sendCreateBucketEvent } from 'src/utilities/analytics'; +import { getErrorMap } from 'src/utilities/errorUtils'; +import { getGDPRDetails } from 'src/utilities/formatRegion'; + +import { EnableObjectStorageModal } from '../EnableObjectStorageModal'; +import { BucketRegions } from './BucketRegions'; +import { StyledEUAgreementCheckbox } from './OMC_CreateBucketDrawer.styles'; +import { OveragePricing } from './OveragePricing'; + +interface Props { + isOpen: boolean; + onClose: () => void; +} + +export const OMC_CreateBucketDrawer = (props: Props) => { + const { data: profile } = useProfile(); + const { isOpen, onClose } = props; + const isRestrictedUser = profile?.restricted; + const { data: regions } = useRegionsQuery(); + // @TODO OBJ Multicluster - clusters will likely to be replaced with regions and will be taken care in future tickets. + const { data: clusters } = useObjectStorageClusters(); + const { data: buckets } = useObjectStorageBuckets(clusters); + + const { + error, + isLoading, + mutateAsync: createBucket, + reset, + } = useCreateBucketMutation(); + const { data: agreements } = useAccountAgreements(); + const { mutateAsync: updateAccountAgreements } = useMutateAccountAgreements(); + const { data: accountSettings } = useAccountSettings(); + const [isEnableObjDialogOpen, setIsEnableObjDialogOpen] = React.useState( + false + ); + const [hasSignedAgreement, setHasSignedAgreement] = React.useState( + false + ); + + const formik = useFormik({ + initialValues: { + label: '', + region: '', + }, + async onSubmit(values) { + await createBucket(values); + sendCreateBucketEvent(values.region); + if (hasSignedAgreement) { + updateAccountAgreements({ + eu_model: true, + }).catch(reportAgreementSigningError); + } + onClose(); + }, + validate(values) { + reset(); + const doesBucketExist = buckets?.buckets.find( + (b) => b.label === values.label && b.region === values.region + ); + if (doesBucketExist) { + return { + label: + 'A bucket with this label already exists in your selected region', + }; + } + return {}; + }, + }); + + const onSubmit: React.FormEventHandler = (e) => { + e.preventDefault(); + if (accountSettings?.object_storage === 'active') { + formik.handleSubmit(e); + } else { + setIsEnableObjDialogOpen(true); + } + }; + + React.useEffect(() => { + if (isOpen) { + formik.resetForm(); + reset(); + } + }, [isOpen]); + + const { showGDPRCheckbox } = getGDPRDetails({ + agreements, + profile, + regions, + selectedRegionId: formik.values.region ?? '', + }); + + const errorMap = getErrorMap(['label', 'cluster'], error); + + return ( + +
+ {isRestrictedUser && ( + + )} + {Boolean(errorMap.none) && ( + + )} + + formik.setFieldValue('region', value)} + required + selectedRegion={formik.values.region} + /> + {formik.values.region && ( + + )} + {showGDPRCheckbox ? ( + setHasSignedAgreement(e.target.checked)} + /> + ) : null} + + + setIsEnableObjDialogOpen(false)} + open={isEnableObjDialogOpen} + regionId={formik.values.region} + /> + +
+ ); +}; diff --git a/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx b/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx index bbb3dfa37b0..34a109ec00e 100644 --- a/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx +++ b/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx @@ -22,9 +22,11 @@ import { useObjectStorageBuckets, useObjectStorageClusters, } from 'src/queries/objectStorage'; +import { isFeatureEnabled } from 'src/utilities/accountCapabilities'; import { MODE } from './AccessKeyLanding/types'; import { CreateBucketDrawer } from './BucketLanding/CreateBucketDrawer'; +import { OMC_CreateBucketDrawer } from './BucketLanding/OMC_CreateBucketDrawer'; const BucketLanding = React.lazy(() => import('./BucketLanding/BucketLanding').then((module) => ({ @@ -45,7 +47,11 @@ export const ObjectStorageLanding = () => { tab?: 'access-keys' | 'buckets'; }>(); const isCreateBucketOpen = tab === 'buckets' && action === 'create'; - const { _isRestrictedUser, accountSettings } = useAccountManagement(); + const { + _isRestrictedUser, + account, + accountSettings, + } = useAccountManagement(); const { data: objectStorageClusters } = useObjectStorageClusters(); const { data: objectStorageBucketsResponse, @@ -80,6 +86,12 @@ export const ObjectStorageLanding = () => { const flags = useFlags(); + const isObjMultiClusterFlagEnabled = isFeatureEnabled( + 'Object Storage Access Key Regions', + Boolean(flags.objMultiCluster), + account?.capabilities ?? [] + ); + const objPromotionalOffers = ( flags.promotionalOffers ?? [] ).filter((promotionalOffer) => @@ -159,10 +171,17 @@ export const ObjectStorageLanding = () => { - history.replace('/object-storage/buckets')} - /> + {isObjMultiClusterFlagEnabled ? ( + history.replace('/object-storage/buckets')} + /> + ) : ( + history.replace('/object-storage/buckets')} + /> + )}
); diff --git a/packages/manager/src/features/OneClickApps/AppDetailDrawer.tsx b/packages/manager/src/features/OneClickApps/AppDetailDrawer.tsx index e69fff73aab..16d9851948c 100644 --- a/packages/manager/src/features/OneClickApps/AppDetailDrawer.tsx +++ b/packages/manager/src/features/OneClickApps/AppDetailDrawer.tsx @@ -1,7 +1,7 @@ import Close from '@mui/icons-material/Close'; import Drawer from '@mui/material/Drawer'; import { Theme } from '@mui/material/styles'; -import { makeStyles } from '@mui/styles'; +import { makeStyles } from 'tss-react/mui'; import * as React from 'react'; import { Box } from 'src/components/Box'; @@ -16,7 +16,7 @@ import { mapStackScriptLabelToOCA } from './utils'; import type { OCA } from './types'; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles()((theme: Theme) => ({ appName: { color: '#fff !important', fontFamily: theme.font.bold, @@ -84,7 +84,7 @@ interface Props { export const AppDetailDrawer: React.FunctionComponent = (props) => { const { onClose, open, stackScriptLabel } = props; - const classes = useStyles(); + const { classes } = useStyles(); const { oneClickAppsDocsOverride } = useFlags(); const [selectedApp, setSelectedApp] = React.useState(null); diff --git a/packages/manager/src/features/OneClickApps/oneClickApps.ts b/packages/manager/src/features/OneClickApps/oneClickApps.ts index 07f7e37cfee..4fd73932de4 100644 --- a/packages/manager/src/features/OneClickApps/oneClickApps.ts +++ b/packages/manager/src/features/OneClickApps/oneClickApps.ts @@ -1141,7 +1141,8 @@ export const oneClickApps: OCA[] = [ 'Deploy MainConcept FFmpeg Plugins Demo through the Linode Marketplace', }, ], - summary: 'MainConcept FFmpeg Plugins Demo contains advanced video encoding tools.', + summary: + 'MainConcept FFmpeg Plugins Demo contains advanced video encoding tools.', website: 'https://www.mainconcept.com/ffmpeg', }, { @@ -1159,7 +1160,8 @@ export const oneClickApps: OCA[] = [ { href: 'https://www.linode.com/docs/products/tools/marketplace/guides/mainconcept-live-encoder-demo/', - title: 'Deploy MainConcept Live Encoder Demo through the Linode Marketplace', + title: + 'Deploy MainConcept Live Encoder Demo through the Linode Marketplace', }, ], summary: 'MainConcept Live Encoder is a real time video encoding engine.', diff --git a/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.test.tsx b/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.test.tsx index d31df383ce0..90fdb8b8ced 100644 --- a/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.test.tsx +++ b/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.test.tsx @@ -3,11 +3,25 @@ import userEvent from '@testing-library/user-event'; import * as React from 'react'; import { appTokenFactory } from 'src/factories'; +import { accountUserFactory } from 'src/factories/accountUsers'; import { rest, server } from 'src/mocks/testServer'; import { renderWithTheme } from 'src/utilities/testHelpers'; import { CreateAPITokenDrawer } from './CreateAPITokenDrawer'; +// Mock the useAccountUser hooks to immediately return the expected data, circumventing the HTTP request and loading state. +const queryMocks = vi.hoisted(() => ({ + useAccountUser: vi.fn().mockReturnValue({}), +})); + +vi.mock('src/queries/accountUsers', async () => { + const actual = await vi.importActual('src/queries/accountUsers'); + return { + ...actual, + useAccountUser: queryMocks.useAccountUser, + }; +}); + const props = { onClose: vi.fn(), open: true, @@ -38,6 +52,7 @@ describe('Create API Token Drawer', () => { expect(cancelBtn).toBeEnabled(); expect(cancelBtn).toBeVisible(); }); + it('Should see secret modal with secret when you type a label and submit the form successfully', async () => { server.use( rest.post('*/profile/tokens', (req, res, ctx) => { @@ -58,19 +73,48 @@ describe('Create API Token Drawer', () => { expect(props.showSecret).toBeCalledWith('secret-value') ); }); - it('Should default to read/write for all scopes', () => { + + it('Should default to None for all scopes', () => { const { getByLabelText } = renderWithTheme( ); - const selectAllReadWriteRadioButton = getByLabelText( - 'Select read/write for all' - ); - expect(selectAllReadWriteRadioButton).toBeChecked(); + const selectAllNonePermRadioButton = getByLabelText('Select none for all'); + expect(selectAllNonePermRadioButton).toBeChecked(); }); + it('Should default to 6 months for expiration', () => { const { getByText } = renderWithTheme(); getByText('In 6 months'); }); + + it('Should show the Child Account Access scope for a parent user account with the parent/child feature flag on', () => { + queryMocks.useAccountUser.mockReturnValue({ + data: accountUserFactory.build({ user_type: 'parent' }), + }); + + const { getByText } = renderWithTheme(, { + flags: { parentChildAccountAccess: true }, + }); + const childScope = getByText('Child Account Access'); + expect(childScope).toBeInTheDocument(); + }); + + it('Should not show the Child Account Access scope for a non-parent user account with the parent/child feature flag on', () => { + queryMocks.useAccountUser.mockReturnValue({ + data: accountUserFactory.build({ user_type: null }), + }); + + const { queryByText } = renderWithTheme( + , + { + flags: { parentChildAccountAccess: true }, + } + ); + + const childScope = queryByText('Child Account Access'); + expect(childScope).not.toBeInTheDocument(); + }); + it('Should close when Cancel is pressed', () => { const { getByText } = renderWithTheme(); const cancelButton = getByText(/Cancel/); diff --git a/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.tsx b/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.tsx index 87e1d178331..5ff85319184 100644 --- a/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.tsx +++ b/packages/manager/src/features/Profile/APITokens/CreateAPITokenDrawer.tsx @@ -5,6 +5,8 @@ import * as React from 'react'; import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; import { Drawer } from 'src/components/Drawer'; import Select, { Item } from 'src/components/EnhancedSelect/Select'; +import { FormControl } from 'src/components/FormControl'; +import { FormHelperText } from 'src/components/FormHelperText'; import { Notice } from 'src/components/Notice/Notice'; import { Radio } from 'src/components/Radio/Radio'; import { TableBody } from 'src/components/TableBody'; @@ -12,10 +14,11 @@ import { TableCell } from 'src/components/TableCell'; import { TableHead } from 'src/components/TableHead'; import { TableRow } from 'src/components/TableRow'; import { TextField } from 'src/components/TextField'; -import { FormControl } from 'src/components/FormControl'; -import { FormHelperText } from 'src/components/FormHelperText'; import { ISO_DATETIME_NO_TZ_FORMAT } from 'src/constants'; import { AccessCell } from 'src/features/ObjectStorage/AccessKeyLanding/AccessCell'; +import { useFlags } from 'src/hooks/useFlags'; +import { useAccountUser } from 'src/queries/accountUsers'; +import { useProfile } from 'src/queries/profile'; import { useCreatePersonalAccessTokenMutation } from 'src/queries/tokens'; import { getErrorMap } from 'src/utilities/errorUtils'; @@ -82,12 +85,17 @@ export const CreateAPITokenDrawer = (props: Props) => { const expiryTups = genExpiryTups(); const { onClose, open, showSecret } = props; + const flags = useFlags(); + const initialValues = { expiry: expiryTups[0][1], label: '', - scopes: scopeStringToPermTuples('*'), + scopes: scopeStringToPermTuples(''), }; + const { data: profile } = useProfile(); + const { data: user } = useAccountUser(profile?.username ?? ''); + const { error, isLoading, @@ -152,6 +160,27 @@ export const CreateAPITokenDrawer = (props: Props) => { return { label: expiryTup[0], value: expiryTup[1] }; }); + // Filter permissions for all users except parent user accounts. + const allPermissions = form.values.scopes; + const showFilteredPermissions = + (flags.parentChildAccountAccess && user?.user_type !== 'parent') || + Boolean(!flags.parentChildAccountAccess); + const filteredPermissions = allPermissions.filter( + (scopeTup) => basePermNameMap[scopeTup[0]] !== 'Child Account Access' + ); + // TODO: Parent/Child - remove this conditional once code is in prod. + // Note: We couldn't include 'child_account' in our list of permissions in utils + // because it needs to be feature-flagged. Therefore, we're manually adding it here. + if (flags.parentChildAccountAccess && user?.user_type !== null) { + const childAccountIndex = allPermissions.findIndex( + ([scope]) => scope === 'child_account' + ); + if (childAccountIndex === -1) { + allPermissions.push(['child_account', 0]); + } + basePermNameMap.child_account = 'Child Account Access'; + } + return ( {errorMap.none && } @@ -236,57 +265,59 @@ export const CreateAPITokenDrawer = (props: Props) => { /> - {form.values.scopes.map((scopeTup) => { - if (!basePermNameMap[scopeTup[0]]) { - return null; - } - return ( - - - {basePermNameMap[scopeTup[0]]} - - - - - - - - { + if (!basePermNameMap[scopeTup[0]]) { + return null; + } + return ( + - - - - ); - })} + + {basePermNameMap[scopeTup[0]]} + + + + + + + + + + + + ); + } + )} {errorMap.scopes && ( diff --git a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx index 5f2c0b8e7b3..547d97aa214 100644 --- a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx +++ b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.test.tsx @@ -1,12 +1,33 @@ import * as React from 'react'; import { appTokenFactory } from 'src/factories'; +import { accountUserFactory } from 'src/factories/accountUsers'; import { renderWithTheme } from 'src/utilities/testHelpers'; import { ViewAPITokenDrawer } from './ViewAPITokenDrawer'; import { basePerms } from './utils'; +// Mock the useAccountUser hooks to immediately return the expected data, circumventing the HTTP request and loading state. +const queryMocks = vi.hoisted(() => ({ + useAccountUser: vi.fn().mockReturnValue({}), +})); + +vi.mock('src/queries/accountUsers', async () => { + const actual = await vi.importActual('src/queries/accountUsers'); + return { + ...actual, + useAccountUser: queryMocks.useAccountUser, + }; +}); + +// TODO: Parent/Child - add back after API code is in prod. Replace basePerms with nonParentPerms. +// const nonParentPerms = basePerms.filter((value) => value !== 'child_account'); + const token = appTokenFactory.build({ label: 'my-token', scopes: '*' }); +const limitedToken = appTokenFactory.build({ + label: 'my-limited-token', + scopes: '', +}); const props = { onClose: vi.fn(), @@ -21,7 +42,7 @@ describe('View API Token Drawer', () => { expect(getByText(token.label)).toBeVisible(); }); - it('should all permissions as read/write with wildcard scopes', () => { + it('should show all permissions as read/write with wildcard scopes', () => { const { getByTestId } = renderWithTheme(); for (const permissionName of basePerms) { expect(getByTestId(`perm-${permissionName}`)).toHaveAttribute( @@ -31,6 +52,19 @@ describe('View API Token Drawer', () => { } }); + it('should show all permissions as none with no scopes', () => { + const { getByTestId } = renderWithTheme( + , + { flags: { parentChildAccountAccess: false } } + ); + for (const permissionName of basePerms) { + expect(getByTestId(`perm-${permissionName}`)).toHaveAttribute( + 'aria-label', + `This token has 0 access for ${permissionName}` + ); + } + }); + it('only account has read/write, all others are none', () => { const { getByTestId } = renderWithTheme( { ); } }); + + it('should show Child Account Access scope with read/write perms for a parent user account with the parent/child feature flag on', () => { + queryMocks.useAccountUser.mockReturnValue({ + data: accountUserFactory.build({ user_type: 'parent' }), + }); + + const { getByTestId, getByText } = renderWithTheme( + , + { + flags: { parentChildAccountAccess: true }, + } + ); + + const childScope = getByText('Child Account Access'); + // TODO: Parent/Child - confirm that this scope level shouldn't be 2 + const expectedScopeLevels = { + child_account: 0, + } as const; + const childPermissionName = 'child_account'; + + expect(childScope).toBeInTheDocument(); + expect(getByTestId(`perm-${childPermissionName}`)).toHaveAttribute( + 'aria-label', + `This token has ${expectedScopeLevels[childPermissionName]} access for ${childPermissionName}` + ); + }); + + it('should not show the Child Account Access scope for a non-parent user account with the parent/child feature flag on', () => { + queryMocks.useAccountUser.mockReturnValue({ + data: accountUserFactory.build({ user_type: null }), + }); + + const { queryByText } = renderWithTheme(, { + flags: { parentChildAccountAccess: true }, + }); + + const childScope = queryByText('Child Account Access'); + expect(childScope).not.toBeInTheDocument(); + }); }); diff --git a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.tsx b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.tsx index 12493e8ffa0..e85f302f54f 100644 --- a/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.tsx +++ b/packages/manager/src/features/Profile/APITokens/ViewAPITokenDrawer.tsx @@ -7,6 +7,9 @@ import { TableCell } from 'src/components/TableCell'; import { TableHead } from 'src/components/TableHead'; import { TableRow } from 'src/components/TableRow'; import { AccessCell } from 'src/features/ObjectStorage/AccessKeyLanding/AccessCell'; +import { useFlags } from 'src/hooks/useFlags'; +import { useAccountUser } from 'src/queries/accountUsers'; +import { useProfile } from 'src/queries/profile'; import { StyledAccessCell, @@ -24,7 +27,32 @@ interface Props { export const ViewAPITokenDrawer = (props: Props) => { const { onClose, open, token } = props; - const permissions = scopeStringToPermTuples(token?.scopes ?? ''); + const flags = useFlags(); + + const { data: profile } = useProfile(); + const { data: user } = useAccountUser(profile?.username ?? ''); + + const allPermissions = scopeStringToPermTuples(token?.scopes ?? ''); + + // Filter permissions for all users except parent user accounts. + const showFilteredPermissions = + (flags.parentChildAccountAccess && user?.user_type !== 'parent') || + Boolean(!flags.parentChildAccountAccess); + const filteredPermissions = allPermissions.filter( + (scopeTup) => basePermNameMap[scopeTup[0]] !== 'Child Account Access' + ); + // TODO: Parent/Child - remove this conditional once code is in prod. + // Note: We couldn't include 'child_account' in our list of permissions in utils + // because it needs to be feature-flagged. Therefore, we're manually adding it here. + if (flags.parentChildAccountAccess && user?.user_type !== null) { + const childAccountIndex = allPermissions.findIndex( + ([scope]) => scope === 'child_account' + ); + if (childAccountIndex === -1) { + allPermissions.push(['child_account', 0]); + } + basePermNameMap.child_account = 'Child Account Access'; + } return ( @@ -48,54 +76,56 @@ export const ViewAPITokenDrawer = (props: Props) => { - {permissions.map((scopeTup) => { - if (!basePermNameMap[scopeTup[0]]) { - return null; - } - return ( - - - {basePermNameMap[scopeTup[0]]} - - - null} - scope="0" - scopeDisplay={scopeTup[0]} - viewOnly={true} - /> - - { + if (!basePermNameMap[scopeTup[0]]) { + return null; + } + return ( + - null} - scope="1" - scopeDisplay={scopeTup[0]} - viewOnly={true} - /> - - - null} - scope="2" - scopeDisplay={scopeTup[0]} - viewOnly={true} - /> - - - ); - })} + + {basePermNameMap[scopeTup[0]]} + + + null} + scope="0" + scopeDisplay={scopeTup[0]} + viewOnly={true} + /> + + + null} + scope="1" + scopeDisplay={scopeTup[0]} + viewOnly={true} + /> + + + null} + scope="2" + scopeDisplay={scopeTup[0]} + viewOnly={true} + /> + + + ); + } + )} diff --git a/packages/manager/src/features/Profile/APITokens/utils.test.ts b/packages/manager/src/features/Profile/APITokens/utils.test.ts index 83181c2fbbf..9fe08a35819 100644 --- a/packages/manager/src/features/Profile/APITokens/utils.test.ts +++ b/packages/manager/src/features/Profile/APITokens/utils.test.ts @@ -26,6 +26,8 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('*'); const expected = [ ['account', 2], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 2], ['databases', 2], ['domains', 2], ['events', 2], @@ -49,6 +51,8 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples(''); const expected = [ ['account', 0], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 0], ['events', 0], @@ -73,6 +77,8 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:none'); const expected = [ ['account', 0], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 0], ['events', 0], @@ -97,6 +103,8 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_only'); const expected = [ ['account', 1], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 0], ['events', 0], @@ -121,6 +129,8 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_write'); const expected = [ ['account', 2], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 0], ['events', 0], @@ -147,6 +157,8 @@ describe('APIToken utils', () => { ); const expected = [ ['account', 0], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 1], ['events', 0], @@ -175,6 +187,8 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:none,tokens:read_write'); const expected = [ ['account', 2], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 0], ['events', 0], @@ -203,6 +217,8 @@ describe('APIToken utils', () => { const result = scopeStringToPermTuples('account:read_only,tokens:none'); const expected = [ ['account', 1], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 0], ['events', 0], @@ -227,6 +243,8 @@ describe('APIToken utils', () => { it('should return 0 if all scopes are 0', () => { const scopes: Permission[] = [ ['account', 0], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 0], ['events', 0], @@ -246,6 +264,8 @@ describe('APIToken utils', () => { it('should return 1 if all scopes are 1', () => { const scopes: Permission[] = [ ['account', 1], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 1], ['databases', 1], ['domains', 1], ['events', 1], @@ -265,6 +285,8 @@ describe('APIToken utils', () => { it('should return 2 if all scopes are 2', () => { const scopes: Permission[] = [ ['account', 2], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 2], ['databases', 2], ['domains', 2], ['events', 2], @@ -284,6 +306,8 @@ describe('APIToken utils', () => { it('should return null if all scopes are different', () => { const scopes: Permission[] = [ ['account', 1], + // TODO: Parent/Child - add this scope once code is in prod. + // ['child_account', 0], ['databases', 0], ['domains', 2], ['events', 0], diff --git a/packages/manager/src/features/Profile/APITokens/utils.ts b/packages/manager/src/features/Profile/APITokens/utils.ts index f6dbd4c2a7f..2d78d8699b4 100644 --- a/packages/manager/src/features/Profile/APITokens/utils.ts +++ b/packages/manager/src/features/Profile/APITokens/utils.ts @@ -6,6 +6,8 @@ export type Permission = [string, number]; export const basePerms = [ 'account', + // TODO: Parent/Child - add this scope once API code is in prod. + // 'child_account', 'databases', 'domains', 'events', @@ -23,6 +25,8 @@ export const basePerms = [ export const basePermNameMap: Record = { account: 'Account', + // TODO: Parent/Child - add this scope once API code is in prod. + // child_account: 'Child Account Access', databases: 'Databases', domains: 'Domains', events: 'Events', diff --git a/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx b/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx index f7196cf2fbd..22e46b964e4 100644 --- a/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx +++ b/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx @@ -4,10 +4,10 @@ import { } from '@linode/api-v4/lib/support'; import { APIError } from '@linode/api-v4/lib/types'; import { Theme } from '@mui/material/styles'; -import { makeStyles } from 'tss-react/mui'; import { update } from 'ramda'; import * as React from 'react'; import { debounce } from 'throttle-debounce'; +import { makeStyles } from 'tss-react/mui'; import { Accordion } from 'src/components/Accordion'; import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; diff --git a/packages/manager/src/features/TheApplicationIsOnFire.tsx b/packages/manager/src/features/TheApplicationIsOnFire.tsx index ee6f56dda03..978f061cf14 100644 --- a/packages/manager/src/features/TheApplicationIsOnFire.tsx +++ b/packages/manager/src/features/TheApplicationIsOnFire.tsx @@ -1,11 +1,11 @@ import { Theme } from '@mui/material/styles'; -import { makeStyles } from '@mui/styles'; +import { makeStyles } from 'tss-react/mui'; import * as React from 'react'; import { Dialog } from 'src/components/Dialog/Dialog'; import { Typography } from 'src/components/Typography'; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles()((theme: Theme) => ({ restartButton: { ...theme.applyLinkStyles, }, @@ -22,7 +22,7 @@ const TheApplicationIsOnFire = () => { }; const ReloadLink = () => { - const classes = useStyles(); + const { classes } = useStyles(); return (
diff --git a/packages/manager/src/features/Users/UserDetail.tsx b/packages/manager/src/features/Users/UserDetail.tsx index bfd614cbe5c..280ab5cf5b8 100644 --- a/packages/manager/src/features/Users/UserDetail.tsx +++ b/packages/manager/src/features/Users/UserDetail.tsx @@ -252,6 +252,7 @@ export const UserDetail = () => { diff --git a/packages/manager/src/features/Users/UserPermissions.styles.ts b/packages/manager/src/features/Users/UserPermissions.styles.ts index afdcef657d0..a5bc3241b98 100644 --- a/packages/manager/src/features/Users/UserPermissions.styles.ts +++ b/packages/manager/src/features/Users/UserPermissions.styles.ts @@ -1,6 +1,9 @@ +import Grid from '@mui/material/Unstable_Grid2'; import { styled } from '@mui/material/styles'; +import { CircleProgress } from 'src/components/CircleProgress'; import Select from 'src/components/EnhancedSelect/Select'; +import { Paper } from 'src/components/Paper'; export const StyledSelect = styled(Select, { label: 'StyledSelect', @@ -30,3 +33,57 @@ export const StyledDivWrapper = styled('div', { marginTop: theme.spacing(2), paddingBottom: 0, })); + +export const StyledHeaderGrid = styled(Grid, { + label: 'StyledHeaderGrid', +})(({ theme }) => ({ + padding: 0, + [theme.breakpoints.down('sm')]: { + marginLeft: theme.spacing(2), + marginTop: theme.spacing(1), + width: '100%', + }, +})); + +export const StyledSubHeaderGrid = styled(Grid, { + label: 'StyledSubHeaderGrid', +})(({ theme }) => ({ + [theme.breakpoints.down('sm')]: { + margin: theme.spacing(0.5), + padding: 0, + }, +})); + +export const StyledUnrestrictedGrid = styled(Grid, { + label: 'StyledUnrestrictedGrid', +})(({ theme }) => ({ + paddingBottom: theme.spacing(2), + paddingLeft: theme.spacing(3), + [theme.breakpoints.down('sm')]: { + paddingLeft: theme.spacing(2), + }, +})); + +export const StyledPaper = styled(Paper, { + label: 'StyledPaper', +})(({ theme }) => ({ + paddingBottom: 0, + paddingTop: 0, + [theme.breakpoints.down('sm')]: { + padding: 0, + }, +})); + +export const StyledPermPaper = styled(Paper, { + label: 'StyledPermPaper', +})(({ theme }) => ({ + [theme.breakpoints.down('sm')]: { + padding: theme.spacing(2), + }, +})); + +export const StyledCircleProgress = styled(CircleProgress, { + label: 'StyledCircleProgress', +})(({ theme }) => ({ + marginTop: theme.spacing(2), +})); diff --git a/packages/manager/src/features/Users/UserPermissions.tsx b/packages/manager/src/features/Users/UserPermissions.tsx index 1bfc2848375..33f84d80ff7 100644 --- a/packages/manager/src/features/Users/UserPermissions.tsx +++ b/packages/manager/src/features/Users/UserPermissions.tsx @@ -4,24 +4,27 @@ import { GrantType, Grants, getGrants, + getUser, updateGrants, updateUser, } from '@linode/api-v4/lib/account'; import { APIError } from '@linode/api-v4/lib/types'; +import { Paper } from '@mui/material'; import Grid from '@mui/material/Unstable_Grid2'; import { WithSnackbarProps, withSnackbar } from 'notistack'; import { compose, flatten, lensPath, omit, set } from 'ramda'; import * as React from 'react'; +import { QueryClient } from 'react-query'; import { compose as recompose } from 'recompose'; import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; +import { Box } from 'src/components/Box'; import { CircleProgress } from 'src/components/CircleProgress'; -import { Divider } from 'src/components/Divider'; +// import { Button } from 'src/components/Button/Button'; import { DocumentTitleSegment } from 'src/components/DocumentTitle'; import { Item } from 'src/components/EnhancedSelect/Select'; import { FormControlLabel } from 'src/components/FormControlLabel'; import { Notice } from 'src/components/Notice/Notice'; -import { Paper } from 'src/components/Paper'; import { SelectionCard } from 'src/components/SelectionCard/SelectionCard'; import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel'; import { Tab } from 'src/components/Tabs/Tab'; @@ -41,7 +44,16 @@ import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; import { getAPIErrorFor } from 'src/utilities/getAPIErrorFor'; import { scrollErrorIntoView } from 'src/utilities/scrollErrorIntoView'; -import { StyledDivWrapper, StyledSelect } from './UserPermissions.styles'; +import { + StyledCircleProgress, + StyledDivWrapper, + StyledHeaderGrid, + StyledPaper, + StyledPermPaper, + StyledSelect, + StyledSubHeaderGrid, + StyledUnrestrictedGrid, +} from './UserPermissions.styles'; import { UserPermissionsEntitySection, entityNameMap, @@ -49,6 +61,7 @@ import { interface Props { clearNewUser: () => void; currentUser?: string; + queryClient: QueryClient; username?: string; } @@ -58,6 +71,7 @@ interface TabInfo { } interface State { + childAccountAccessEnabled: boolean; errors?: APIError[]; grants?: Grants; isSavingEntity: boolean; @@ -83,6 +97,7 @@ type CombinedProps = Props & class UserPermissions extends React.Component { componentDidMount() { this.getUserGrants(); + this.checkAndEnableChildAccountAccess(); if (this.props.flags.vpc) { this.setState({ vpcEnabled: true }); @@ -94,6 +109,7 @@ class UserPermissions extends React.Component { componentDidUpdate(prevProps: CombinedProps) { if (prevProps.username !== this.props.username) { this.getUserGrants(); + this.checkAndEnableChildAccountAccess(); } } @@ -138,6 +154,32 @@ class UserPermissions extends React.Component { } }; + checkAndEnableChildAccountAccess = async () => { + const { currentUser: currentUsername, flags } = this.props; + if (currentUsername) { + try { + const currentUser = await getUser(currentUsername); + + const isParentAccount = currentUser.user_type === 'parent'; + const isFeatureFlagOn = flags.parentChildAccountAccess; + + this.setState({ + childAccountAccessEnabled: Boolean( + isParentAccount && isFeatureFlagOn + ), + }); + } catch (error) { + this.setState({ + errors: getAPIErrorOrDefault( + error, + 'Unknown error occurred while fetching user permissions. Try again later.' + ), + }); + scrollErrorIntoView(); + } + } + }; + entityIsAll = (entity: string, value: GrantLevel): boolean => { const { grants } = this.state; if (!(grants && grants[entity])) { @@ -262,12 +304,16 @@ class UserPermissions extends React.Component { this.setState({ restricted: user.restricted, }); + this.props.queryClient.invalidateQueries(['account', 'users']); }) .then(() => { // unconditionally sets this.state.loadingGrants to false this.getUserGrants(); // refresh the data on /account/users so it is accurate this.props.queryClient.invalidateQueries('account-users'); + this.props.enqueueSnackbar('User permissions successfully saved.', { + variant: 'success', + }); }) .catch((errResponse) => { this.setState({ @@ -317,14 +363,13 @@ class UserPermissions extends React.Component { } return ( - + ({ marginTop: theme.spacing(2), paddingBottom: 0, })} container - data-qa-billing-section spacing={2} > @@ -376,48 +421,47 @@ class UserPermissions extends React.Component { const generalError = hasErrorFor('none'); return ( - + theme.spacing(4) }}> {generalError && ( )} - - - ({ - [theme.breakpoints.down('md')]: { - paddingLeft: theme.spacing(), - }, - })} - data-qa-restrict-access={restricted} - variant="h2" - > - Full Account Access: - - - - {!restricted ? 'On' : 'Off'} - - - + + + + + General Permissions + + + + + + + theme.font.bold }} + variant="subtitle2" + > + Full Account Access + + - + {restricted ? this.renderPermissions() : this.renderUnrestricted()} - + ); }; @@ -441,6 +485,11 @@ class UserPermissions extends React.Component { permDescriptionMap['add_vpcs'] = 'Can add VPCs to this account'; } + if (this.state.childAccountAccessEnabled) { + permDescriptionMap['child_account_access'] = + 'Enable child account access'; + } + return ( { })} label={permDescriptionMap[perm]} /> - ); }; renderGlobalPerms = () => { const { grants, isSavingGlobal } = this.state; + if ( + this.state.childAccountAccessEnabled && + !this.globalBooleanPerms.includes('child_account_access') + ) { + this.globalBooleanPerms.push('child_account_access'); + } return ( - ({ - marginTop: theme.spacing(2), - })} - data-qa-global-section - > + - Global Permissions + Configure the specific rights and privileges this user has within the + account.{
}Remember that permissions related to actions with the + '$' symbol may incur additional charges.
({ @@ -503,14 +554,14 @@ class UserPermissions extends React.Component { this.cancelPermsType('global'), isSavingGlobal )} -
+ ); }; renderPermissions = () => { - const { loadingGrants } = this.state; - if (loadingGrants) { - return ; + const { loading, loadingGrants } = this.state; + if (loadingGrants || loading) { + return ; } else { return ( @@ -535,7 +586,7 @@ class UserPermissions extends React.Component { }); return ( - ({ marginTop: theme.spacing(2), })} @@ -607,22 +658,21 @@ class UserPermissions extends React.Component { this.cancelPermsType('entity'), isSavingEntity )} - + ); }; renderUnrestricted = () => { - /* TODO: render all permissions disabled with this message above */ return ( - ({ - marginTop: theme.spacing(2), - padding: theme.spacing(3), - })} - > - - This user has unrestricted access to the account. - + + + + This user has unrestricted access to the account. + + {/* */} + ); }; @@ -658,9 +708,12 @@ class UserPermissions extends React.Component { const { tabs } = this.getTabInformation(grantsResponse); this.setState({ isSavingGlobal: false, tabs }); - this.props.enqueueSnackbar('Successfully saved global permissions', { - variant: 'success', - }); + this.props.enqueueSnackbar( + 'General user permissions successfully saved.', + { + variant: 'success', + } + ); }) .catch((errResponse) => { this.setState({ @@ -711,8 +764,10 @@ class UserPermissions extends React.Component { this.setState((compose as any)(...updateFns)); } this.props.enqueueSnackbar( - 'Successfully saved entity-specific permissions', - { variant: 'success' } + 'Entity-specific user permissions successfully saved.', + { + variant: 'success', + } ); // In the chance a new type entity was added to the account, re-calculate what tabs need to be shown. const { tabs } = this.getTabInformation(grantsResponse); @@ -749,6 +804,7 @@ class UserPermissions extends React.Component { }; state: State = { + childAccountAccessEnabled: false, isSavingEntity: false, isSavingGlobal: false, loading: true, diff --git a/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx b/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx index 5f9b4d9dc63..015355a9208 100644 --- a/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx +++ b/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx @@ -43,159 +43,149 @@ interface Props { showHeading?: boolean; } -export const UserPermissionsEntitySection = React.memo(({ - entity, grants, setGrantTo, entitySetAllTo, showHeading -}: Props) => { - const theme: Theme = useTheme(); - const pagination = usePagination(1); +export const UserPermissionsEntitySection = React.memo( + ({ entity, grants, setGrantTo, entitySetAllTo, showHeading }: Props) => { + const theme: Theme = useTheme(); + const pagination = usePagination(1); - if (!grants || grants.length === 0) { - return null; - } + if (!grants || grants.length === 0) { + return null; + } - const page = createDisplayPage( - pagination.page, - pagination.pageSize - )(grants); + const page = createDisplayPage( + pagination.page, + pagination.pageSize + )(grants); - const entityIsAll = (value: GrantLevel): boolean => { - if (!grants) { - return false; - } + const entityIsAll = (value: GrantLevel): boolean => { + if (!grants) { + return false; + } - return !grants.some((grant) => grant.permissions !== value); - }; + return !grants.some((grant) => grant.permissions !== value); + }; - return ( - - {showHeading && ( - - {entityNameMap[entity]} - - )} - - - - Label - - {/* eslint-disable-next-line */} - - - - {/* eslint-disable-next-line */} - - - - {/* eslint-disable-next-line */} - - - - - - {page.map((grant, _idx) => { - // Index must be corrected to account for pagination - const idx = (pagination.page - 1) * pagination.pageSize + _idx; - return ( - - - {grant.label} - - + return ( + + {showHeading && ( + + {entityNameMap[entity]} + + )} + + + + Label + + {/* eslint-disable-next-line */} + - + + + + {/* eslint-disable-next-line */} + - + + + + {/* eslint-disable-next-line */} + - - ); - })} - - - - - ); -}); + + + + + + {page.map((grant, _idx) => { + // Index must be corrected to account for pagination + const idx = (pagination.page - 1) * pagination.pageSize + _idx; + return ( + + + {grant.label} + + + + + + + + + + + + ); + })} + + + + + ); + } +); diff --git a/packages/manager/src/features/Volumes/VolumeCreate.tsx b/packages/manager/src/features/Volumes/VolumeCreate.tsx index 64aa70c5b69..3365111ae95 100644 --- a/packages/manager/src/features/Volumes/VolumeCreate.tsx +++ b/packages/manager/src/features/Volumes/VolumeCreate.tsx @@ -1,7 +1,7 @@ import { Linode } from '@linode/api-v4/lib/linodes/types'; import { CreateVolumeSchema } from '@linode/validation/lib/volumes.schema'; import { Theme, useTheme } from '@mui/material/styles'; -import { makeStyles } from '@mui/styles'; +import { makeStyles } from 'tss-react/mui'; import { useFormik } from 'formik'; import { useSnackbar } from 'notistack'; import * as React from 'react'; @@ -42,7 +42,7 @@ import { SizeField } from './VolumeDrawer/SizeField'; export const SIZE_FIELD_WIDTH = 160; -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles()((theme: Theme) => ({ agreement: { maxWidth: '70%', [theme.breakpoints.down('sm')]: { @@ -103,7 +103,7 @@ const useStyles = makeStyles((theme: Theme) => ({ export const VolumeCreate = () => { const theme = useTheme(); - const classes = useStyles(); + const { classes } = useStyles(); const history = useHistory(); const { data: profile } = useProfile(); diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx index b906107b95e..d357682346c 100644 --- a/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx +++ b/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx @@ -1,5 +1,5 @@ import { Theme } from '@mui/material/styles'; -import { makeStyles } from '@mui/styles'; +import { makeStyles } from 'tss-react/mui'; import * as React from 'react'; import { Box } from 'src/components/Box'; @@ -27,7 +27,7 @@ interface Props { value: number; } -const useStyles = makeStyles((theme: Theme) => ({ +const useStyles = makeStyles()((theme: Theme) => ({ createVolumeText: { display: 'block', marginLeft: theme.spacing(1.5), @@ -45,7 +45,7 @@ const useStyles = makeStyles((theme: Theme) => ({ })); export const SizeField = (props: Props) => { - const classes = useStyles(); + const { classes } = useStyles(); const { error, diff --git a/packages/manager/src/features/Volumes/VolumeTableRow.tsx b/packages/manager/src/features/Volumes/VolumeTableRow.tsx index a6efc1184b5..69ba7e72ef5 100644 --- a/packages/manager/src/features/Volumes/VolumeTableRow.tsx +++ b/packages/manager/src/features/Volumes/VolumeTableRow.tsx @@ -1,6 +1,6 @@ import { Event } from '@linode/api-v4/lib/account'; import { Volume } from '@linode/api-v4/lib/volumes/types'; -import { makeStyles } from '@mui/styles'; +import { makeStyles } from 'tss-react/mui'; import * as React from 'react'; import { Link } from 'react-router-dom'; @@ -16,7 +16,7 @@ import { useRegionsQuery } from 'src/queries/regions'; import { ActionHandlers, VolumesActionMenu } from './VolumesActionMenu'; // import useEvents from 'src/hooks/useEvents'; -export const useStyles = makeStyles({ +export const useStyles = makeStyles()({ chipWrapper: { alignSelf: 'center', }, @@ -65,7 +65,7 @@ export const volumeStatusIconMap: Record = { }; export const VolumeTableRow = React.memo((props: Props) => { - const classes = useStyles(); + const { classes } = useStyles(); const { data: regions } = useRegionsQuery(); const { handlers, isDetailsPageRow, volume } = props; diff --git a/packages/manager/src/hooks/useInitialRequests.ts b/packages/manager/src/hooks/useInitialRequests.ts index c2bc651c79e..5157f22fd85 100644 --- a/packages/manager/src/hooks/useInitialRequests.ts +++ b/packages/manager/src/hooks/useInitialRequests.ts @@ -70,7 +70,7 @@ export const useInitialRequests = () => { // Username and whether a user is restricted queryClient.prefetchQuery({ - queryFn: getProfile, + queryFn: () => getProfile(), queryKey: 'profile', }), diff --git a/packages/manager/src/mocks/serverHandlers.ts b/packages/manager/src/mocks/serverHandlers.ts index 69636d13d99..ea55bd18bb0 100644 --- a/packages/manager/src/mocks/serverHandlers.ts +++ b/packages/manager/src/mocks/serverHandlers.ts @@ -2,6 +2,7 @@ import { NotificationType, SecurityQuestionsPayload, TokenRequest, + User, VolumeStatus, } from '@linode/api-v4'; import { DateTime } from 'luxon'; @@ -488,26 +489,32 @@ const standardTypes = linodeTypeFactory.buildList(7); const dedicatedTypes = dedicatedTypeFactory.buildList(7); const proDedicatedType = proDedicatedTypeFactory.build(); -const proxyAccount = accountUserFactory.build({ +const proxyAccountUser = accountUserFactory.build({ email: 'partner@proxy.com', last_login: null, user_type: 'proxy', username: 'ParentCompany_a1b2c3d4e5', }); -const parentAccount = accountUserFactory.build({ +const parentAccountUser = accountUserFactory.build({ email: 'parent@acme.com', last_login: null, restricted: false, user_type: 'parent', username: 'ParentUser', }); -const childAccount = accountUserFactory.build({ +const childAccountUser = accountUserFactory.build({ email: 'child@linode.com', last_login: null, restricted: false, user_type: 'child', username: 'ChildUser', }); +const parentAccountNonAdminUser = accountUserFactory.build({ + email: 'account@linode.com', + last_login: null, + restricted: false, + username: 'NonAdminUser', +}); export const handlers = [ rest.get('*/profile', (req, res, ctx) => { @@ -520,7 +527,11 @@ export const handlers = [ return res(ctx.json({ ...profileFactory.build(), ...(req.body as any) })); }), rest.get('*/profile/grants', (req, res, ctx) => { - return res(ctx.json(grantsFactory.build())); + return res( + // Parent/Child: switch out the return statement if you want to mock a restricted parent user with access to child accounts. + // ctx.json(grantsFactory.build({ global: { child_account_access: true } })) + ctx.json(grantsFactory.build()) + ); }), rest.get('*/profile/apps', (req, res, ctx) => { const tokens = appTokenFactory.buildList(5); @@ -903,7 +914,7 @@ export const handlers = [ const page = Number(req.url.searchParams.get('page') || 1); const pageSize = Number(req.url.searchParams.get('page_size') || 25); - const buckets = objectStorageBucketFactory.buildList(0); + const buckets = objectStorageBucketFactory.buildList(1); return res( ctx.json({ @@ -1035,6 +1046,7 @@ export const handlers = [ active_promotions: promoFactory.buildList(1), active_since: '2022-11-30', balance: 50, + company: 'Mock Company', }); return res(ctx.json(account)); }), @@ -1149,6 +1161,41 @@ export const handlers = [ return res(ctx.json(makeResourcePage(accountMaintenance))); }), + rest.get('*/account/child-accounts', (req, res, ctx) => { + const childAccounts = [ + accountFactory.build({ + company: 'Child Company 0', + euuid: '0', + }), + accountFactory.build({ + company: 'Child Company 1', + euuid: '1', + }), + accountFactory.build({ + company: 'Child Company 2', + euuid: '2', + }), + ]; + return res(ctx.json(makeResourcePage(childAccounts))); + }), + rest.get('*/account/child-accounts/:euuid', (req, res, ctx) => { + const childAccount = accountFactory.build({ + company: 'Child Company 1', + euuid: '1', + }); + return res(ctx.json(childAccount)); + }), + rest.post('*/account/child-accounts/:euuid/token', (req, res, ctx) => { + // Proxy tokens expire in 15 minutes. + const now = new Date(); + const expiry = new Date(now.setMinutes(now.getMinutes() + 15)); + + const proxyToken = appTokenFactory.build({ + expiry: expiry.toISOString(), + token: `Bearer ${import.meta.env.REACT_APP_PROXY_PAT}`, + }); + return res(ctx.json(proxyToken)); + }), rest.get('*/account/users', (req, res, ctx) => { const accountUsers = [ accountUserFactory.build({ @@ -1162,26 +1209,44 @@ export const handlers = [ }, }), accountUserFactory.build({ last_login: null }), - childAccount, - parentAccount, - proxyAccount, + childAccountUser, + parentAccountUser, + proxyAccountUser, + parentAccountNonAdminUser, ]; return res(ctx.json(makeResourcePage(accountUsers))); }), - rest.get(`*/account/users/${childAccount.username}`, (req, res, ctx) => { - return res(ctx.json(childAccount)); + rest.get(`*/account/users/${childAccountUser.username}`, (req, res, ctx) => { + return res(ctx.json(childAccountUser)); }), - rest.get(`*/account/users/${proxyAccount.username}`, (req, res, ctx) => { - return res(ctx.json(proxyAccount)); + rest.get(`*/account/users/${proxyAccountUser.username}`, (req, res, ctx) => { + return res(ctx.json(proxyAccountUser)); }), - rest.get(`*/account/users/${parentAccount.username}`, (req, res, ctx) => { - return res(ctx.json(parentAccount)); + rest.get(`*/account/users/${parentAccountUser.username}`, (req, res, ctx) => { + return res(ctx.json(parentAccountUser)); }), + rest.get( + `*/account/users/${parentAccountNonAdminUser.username}`, + (req, res, ctx) => { + return res(ctx.json(parentAccountNonAdminUser)); + } + ), rest.get('*/account/users/:user', (req, res, ctx) => { - return res(ctx.json(accountUserFactory.build())); + // Parent/Child: switch the `user_type` depending on what account view you need to mock. + return res(ctx.json(accountUserFactory.build({ user_type: 'parent' }))); }), + rest.put( + `*/account/users/${parentAccountNonAdminUser.username}`, + (req, res, ctx) => { + const { restricted } = req.body as Partial; + if (restricted !== undefined) { + parentAccountNonAdminUser.restricted = restricted; + } + return res(ctx.json(parentAccountNonAdminUser)); + } + ), rest.get( - `*/account/users/${childAccount.username}/grants`, + `*/account/users/${childAccountUser.username}/grants`, (req, res, ctx) => { return res( ctx.json( @@ -1195,7 +1260,7 @@ export const handlers = [ } ), rest.get( - `*/account/users/${proxyAccount.username}/grants`, + `*/account/users/${proxyAccountUser.username}/grants`, (req, res, ctx) => { return res( ctx.json( @@ -1219,7 +1284,7 @@ export const handlers = [ } ), rest.get( - `*/account/users/${parentAccount.username}/grants`, + `*/account/users/${parentAccountUser.username}/grants`, (req, res, ctx) => { return res( ctx.json( @@ -1233,6 +1298,20 @@ export const handlers = [ ); } ), + rest.get( + `*/account/users/${parentAccountNonAdminUser.username}/grants`, + (req, res, ctx) => { + const grantsResponse = grantsFactory.build({ + global: parentAccountNonAdminUser.restricted + ? { + cancel_account: false, + child_account_access: true, + } + : undefined, + }); + return res(ctx.json(grantsResponse)); + } + ), rest.get('*/account/users/:user/grants', (req, res, ctx) => { return res( ctx.json( @@ -1369,7 +1448,7 @@ export const handlers = [ longview_subscription: 'longview-100', managed: true, network_helper: true, - object_storage: 'disabled', + object_storage: 'active', }) ); }), diff --git a/packages/manager/src/queries/account.ts b/packages/manager/src/queries/account.ts index c69d16a9d88..9adb30e6f26 100644 --- a/packages/manager/src/queries/account.ts +++ b/packages/manager/src/queries/account.ts @@ -9,6 +9,7 @@ import { useMutation, useQuery, useQueryClient } from 'react-query'; import { useGrants, useProfile } from 'src/queries/profile'; +import { useAccountUser } from './accountUsers'; import { queryPresets } from './base'; import type { @@ -52,6 +53,8 @@ export const useChildAccounts = ({ headers, params, }: RequestOptions) => { + const { data: profile } = useProfile(); + const { data: user } = useAccountUser(profile?.username ?? ''); const { data: grants } = useGrants(); const hasExplicitAuthToken = Boolean(headers?.Authorization); @@ -60,13 +63,17 @@ export const useChildAccounts = ({ () => getChildAccounts({ filter, headers, params }), { enabled: - Boolean(grants?.global?.child_account_access) || hasExplicitAuthToken, + (Boolean(user?.user_type === 'parent') && !profile?.restricted) || + Boolean(grants?.global?.child_account_access) || + hasExplicitAuthToken, keepPreviousData: true, } ); }; export const useChildAccount = ({ euuid, headers }: ChildAccountPayload) => { + const { data: profile } = useProfile(); + const { data: user } = useAccountUser(profile?.username ?? ''); const { data: grants } = useGrants(); const hasExplicitAuthToken = Boolean(headers?.Authorization); @@ -75,7 +82,9 @@ export const useChildAccount = ({ euuid, headers }: ChildAccountPayload) => { () => getChildAccount({ euuid }), { enabled: - Boolean(grants?.global?.child_account_access) || hasExplicitAuthToken, + (Boolean(user?.user_type === 'parent') && !profile?.restricted) || + Boolean(grants?.global?.child_account_access) || + hasExplicitAuthToken, } ); }; diff --git a/packages/manager/src/queries/profile.ts b/packages/manager/src/queries/profile.ts index 18e89ff4139..93b95599dd5 100644 --- a/packages/manager/src/queries/profile.ts +++ b/packages/manager/src/queries/profile.ts @@ -37,13 +37,24 @@ import { Grants } from '../../../api-v4/lib'; import { queryKey as accountQueryKey } from './account'; import { queryPresets } from './base'; +import type { RequestOptions } from '@linode/api-v4'; + export const queryKey = 'profile'; -export const useProfile = (givenProfile?: Profile) => - useQuery(queryKey, getProfile, { - ...queryPresets.oneTimeFetch, - initialData: givenProfile, - }); +export const useProfile = (options?: RequestOptions) => { + const key = [ + queryKey, + options?.headers ? { headers: options.headers } : null, + ]; + + return useQuery( + key, + () => getProfile({ headers: options?.headers }), + { + ...queryPresets.oneTimeFetch, + } + ); +}; export const useMutateProfile = () => { const queryClient = useQueryClient(); @@ -57,7 +68,7 @@ export const updateProfileData = ( newData: Partial, queryClient: QueryClient ): void => { - queryClient.setQueryData(queryKey, (oldData: Profile) => ({ + queryClient.setQueryData([queryKey, null], (oldData: Profile) => ({ ...oldData, ...newData, })); @@ -72,7 +83,8 @@ export const useGrants = () => { }; export const getProfileData = (queryClient: QueryClient) => - queryClient.getQueryData(queryKey); + queryClient.getQueryData([queryKey, null]); + export const getGrantData = (queryClient: QueryClient) => queryClient.getQueryData([queryKey, 'grants']); @@ -179,7 +191,9 @@ export const useDisableTwoFactorMutation = () => { const queryClient = useQueryClient(); return useMutation<{}, APIError[]>(disableTwoFactor, { onSuccess() { - queryClient.invalidateQueries([queryKey]); + queryClient.invalidateQueries([queryKey, null]); + // also invalidate the /account/users data because that endpoint returns 2FA status for each user + queryClient.invalidateQueries([accountQueryKey, 'users']); }, }); }; diff --git a/packages/manager/src/utilities/creditCard.test.ts b/packages/manager/src/utilities/creditCard.test.ts index f3f566b3b78..5787fab5623 100644 --- a/packages/manager/src/utilities/creditCard.test.ts +++ b/packages/manager/src/utilities/creditCard.test.ts @@ -1,10 +1,10 @@ import { CreditCardSchema } from '@linode/validation'; -import { DateTime } from 'luxon'; +import { Settings } from 'luxon'; import { take, takeLast } from 'ramda'; import { formatExpiry, - hasExpirationPassedFor, + isCreditCardExpired, parseExpiryYear, } from './creditCard'; @@ -12,10 +12,9 @@ const currentYear = new Date().getFullYear(); const currentYearFirstTwoDigits = take(2, String(currentYear)); describe('isCreditCardExpired', () => { - describe('give today is 01/01/2019', () => { - const date = DateTime.fromObject({ day: 1, month: 1, year: 2019 }); - - const isCreditCardExpired = hasExpirationPassedFor(date); + describe('given today is 01/01/2019', () => { + // Mock that the current date is 1/1/2019 + Settings.now = () => new Date(2019, 0, 1).valueOf(); [ ['01/2018', true], @@ -30,7 +29,7 @@ describe('isCreditCardExpired', () => { ['10/2018', true], ['11/2018', true], ['12/2018', true], - ['01/2019', false], + ['01/2019', false], // A card is still valid until the end of the month ['02/2019', false], ['03/2019', false], ['04/2019', false], diff --git a/packages/manager/src/utilities/creditCard.ts b/packages/manager/src/utilities/creditCard.ts index 0fce59e77b3..921c68cae5c 100644 --- a/packages/manager/src/utilities/creditCard.ts +++ b/packages/manager/src/utilities/creditCard.ts @@ -1,8 +1,12 @@ import { DateTime } from 'luxon'; import { take, takeLast } from 'ramda'; /** - * Expiration is the beginning of the day of the first day of the month. - * Expiration: yyyy-MM-01 00:00:00 + * Credit cards generally are valid through the expiry month (inclusive). + * + * For example, + * A credit card with an expiry of 01/2019 expires the last day of January. + * + * @param expDate The expiry date in the format MM/YYYY */ const expirationDateFromString = (expDate: string /* MM/YYYY */) => { const pattern = /^((0[1-9])|(1[0-2]))\/(\d{4})$/i; @@ -11,16 +15,22 @@ const expirationDateFromString = (expDate: string /* MM/YYYY */) => { } // month are 1 based in luxon - const month = +expDate.substr(0, 2); - const year = +expDate.substr(3, 8); + const month = +expDate.substring(0, 2); + const year = +expDate.substring(3, 8); - return DateTime.fromObject({ day: 1, month, year }).endOf('month'); + return DateTime.fromObject({ month, year }).endOf('month'); }; -export const hasExpirationPassedFor = (today: DateTime = DateTime.local()) => ( - expDate: string /** MM/YYYY */ -) => { - return today > expirationDateFromString(expDate); +/** + * Returns true if a credit card is expired. + * + * For example, if a card has an expiry of 1/1/2023 and the current date is + * 1/1/2023, the card is is not expired. + * + * @param expDate The expiry date in the format MM/YYYY + */ +export const isCreditCardExpired = (expDate: string) => { + return DateTime.local() > expirationDateFromString(expDate); }; /** @@ -48,5 +58,3 @@ export const parseExpiryYear = ( return take(2, String(new Date().getFullYear())) + expiryYear; }; - -export default hasExpirationPassedFor(); diff --git a/packages/manager/src/utilities/stringUtils.test.ts b/packages/manager/src/utilities/stringUtils.test.ts index 43e66f7814e..62bbea50283 100644 --- a/packages/manager/src/utilities/stringUtils.test.ts +++ b/packages/manager/src/utilities/stringUtils.test.ts @@ -1,4 +1,10 @@ -import { isNumeric, truncateAndJoinList } from './stringUtils'; +import { + getNextLabel, + getNumberAtEnd, + isNumeric, + removeNumberAtEnd, + truncateAndJoinList, +} from './stringUtils'; describe('truncateAndJoinList', () => { const strList = ['a', 'b', 'c']; @@ -49,3 +55,44 @@ describe('isNumeric', () => { expect(isNumeric('my-linode')).toBe(false); }); }); + +describe('getNumberAtEnd', () => { + it('should return 1 when given test-1', () => { + expect(getNumberAtEnd('test-1')).toBe(1); + }); + it('should return null if there is no number in the string', () => { + expect(getNumberAtEnd('test')).toBe(null); + }); + it('should get the last number in the string', () => { + expect(getNumberAtEnd('test-1-2-3')).toBe(3); + }); + it('should handle a string that only contains numbers', () => { + expect(getNumberAtEnd('123')).toBe(123); + }); +}); + +describe('removeNumberAtEnd', () => { + it('should return 1 in "test-1"', () => { + expect(removeNumberAtEnd('test-1')).toBe('test-'); + }); + it('should return the same string if there is no number at the end', () => { + expect(removeNumberAtEnd('test')).toBe('test'); + }); + it('should return an empty string if the input is just a number', () => { + expect(removeNumberAtEnd('123')).toBe(''); + }); + it('should not remove the first number', () => { + expect(removeNumberAtEnd('1-2-3')).toBe('1-2-'); + }); +}); + +describe('getNextLabel', () => { + it('should append a number to get the next label', () => { + expect(getNextLabel({ label: 'test' }, [{ label: 'test' }])).toBe('test-1'); + }); + it('should not duplicate labels so that the returned label is unique', () => { + expect(getNextLabel({ label: 'test' }, [{ label: 'test-1' }])).toBe( + 'test-2' + ); + }); +}); diff --git a/packages/manager/src/utilities/stringUtils.ts b/packages/manager/src/utilities/stringUtils.ts index ae87327330b..a497d7a4a70 100644 --- a/packages/manager/src/utilities/stringUtils.ts +++ b/packages/manager/src/utilities/stringUtils.ts @@ -35,3 +35,47 @@ export const convertForAria = (str: string) => { .toLowerCase() .replace(/([^A-Z0-9]+)(.)/gi, (match, p1, p2) => p2.toUpperCase()); }; + +export function getNumberAtEnd(str: string) { + // Use a regular expression to match one or more digits at the end of the string + const match = str.match(/\d+$/); + + // If there is a match, return the matched number; otherwise, return null + return match ? parseInt(match[0], 10) : null; +} + +export function removeNumberAtEnd(str: string) { + // Use a regular expression to match one or more digits at the end of the string + const regex = /\d+$/; + + // Use the replace() method to remove the matched portion + return str.replace(regex, ''); +} + +/** + * Gets the next available unique entity label + */ +export function getNextLabel( + selectedEntity: T, + allEntities: T[] +): string { + const numberAtEnd = getNumberAtEnd(selectedEntity.label); + + let labelToReturn = ''; + + if (numberAtEnd === null) { + labelToReturn = `${selectedEntity.label}-1`; + } else { + labelToReturn = `${removeNumberAtEnd(selectedEntity.label)}${ + numberAtEnd + 1 + }`; + } + + if (allEntities.some((r) => r.label === labelToReturn)) { + return getNextLabel( + { ...selectedEntity, label: labelToReturn }, + allEntities + ); + } + return labelToReturn; +} diff --git a/packages/validation/CHANGELOG.md b/packages/validation/CHANGELOG.md index dc01893dc56..60b0c948499 100644 --- a/packages/validation/CHANGELOG.md +++ b/packages/validation/CHANGELOG.md @@ -1,3 +1,10 @@ +## [2024-01-08] - v0.37.0 + + +### Tech Stories: + +- Add Lint Github Action ([#9973](https://github.com/linode/manager/pull/9973)) + ## [2023-12-11] - v0.36.0 diff --git a/packages/validation/package.json b/packages/validation/package.json index bd8e0791da9..99fb18d1fff 100644 --- a/packages/validation/package.json +++ b/packages/validation/package.json @@ -1,6 +1,6 @@ { "name": "@linode/validation", - "version": "0.36.0", + "version": "0.37.0", "description": "Yup validation schemas for use with the Linode APIv4", "type": "module", "main": "lib/index.cjs", diff --git a/packages/validation/src/buckets.schema.ts b/packages/validation/src/buckets.schema.ts index 97cd17611b7..90f248ceb4b 100644 --- a/packages/validation/src/buckets.schema.ts +++ b/packages/validation/src/buckets.schema.ts @@ -1,14 +1,24 @@ import { boolean, object, string } from 'yup'; -export const CreateBucketSchema = object({ - label: string() - .required('Label is required.') - .matches(/^\S*$/, 'Label must not contain spaces.') - .ensure() - .min(3, 'Label must be between 3 and 63 characters.') - .max(63, 'Label must be between 3 and 63 characters.'), - cluster: string().required('Cluster is required.'), -}); +export const CreateBucketSchema = object().shape( + { + label: string() + .required('Label is required.') + .matches(/^\S*$/, 'Label must not contain spaces.') + .ensure() + .min(3, 'Label must be between 3 and 63 characters.') + .max(63, 'Label must be between 3 and 63 characters.'), + cluster: string().when('region', { + is: (region: string) => !region || region.length === 0, + then: string().required('Cluster is required.'), + }), + region: string().when('cluster', { + is: (cluster: string) => !cluster || cluster.length === 0, + then: string().required('Region is required.'), + }), + }, + [['cluster', 'region']] +); export const UploadCertificateSchema = object({ certificate: string().required('Certificate is required.'), diff --git a/packages/validation/src/loadbalancers.schema.ts b/packages/validation/src/loadbalancers.schema.ts index c99a46218c7..1153342ccd0 100644 --- a/packages/validation/src/loadbalancers.schema.ts +++ b/packages/validation/src/loadbalancers.schema.ts @@ -50,10 +50,14 @@ export const EndpointSchema = object({ const HealthCheckSchema = object({ protocol: string().oneOf(['http', 'tcp']), - interval: number().min(0), - timeout: number().min(0), - unhealthy_threshold: number().min(0), - healthy_threshold: number().min(0), + interval: number().typeError('Interval must be a number.').min(1, 'Interval must be greater than zero.'), + timeout: number().typeError('Timeout must be a number.').min(1, 'Timeout must be greater than zero.'), + unhealthy_threshold: number() + .typeError('Unhealthy Threshold must be a number.') + .min(1, 'Unhealthy Threshold must be greater than zero.'), + healthy_threshold: number() + .typeError('Healthy Threshold must be a number.') + .min(1, 'Healthy Threshold must be greater than zero.'), path: string().nullable(), host: string().nullable(), }); diff --git a/yarn.lock b/yarn.lock index bddd48ae342..07eb43cbe00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -151,6 +151,14 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" +"@babel/code-frame@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + "@babel/compat-data@^7.20.5": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" @@ -161,12 +169,17 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.3.tgz#cd502a6a0b6e37d7ad72ce7e71a7160a3ae36f7e" integrity sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ== -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9", "@babel/compat-data@^7.23.2": +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.2.tgz#6a12ced93455827037bfb5ed8492820d60fc32cc" integrity sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ== -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.20.12": +"@babel/compat-data@^7.23.3", "@babel/compat-data@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" + integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.20.12": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== @@ -187,7 +200,7 @@ json5 "^2.2.2" semver "^6.3.0" -"@babel/core@^7.18.9", "@babel/core@^7.22.9": +"@babel/core@^7.18.9": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.2.tgz#ed10df0d580fff67c5f3ee70fd22e2e4c90a9f94" integrity sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ== @@ -229,6 +242,27 @@ json5 "^2.2.2" semver "^6.3.0" +"@babel/core@^7.23.0", "@babel/core@^7.23.2": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.6.tgz#8be77cd77c55baadcc1eae1c33df90ab6d2151d4" + integrity sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.23.6" + "@babel/parser" "^7.23.6" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.6" + "@babel/types" "^7.23.6" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/generator@^7.21.0", "@babel/generator@^7.21.1": version "7.21.1" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" @@ -249,7 +283,7 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" -"@babel/generator@^7.22.9", "@babel/generator@^7.23.0": +"@babel/generator@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.0.tgz#df5c386e2218be505b34837acbcb874d7a983420" integrity sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g== @@ -259,6 +293,16 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== + dependencies: + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -273,7 +317,7 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz#5426b109cf3ad47b91120f8328d8ab1be8b0b956" integrity sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw== @@ -302,7 +346,7 @@ lru-cache "^5.1.1" semver "^6.3.0" -"@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": +"@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.6": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== @@ -313,21 +357,33 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz#64f49ecb0020532f19b1d014b03bccaa1ab85fb9" - integrity sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ== +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.18.6" - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-member-expression-to-functions" "^7.21.0" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/helper-replace-supers" "^7.20.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.22.15", "@babel/helper-create-class-features-plugin@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.6.tgz#b04d915ce92ce363666f816a884cdcfc9be04953" + integrity sha512-cBXU1vZni/CpGF29iTu4YRbOZt3Wat6zCoMDxRF1MayiEc4URxOj31tT65HUM0CRpMowA3HCJaAOVOUnMf96cw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-member-expression-to-functions" "^7.23.0" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.20" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.22.11", "@babel/helper-create-class-features-plugin@^7.22.5": +"@babel/helper-create-class-features-plugin@^7.22.5": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz#97a61b385e57fe458496fad19f8e63b63c867de4" integrity sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg== @@ -350,7 +406,7 @@ "@babel/helper-annotate-as-pure" "^7.18.6" regexpu-core "^5.3.1" -"@babel/helper-create-regexp-features-plugin@^7.22.5": +"@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1" integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w== @@ -415,14 +471,7 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-member-expression-to-functions@^7.20.7", "@babel/helper-member-expression-to-functions@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz#319c6a940431a133897148515877d2f3269c3ba5" - integrity sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q== - dependencies: - "@babel/types" "^7.21.0" - -"@babel/helper-member-expression-to-functions@^7.22.15": +"@babel/helper-member-expression-to-functions@^7.22.15", "@babel/helper-member-expression-to-functions@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz#9263e88cc5e41d39ec18c9a3e0eced59a3e7d366" integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== @@ -443,14 +492,14 @@ dependencies: "@babel/types" "^7.21.4" -"@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5": +"@babel/helper-module-imports@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== dependencies: "@babel/types" "^7.22.15" -"@babel/helper-module-transforms@^7.21.0", "@babel/helper-module-transforms@^7.21.2": +"@babel/helper-module-transforms@^7.21.0": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== @@ -478,7 +527,7 @@ "@babel/traverse" "^7.22.1" "@babel/types" "^7.22.0" -"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.23.0": +"@babel/helper-module-transforms@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" integrity sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw== @@ -489,12 +538,16 @@ "@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-validator-identifier" "^7.22.20" -"@babel/helper-optimise-call-expression@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe" - integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA== +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== dependencies: - "@babel/types" "^7.18.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" "@babel/helper-optimise-call-expression@^7.22.5": version "7.22.5" @@ -513,7 +566,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== -"@babel/helper-remap-async-to-generator@^7.22.20", "@babel/helper-remap-async-to-generator@^7.22.5": +"@babel/helper-remap-async-to-generator@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz#7b68e1cb4fa964d2996fd063723fb48eca8498e0" integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== @@ -522,19 +575,7 @@ "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-wrap-function" "^7.22.20" -"@babel/helper-replace-supers@^7.20.7": - version "7.20.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz#243ecd2724d2071532b2c8ad2f0f9f083bcae331" - integrity sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A== - dependencies: - "@babel/helper-environment-visitor" "^7.18.9" - "@babel/helper-member-expression-to-functions" "^7.20.7" - "@babel/helper-optimise-call-expression" "^7.18.6" - "@babel/template" "^7.20.7" - "@babel/traverse" "^7.20.7" - "@babel/types" "^7.20.7" - -"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": +"@babel/helper-replace-supers@^7.22.20", "@babel/helper-replace-supers@^7.22.9": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== @@ -564,13 +605,6 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-skip-transparent-expression-wrappers@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz#fbe4c52f60518cab8140d77101f0e63a8a230684" - integrity sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg== - dependencies: - "@babel/types" "^7.20.0" - "@babel/helper-skip-transparent-expression-wrappers@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" @@ -607,6 +641,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -627,6 +666,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + "@babel/helper-wrap-function@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz#15352b0b9bfb10fc9c76f79f6342c00e3411a569" @@ -663,6 +707,15 @@ "@babel/traverse" "^7.23.2" "@babel/types" "^7.23.0" +"@babel/helpers@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.6.tgz#d03af2ee5fb34691eec0cda90f5ecbb4d4da145a" + integrity sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.6" + "@babel/types" "^7.23.6" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -681,7 +734,16 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2", "@babel/parser@^7.7.0": +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2", "@babel/parser@^7.7.0": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== @@ -691,51 +753,44 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.4.tgz#a770e98fd785c231af9d93f6459d36770993fb32" integrity sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA== -"@babel/parser@^7.22.15", "@babel/parser@^7.22.7", "@babel/parser@^7.23.0": +"@babel/parser@^7.22.15", "@babel/parser@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz#02dc8a03f613ed5fdc29fb2f728397c78146c962" - integrity sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg== +"@babel/parser@^7.23.3": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563" + integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ== + +"@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz#5cd1c87ba9380d0afb78469292c954fee5d2411a" + integrity sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz#2aeb91d337d4e1a1e7ce85b76a37f5301781200f" - integrity sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz#f6652bb16b94f8f9c20c50941e16e9756898dc5d" + integrity sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/plugin-transform-optional-chaining" "^7.22.15" + "@babel/plugin-transform-optional-chaining" "^7.23.3" -"@babel/plugin-proposal-class-properties@^7.13.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" - integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz#20c60d4639d18f7da8602548512e9d3a4c8d7098" + integrity sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w== dependencies: - "@babel/helper-create-class-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" - integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.13.12": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea" - integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA== - dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": version "7.21.0-placeholder-for-preset-env.2" @@ -777,24 +832,24 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-flow@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz#774d825256f2379d06139be0c723c4dd444f3ca1" - integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A== +"@babel/plugin-syntax-flow@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.23.3.tgz#084564e0f3cc21ea6c70c44cff984a1c0509729a" + integrity sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-syntax-import-assertions@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" - integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== +"@babel/plugin-syntax-import-assertions@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz#9c05a7f592982aff1a2768260ad84bcd3f0c77fc" + integrity sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-syntax-import-attributes@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb" - integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg== +"@babel/plugin-syntax-import-attributes@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz#992aee922cf04512461d7dae3ff6951b90a2dc06" + integrity sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -812,6 +867,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" + integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -868,12 +930,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.20.0": - version "7.20.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz#4e9a0cfc769c85689b77a2e642d24e9f697fc8c7" - integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== +"@babel/plugin-syntax-typescript@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" + integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" @@ -883,43 +945,43 @@ "@babel/helper-create-regexp-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-arrow-functions@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" - integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== +"@babel/plugin-transform-arrow-functions@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz#94c6dcfd731af90f27a79509f9ab7fb2120fc38b" + integrity sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-async-generator-functions@^7.23.2": - version "7.23.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.2.tgz#054afe290d64c6f576f371ccc321772c8ea87ebb" - integrity sha512-BBYVGxbDVHfoeXbOwcagAkOQAm9NxoTdMGfTqghu1GrvadSaw6iW3Je6IcL5PNOw8VwjxqBECXy50/iCQSY/lQ== +"@babel/plugin-transform-async-generator-functions@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz#93ac8e3531f347fba519b4703f9ff2a75c6ae27a" + integrity sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw== dependencies: "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-remap-async-to-generator" "^7.22.20" "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-transform-async-to-generator@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775" - integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ== +"@babel/plugin-transform-async-to-generator@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz#d1f513c7a8a506d43f47df2bf25f9254b0b051fa" + integrity sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw== dependencies: - "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-module-imports" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-remap-async-to-generator" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.20" -"@babel/plugin-transform-block-scoped-functions@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" - integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== +"@babel/plugin-transform-block-scoped-functions@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz#fe1177d715fb569663095e04f3598525d98e8c77" + integrity sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-block-scoping@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz#8744d02c6c264d82e1a4bc5d2d501fd8aff6f022" - integrity sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g== +"@babel/plugin-transform-block-scoping@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz#b2d38589531c6c80fbe25e6b58e763622d2d3cf5" + integrity sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -931,155 +993,155 @@ "@babel/helper-create-class-features-plugin" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-class-static-block@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz#dc8cc6e498f55692ac6b4b89e56d87cec766c974" - integrity sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g== +"@babel/plugin-transform-class-properties@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz#35c377db11ca92a785a718b6aa4e3ed1eb65dc48" + integrity sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.15" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-static-block@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz#2a202c8787a8964dd11dfcedf994d36bfc844ab5" + integrity sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.22.11" + "@babel/helper-create-class-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-transform-classes@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz#aaf4753aee262a232bbc95451b4bdf9599c65a0b" - integrity sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw== +"@babel/plugin-transform-classes@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz#e7a75f815e0c534cc4c9a39c56636c84fc0d64f2" + integrity sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" "@babel/helper-optimise-call-expression" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-replace-supers" "^7.22.20" "@babel/helper-split-export-declaration" "^7.22.6" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" - integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== +"@babel/plugin-transform-computed-properties@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz#652e69561fcc9d2b50ba4f7ac7f60dcf65e86474" + integrity sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" - "@babel/template" "^7.22.5" + "@babel/template" "^7.22.15" -"@babel/plugin-transform-destructuring@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz#6447aa686be48b32eaf65a73e0e2c0bd010a266c" - integrity sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg== +"@babel/plugin-transform-destructuring@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz#8c9ee68228b12ae3dff986e56ed1ba4f3c446311" + integrity sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-dotall-regex@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165" - integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw== +"@babel/plugin-transform-dotall-regex@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz#3f7af6054882ede89c378d0cf889b854a993da50" + integrity sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-create-regexp-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-duplicate-keys@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285" - integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw== +"@babel/plugin-transform-duplicate-keys@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz#664706ca0a5dfe8d066537f99032fc1dc8b720ce" + integrity sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-dynamic-import@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz#2c7722d2a5c01839eaf31518c6ff96d408e447aa" - integrity sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA== +"@babel/plugin-transform-dynamic-import@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz#c7629e7254011ac3630d47d7f34ddd40ca535143" + integrity sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-transform-exponentiation-operator@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a" - integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g== +"@babel/plugin-transform-exponentiation-operator@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz#ea0d978f6b9232ba4722f3dbecdd18f450babd18" + integrity sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-export-namespace-from@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz#b3c84c8f19880b6c7440108f8929caf6056db26c" - integrity sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw== +"@babel/plugin-transform-export-namespace-from@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz#084c7b25e9a5c8271e987a08cf85807b80283191" + integrity sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-transform-flow-strip-types@^7.18.6": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz#6aeca0adcb81dc627c8986e770bfaa4d9812aff5" - integrity sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w== +"@babel/plugin-transform-flow-strip-types@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.23.3.tgz#cfa7ca159cc3306fab526fc67091556b51af26ff" + integrity sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-flow" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-flow" "^7.23.3" -"@babel/plugin-transform-for-of@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz#f64b4ccc3a4f131a996388fae7680b472b306b29" - integrity sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA== +"@babel/plugin-transform-for-of@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz#81c37e24171b37b370ba6aaffa7ac86bcb46f94e" + integrity sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" -"@babel/plugin-transform-function-name@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" - integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== +"@babel/plugin-transform-function-name@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz#8f424fcd862bf84cb9a1a6b42bc2f47ed630f8dc" + integrity sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw== dependencies: - "@babel/helper-compilation-targets" "^7.22.5" - "@babel/helper-function-name" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-function-name" "^7.23.0" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-json-strings@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz#689a34e1eed1928a40954e37f74509f48af67835" - integrity sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw== +"@babel/plugin-transform-json-strings@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz#a871d9b6bd171976efad2e43e694c961ffa3714d" + integrity sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-transform-literals@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" - integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== +"@babel/plugin-transform-literals@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz#8214665f00506ead73de157eba233e7381f3beb4" + integrity sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-logical-assignment-operators@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz#24c522a61688bde045b7d9bc3c2597a4d948fc9c" - integrity sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ== +"@babel/plugin-transform-logical-assignment-operators@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz#e599f82c51d55fac725f62ce55d3a0886279ecb5" + integrity sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-transform-member-expression-literals@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" - integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== +"@babel/plugin-transform-member-expression-literals@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz#e37b3f0502289f477ac0e776b05a833d853cabcc" + integrity sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-amd@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.0.tgz#05b2bc43373faa6d30ca89214731f76f966f3b88" - integrity sha512-xWT5gefv2HGSm4QHtgc1sYPbseOyf+FFDo2JbpE25GWl5BqTGO9IMwTYJRoIdjsF85GE+VegHxSCUt5EvoYTAw== +"@babel/plugin-transform-modules-amd@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz#e19b55436a1416829df0a1afc495deedfae17f7d" + integrity sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw== dependencies: - "@babel/helper-module-transforms" "^7.23.0" + "@babel/helper-module-transforms" "^7.23.3" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-commonjs@^7.13.8": - version "7.21.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz#6ff5070e71e3192ef2b7e39820a06fb78e3058e7" - integrity sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA== - dependencies: - "@babel/helper-module-transforms" "^7.21.2" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-simple-access" "^7.20.2" - "@babel/plugin-transform-modules-commonjs@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz#b3dba4757133b2762c00f4f94590cf6d52602481" @@ -1089,22 +1151,31 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-simple-access" "^7.22.5" -"@babel/plugin-transform-modules-systemjs@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.0.tgz#77591e126f3ff4132a40595a6cccd00a6b60d160" - integrity sha512-qBej6ctXZD2f+DhlOC9yO47yEYgUh5CZNz/aBoH4j/3NOlRfJXJbY7xDQCqQVf9KbrqGzIWER1f23doHGrIHFg== +"@babel/plugin-transform-modules-commonjs@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz#661ae831b9577e52be57dd8356b734f9700b53b4" + integrity sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA== + dependencies: + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-modules-systemjs@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz#fa7e62248931cb15b9404f8052581c302dd9de81" + integrity sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ== dependencies: "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-module-transforms" "^7.23.0" + "@babel/helper-module-transforms" "^7.23.3" "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-validator-identifier" "^7.22.20" -"@babel/plugin-transform-modules-umd@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98" - integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ== +"@babel/plugin-transform-modules-umd@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz#5d4395fccd071dfefe6585a4411aa7d6b7d769e9" + integrity sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg== dependencies: - "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-module-transforms" "^7.23.3" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": @@ -1115,10 +1186,10 @@ "@babel/helper-create-regexp-features-plugin" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-new-target@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d" - integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw== +"@babel/plugin-transform-new-target@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz#5491bb78ed6ac87e990957cea367eab781c4d980" + integrity sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -1130,42 +1201,50 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-transform-numeric-separator@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz#498d77dc45a6c6db74bb829c02a01c1d719cbfbd" - integrity sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg== +"@babel/plugin-transform-nullish-coalescing-operator@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz#45556aad123fc6e52189ea749e33ce090637346e" + integrity sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz#03d08e3691e405804ecdd19dd278a40cca531f29" + integrity sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-transform-object-rest-spread@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz#21a95db166be59b91cde48775310c0df6e1da56f" - integrity sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q== +"@babel/plugin-transform-object-rest-spread@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz#2b9c2d26bf62710460bdc0d1730d4f1048361b83" + integrity sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g== dependencies: - "@babel/compat-data" "^7.22.9" + "@babel/compat-data" "^7.23.3" "@babel/helper-compilation-targets" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.22.15" + "@babel/plugin-transform-parameters" "^7.23.3" -"@babel/plugin-transform-object-super@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" - integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== +"@babel/plugin-transform-object-super@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz#81fdb636dcb306dd2e4e8fd80db5b2362ed2ebcd" + integrity sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.20" -"@babel/plugin-transform-optional-catch-binding@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz#461cc4f578a127bb055527b3e77404cad38c08e0" - integrity sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ== +"@babel/plugin-transform-optional-catch-binding@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz#318066de6dacce7d92fa244ae475aa8d91778017" + integrity sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.22.15", "@babel/plugin-transform-optional-chaining@^7.23.0": +"@babel/plugin-transform-optional-chaining@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.0.tgz#73ff5fc1cf98f542f09f29c0631647d8ad0be158" integrity sha512-sBBGXbLJjxTzLBF5rFWaikMnOGOk/BmK6vVByIdEggZ7Vn6CvWXZyRkkLFK6WE0IF8jSliyOkUN6SScFgzCM0g== @@ -1174,10 +1253,19 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-transform-parameters@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz#719ca82a01d177af358df64a514d64c2e3edb114" - integrity sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ== +"@babel/plugin-transform-optional-chaining@^7.23.3", "@babel/plugin-transform-optional-chaining@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz#6acf61203bdfc4de9d4e52e64490aeb3e52bd017" + integrity sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz#83ef5d1baf4b1072fa6e54b2b0999a7b2527e2af" + integrity sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -1189,20 +1277,28 @@ "@babel/helper-create-class-features-plugin" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-private-property-in-object@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz#ad45c4fc440e9cb84c718ed0906d96cf40f9a4e1" - integrity sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ== +"@babel/plugin-transform-private-methods@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz#b2d7a3c97e278bfe59137a978d53b2c2e038c0e4" + integrity sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.15" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-property-in-object@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz#3ec711d05d6608fd173d9b8de39872d8dbf68bf5" + integrity sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.22.11" + "@babel/helper-create-class-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-private-property-in-object" "^7.14.5" -"@babel/plugin-transform-property-literals@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" - integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== +"@babel/plugin-transform-property-literals@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz#54518f14ac4755d22b92162e4a852d308a560875" + integrity sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -1220,116 +1316,118 @@ dependencies: "@babel/helper-plugin-utils" "^7.19.0" -"@babel/plugin-transform-regenerator@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz#8ceef3bd7375c4db7652878b0241b2be5d0c3cca" - integrity sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw== +"@babel/plugin-transform-regenerator@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz#141afd4a2057298602069fce7f2dc5173e6c561c" + integrity sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" regenerator-transform "^0.15.2" -"@babel/plugin-transform-reserved-words@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb" - integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA== +"@babel/plugin-transform-reserved-words@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz#4130dcee12bd3dd5705c587947eb715da12efac8" + integrity sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-shorthand-properties@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" - integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== +"@babel/plugin-transform-shorthand-properties@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz#97d82a39b0e0c24f8a981568a8ed851745f59210" + integrity sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-spread@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" - integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== +"@babel/plugin-transform-spread@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz#41d17aacb12bde55168403c6f2d6bdca563d362c" + integrity sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" -"@babel/plugin-transform-sticky-regex@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa" - integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw== +"@babel/plugin-transform-sticky-regex@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz#dec45588ab4a723cb579c609b294a3d1bd22ff04" + integrity sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-template-literals@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" - integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== +"@babel/plugin-transform-template-literals@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz#5f0f028eb14e50b5d0f76be57f90045757539d07" + integrity sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-typeof-symbol@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34" - integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA== +"@babel/plugin-transform-typeof-symbol@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz#9dfab97acc87495c0c449014eb9c547d8966bca4" + integrity sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-typescript@^7.21.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.0.tgz#f0956a153679e3b377ae5b7f0143427151e4c848" - integrity sha512-xo///XTPp3mDzTtrqXoBlK9eiAYW3wv9JXglcn/u1bi60RW11dEUxIgA8cbnDhutS1zacjMRmAwxE0gMklLnZg== +"@babel/plugin-transform-typescript@^7.23.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz#aa36a94e5da8d94339ae3a4e22d40ed287feb34c" + integrity sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.21.0" - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/plugin-syntax-typescript" "^7.20.0" + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.23.6" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-typescript" "^7.23.3" -"@babel/plugin-transform-unicode-escapes@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz#c723f380f40a2b2f57a62df24c9005834c8616d9" - integrity sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg== +"@babel/plugin-transform-unicode-escapes@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz#1f66d16cab01fab98d784867d24f70c1ca65b925" + integrity sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-unicode-property-regex@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81" - integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A== +"@babel/plugin-transform-unicode-property-regex@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz#19e234129e5ffa7205010feec0d94c251083d7ad" + integrity sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-create-regexp-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-unicode-regex@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183" - integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg== +"@babel/plugin-transform-unicode-regex@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz#26897708d8f42654ca4ce1b73e96140fbad879dc" + integrity sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-create-regexp-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-unicode-sets-regex@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91" - integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg== +"@babel/plugin-transform-unicode-sets-regex@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz#4fb6f0a719c2c5859d11f6b55a050cc987f3799e" + integrity sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-create-regexp-features-plugin" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/preset-env@^7.22.9": - version "7.23.2" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.23.2.tgz#1f22be0ff0e121113260337dbc3e58fafce8d059" - integrity sha512-BW3gsuDD+rvHL2VO2SjAUNTBe5YrjsTiDyqamPDWY723na3/yPQ65X5oQkFVJZ0o50/2d+svm1rkPoJeR1KxVQ== +"@babel/preset-env@^7.23.2": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.23.6.tgz#ad0ea799d5a3c07db5b9a172819bbd444092187a" + integrity sha512-2XPn/BqKkZCpzYhUUNZ1ssXw7DcXfKQEjv/uXZUXgaebCMYmkEsfZ2yY+vv+xtXv50WmL5SGhyB6/xsWxIvvOQ== dependencies: - "@babel/compat-data" "^7.23.2" - "@babel/helper-compilation-targets" "^7.22.15" + "@babel/compat-data" "^7.23.5" + "@babel/helper-compilation-targets" "^7.23.6" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-validator-option" "^7.22.15" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.15" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.15" + "@babel/helper-validator-option" "^7.23.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.23.3" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.23.3" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.23.3" "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" "@babel/plugin-syntax-class-static-block" "^7.14.5" "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.22.5" - "@babel/plugin-syntax-import-attributes" "^7.22.5" + "@babel/plugin-syntax-import-assertions" "^7.23.3" + "@babel/plugin-syntax-import-attributes" "^7.23.3" "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" @@ -1341,70 +1439,69 @@ "@babel/plugin-syntax-private-property-in-object" "^7.14.5" "@babel/plugin-syntax-top-level-await" "^7.14.5" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" - "@babel/plugin-transform-arrow-functions" "^7.22.5" - "@babel/plugin-transform-async-generator-functions" "^7.23.2" - "@babel/plugin-transform-async-to-generator" "^7.22.5" - "@babel/plugin-transform-block-scoped-functions" "^7.22.5" - "@babel/plugin-transform-block-scoping" "^7.23.0" - "@babel/plugin-transform-class-properties" "^7.22.5" - "@babel/plugin-transform-class-static-block" "^7.22.11" - "@babel/plugin-transform-classes" "^7.22.15" - "@babel/plugin-transform-computed-properties" "^7.22.5" - "@babel/plugin-transform-destructuring" "^7.23.0" - "@babel/plugin-transform-dotall-regex" "^7.22.5" - "@babel/plugin-transform-duplicate-keys" "^7.22.5" - "@babel/plugin-transform-dynamic-import" "^7.22.11" - "@babel/plugin-transform-exponentiation-operator" "^7.22.5" - "@babel/plugin-transform-export-namespace-from" "^7.22.11" - "@babel/plugin-transform-for-of" "^7.22.15" - "@babel/plugin-transform-function-name" "^7.22.5" - "@babel/plugin-transform-json-strings" "^7.22.11" - "@babel/plugin-transform-literals" "^7.22.5" - "@babel/plugin-transform-logical-assignment-operators" "^7.22.11" - "@babel/plugin-transform-member-expression-literals" "^7.22.5" - "@babel/plugin-transform-modules-amd" "^7.23.0" - "@babel/plugin-transform-modules-commonjs" "^7.23.0" - "@babel/plugin-transform-modules-systemjs" "^7.23.0" - "@babel/plugin-transform-modules-umd" "^7.22.5" + "@babel/plugin-transform-arrow-functions" "^7.23.3" + "@babel/plugin-transform-async-generator-functions" "^7.23.4" + "@babel/plugin-transform-async-to-generator" "^7.23.3" + "@babel/plugin-transform-block-scoped-functions" "^7.23.3" + "@babel/plugin-transform-block-scoping" "^7.23.4" + "@babel/plugin-transform-class-properties" "^7.23.3" + "@babel/plugin-transform-class-static-block" "^7.23.4" + "@babel/plugin-transform-classes" "^7.23.5" + "@babel/plugin-transform-computed-properties" "^7.23.3" + "@babel/plugin-transform-destructuring" "^7.23.3" + "@babel/plugin-transform-dotall-regex" "^7.23.3" + "@babel/plugin-transform-duplicate-keys" "^7.23.3" + "@babel/plugin-transform-dynamic-import" "^7.23.4" + "@babel/plugin-transform-exponentiation-operator" "^7.23.3" + "@babel/plugin-transform-export-namespace-from" "^7.23.4" + "@babel/plugin-transform-for-of" "^7.23.6" + "@babel/plugin-transform-function-name" "^7.23.3" + "@babel/plugin-transform-json-strings" "^7.23.4" + "@babel/plugin-transform-literals" "^7.23.3" + "@babel/plugin-transform-logical-assignment-operators" "^7.23.4" + "@babel/plugin-transform-member-expression-literals" "^7.23.3" + "@babel/plugin-transform-modules-amd" "^7.23.3" + "@babel/plugin-transform-modules-commonjs" "^7.23.3" + "@babel/plugin-transform-modules-systemjs" "^7.23.3" + "@babel/plugin-transform-modules-umd" "^7.23.3" "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" - "@babel/plugin-transform-new-target" "^7.22.5" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.11" - "@babel/plugin-transform-numeric-separator" "^7.22.11" - "@babel/plugin-transform-object-rest-spread" "^7.22.15" - "@babel/plugin-transform-object-super" "^7.22.5" - "@babel/plugin-transform-optional-catch-binding" "^7.22.11" - "@babel/plugin-transform-optional-chaining" "^7.23.0" - "@babel/plugin-transform-parameters" "^7.22.15" - "@babel/plugin-transform-private-methods" "^7.22.5" - "@babel/plugin-transform-private-property-in-object" "^7.22.11" - "@babel/plugin-transform-property-literals" "^7.22.5" - "@babel/plugin-transform-regenerator" "^7.22.10" - "@babel/plugin-transform-reserved-words" "^7.22.5" - "@babel/plugin-transform-shorthand-properties" "^7.22.5" - "@babel/plugin-transform-spread" "^7.22.5" - "@babel/plugin-transform-sticky-regex" "^7.22.5" - "@babel/plugin-transform-template-literals" "^7.22.5" - "@babel/plugin-transform-typeof-symbol" "^7.22.5" - "@babel/plugin-transform-unicode-escapes" "^7.22.10" - "@babel/plugin-transform-unicode-property-regex" "^7.22.5" - "@babel/plugin-transform-unicode-regex" "^7.22.5" - "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.23.3" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.23.4" + "@babel/plugin-transform-numeric-separator" "^7.23.4" + "@babel/plugin-transform-object-rest-spread" "^7.23.4" + "@babel/plugin-transform-object-super" "^7.23.3" + "@babel/plugin-transform-optional-catch-binding" "^7.23.4" + "@babel/plugin-transform-optional-chaining" "^7.23.4" + "@babel/plugin-transform-parameters" "^7.23.3" + "@babel/plugin-transform-private-methods" "^7.23.3" + "@babel/plugin-transform-private-property-in-object" "^7.23.4" + "@babel/plugin-transform-property-literals" "^7.23.3" + "@babel/plugin-transform-regenerator" "^7.23.3" + "@babel/plugin-transform-reserved-words" "^7.23.3" + "@babel/plugin-transform-shorthand-properties" "^7.23.3" + "@babel/plugin-transform-spread" "^7.23.3" + "@babel/plugin-transform-sticky-regex" "^7.23.3" + "@babel/plugin-transform-template-literals" "^7.23.3" + "@babel/plugin-transform-typeof-symbol" "^7.23.3" + "@babel/plugin-transform-unicode-escapes" "^7.23.3" + "@babel/plugin-transform-unicode-property-regex" "^7.23.3" + "@babel/plugin-transform-unicode-regex" "^7.23.3" + "@babel/plugin-transform-unicode-sets-regex" "^7.23.3" "@babel/preset-modules" "0.1.6-no-external-plugins" - "@babel/types" "^7.23.0" babel-plugin-polyfill-corejs2 "^0.4.6" babel-plugin-polyfill-corejs3 "^0.8.5" babel-plugin-polyfill-regenerator "^0.5.3" core-js-compat "^3.31.0" semver "^6.3.1" -"@babel/preset-flow@^7.13.13": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.18.6.tgz#83f7602ba566e72a9918beefafef8ef16d2810cb" - integrity sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ== +"@babel/preset-flow@^7.22.15": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.23.3.tgz#8084e08b9ccec287bd077ab288b286fab96ffab1" + integrity sha512-7yn6hl8RIv+KNk6iIrGZ+D06VhVY35wLVf23Cz/mMu1zOr7u4MMP4j0nZ9tLf8+4ZFpnib8cFYgB/oYg9hfswA== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-transform-flow-strip-types" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.15" + "@babel/plugin-transform-flow-strip-types" "^7.23.3" "@babel/preset-modules@0.1.6-no-external-plugins": version "0.1.6-no-external-plugins" @@ -1415,19 +1512,21 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-typescript@^7.13.0": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.21.0.tgz#bcbbca513e8213691fe5d4b23d9251e01f00ebff" - integrity sha512-myc9mpoVA5m1rF8K8DgLEatOYFDpwC+RkMkjZ0Du6uI62YvDe8uxIEYVs/VCdSJ097nlALiU/yBC7//3nI+hNg== +"@babel/preset-typescript@^7.23.0": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz#14534b34ed5b6d435aa05f1ae1c5e7adcc01d913" + integrity sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ== dependencies: - "@babel/helper-plugin-utils" "^7.20.2" - "@babel/helper-validator-option" "^7.21.0" - "@babel/plugin-transform-typescript" "^7.21.0" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.15" + "@babel/plugin-syntax-jsx" "^7.23.3" + "@babel/plugin-transform-modules-commonjs" "^7.23.3" + "@babel/plugin-transform-typescript" "^7.23.3" -"@babel/register@^7.13.16": - version "7.21.0" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.21.0.tgz#c97bf56c2472e063774f31d344c592ebdcefa132" - integrity sha512-9nKsPmYDi5DidAqJaQooxIhsLJiNMkGr8ypQ8Uic7cIox7UCDsM7HuUGxdGT7mSDTYbqzIdsOWzfBton/YJrMw== +"@babel/register@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.22.15.tgz#c2c294a361d59f5fa7bcc8b97ef7319c32ecaec7" + integrity sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg== dependencies: clone-deep "^4.0.1" find-cache-dir "^2.0.0" @@ -1448,7 +1547,7 @@ core-js-pure "^3.25.1" regenerator-runtime "^0.13.11" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.14.6", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.0.tgz#5b55c9d394e5fcf304909a8b00c07dc217b56673" integrity sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw== @@ -1487,7 +1586,7 @@ "@babel/parser" "^7.21.9" "@babel/types" "^7.21.5" -"@babel/template@^7.22.15", "@babel/template@^7.22.5": +"@babel/template@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== @@ -1496,7 +1595,7 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.18.9", "@babel/traverse@^7.22.8", "@babel/traverse@^7.23.2": +"@babel/traverse@^7.18.9", "@babel/traverse@^7.23.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== @@ -1512,7 +1611,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.7.0": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75" integrity sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw== @@ -1544,7 +1643,23 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0": +"@babel/traverse@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.6.tgz#b53526a2367a0dd6edc423637f3d2d0f2521abc5" + integrity sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.3.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== @@ -1580,6 +1695,24 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.23.3": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.5.tgz#48d730a00c95109fa4393352705954d74fb5b602" + integrity sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@babel/types@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@base2/pretty-print-object@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz#371ba8be66d556812dc7fb169ebc3c08378f69d4" @@ -1920,111 +2053,221 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== +"@esbuild/android-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz#fb7130103835b6d43ea499c3f30cfb2b2ed58456" + integrity sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA== + "@esbuild/android-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== +"@esbuild/android-arm@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.8.tgz#b46e4d9e984e6d6db6c4224d72c86b7757e35bcb" + integrity sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA== + "@esbuild/android-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== +"@esbuild/android-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.8.tgz#a13db9441b5a4f4e4fec4a6f8ffacfea07888db7" + integrity sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A== + "@esbuild/darwin-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== +"@esbuild/darwin-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz#49f5718d36541f40dd62bfdf84da9c65168a0fc2" + integrity sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw== + "@esbuild/darwin-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== +"@esbuild/darwin-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz#75c5c88371eea4bfc1f9ecfd0e75104c74a481ac" + integrity sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q== + "@esbuild/freebsd-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== +"@esbuild/freebsd-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz#9d7259fea4fd2b5f7437b52b542816e89d7c8575" + integrity sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw== + "@esbuild/freebsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== +"@esbuild/freebsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz#abac03e1c4c7c75ee8add6d76ec592f46dbb39e3" + integrity sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg== + "@esbuild/linux-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== +"@esbuild/linux-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz#c577932cf4feeaa43cb9cec27b89cbe0df7d9098" + integrity sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ== + "@esbuild/linux-arm@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== +"@esbuild/linux-arm@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz#d6014d8b98b5cbc96b95dad3d14d75bb364fdc0f" + integrity sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ== + "@esbuild/linux-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== +"@esbuild/linux-ia32@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz#2379a0554307d19ac4a6cdc15b08f0ea28e7a40d" + integrity sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ== + "@esbuild/linux-loong64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== +"@esbuild/linux-loong64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz#e2a5bbffe15748b49356a6cd7b2d5bf60c5a7123" + integrity sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ== + "@esbuild/linux-mips64el@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== +"@esbuild/linux-mips64el@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz#1359331e6f6214f26f4b08db9b9df661c57cfa24" + integrity sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q== + "@esbuild/linux-ppc64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== +"@esbuild/linux-ppc64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz#9ba436addc1646dc89dae48c62d3e951ffe70951" + integrity sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg== + "@esbuild/linux-riscv64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== +"@esbuild/linux-riscv64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz#fbcf0c3a0b20f40b5fc31c3b7695f0769f9de66b" + integrity sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg== + "@esbuild/linux-s390x@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== +"@esbuild/linux-s390x@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz#989e8a05f7792d139d5564ffa7ff898ac6f20a4a" + integrity sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg== + "@esbuild/linux-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== +"@esbuild/linux-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz#b187295393a59323397fe5ff51e769ec4e72212b" + integrity sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg== + "@esbuild/netbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== +"@esbuild/netbsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz#c1ec0e24ea82313cb1c7bae176bd5acd5bde7137" + integrity sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw== + "@esbuild/openbsd-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== +"@esbuild/openbsd-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz#0c5b696ac66c6d70cf9ee17073a581a28af9e18d" + integrity sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ== + "@esbuild/sunos-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== +"@esbuild/sunos-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz#2a697e1f77926ff09fcc457d8f29916d6cd48fb1" + integrity sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w== + "@esbuild/win32-arm64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== +"@esbuild/win32-arm64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz#ec029e62a2fca8c071842ecb1bc5c2dd20b066f1" + integrity sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg== + "@esbuild/win32-ia32@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== +"@esbuild/win32-ia32@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz#cbb9a3146bde64dc15543e48afe418c7a3214851" + integrity sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw== + "@esbuild/win32-x64@0.18.20": version "0.18.20" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== +"@esbuild/win32-x64@0.19.8": + version "0.19.8" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz#c8285183dbdb17008578dbacb6e22748709b4822" + integrity sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2384,29 +2627,6 @@ csstype "^3.1.2" prop-types "^15.8.1" -"@mui/styles@^5.14.7": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/styles/-/styles-5.14.7.tgz#e704f465b39e6dbfcd30090b191cf8140f7a9e42" - integrity sha512-5qA81gIRBUd3ur2FtGO10UmArpqaGWL+eUGFVSf68SjhahhHr86/JgqsXqUPyW/LPnyW92SZxhQ6El6Co8i7AQ== - dependencies: - "@babel/runtime" "^7.22.10" - "@emotion/hash" "^0.9.1" - "@mui/private-theming" "^5.14.7" - "@mui/types" "^7.2.4" - "@mui/utils" "^5.14.7" - clsx "^2.0.0" - csstype "^3.1.2" - hoist-non-react-statics "^3.3.2" - jss "^10.10.0" - jss-plugin-camel-case "^10.10.0" - jss-plugin-default-unit "^10.10.0" - jss-plugin-global "^10.10.0" - jss-plugin-nested "^10.10.0" - jss-plugin-props-sort "^10.10.0" - jss-plugin-rule-value-function "^10.10.0" - jss-plugin-vendor-prefixer "^10.10.0" - prop-types "^15.8.1" - "@mui/system@^5.14.7": version "5.14.7" resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.7.tgz#b08e23f9151d38186ab12dd618906abd4d73d203" @@ -2844,6 +3064,66 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@rollup/rollup-android-arm-eabi@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz#0ea289f68ff248b50fea5716ca9f65f7d4dba3ae" + integrity sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA== + +"@rollup/rollup-android-arm64@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.6.1.tgz#27c8c67fc5de574874085a1b480ac65b3e18378e" + integrity sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA== + +"@rollup/rollup-darwin-arm64@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.6.1.tgz#c5735c042980c85495411af7183dd20294763bd8" + integrity sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw== + +"@rollup/rollup-darwin-x64@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.6.1.tgz#af844bd54abb73ca3c9cf89a31eec17861d1375d" + integrity sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg== + +"@rollup/rollup-linux-arm-gnueabihf@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.6.1.tgz#5e972f63c441eaf859551039b3f18db9b035977d" + integrity sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ== + +"@rollup/rollup-linux-arm64-gnu@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.6.1.tgz#f4cfbc71e3b6fdb395b28b1472414e181515c72d" + integrity sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw== + +"@rollup/rollup-linux-arm64-musl@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.6.1.tgz#6a94c691830dc29bf708de7c640f494996130893" + integrity sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw== + +"@rollup/rollup-linux-x64-gnu@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.6.1.tgz#f07bae3f7dc532d9ea5ab36c9071db329f9a1efb" + integrity sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA== + +"@rollup/rollup-linux-x64-musl@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.6.1.tgz#357a34fdbf410af88ce48bd802bea6462bb9a8bc" + integrity sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ== + +"@rollup/rollup-win32-arm64-msvc@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.6.1.tgz#b6e97fd38281667e35297033393cd1101f4a31be" + integrity sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ== + +"@rollup/rollup-win32-ia32-msvc@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.6.1.tgz#a95db026c640c8128bfd38546d85342f2329beaf" + integrity sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw== + +"@rollup/rollup-win32-x64-msvc@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.6.1.tgz#45785b5caf83200a34a9867ba50d69560880c120" + integrity sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A== + "@sentry-internal/tracing@7.57.0": version "7.57.0" resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.57.0.tgz#cb761931b635f8f24c84be0eecfacb8516b20551" @@ -2918,99 +3198,75 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@storybook/addon-actions@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-7.5.2.tgz#8b692a4c4d62115ed3b93f9fd2aeecdc0a02e3f5" - integrity sha512-jKF3rrMEu42TgZ5AEszADpVdASDu1S4Ozp1Ymf4akHLkaMOv+yzzD7LV6YGjJz8S2IryndZqE47e6stF0T99uA== +"@storybook/addon-actions@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-7.6.4.tgz#b2d2941baa926718f0c53581c8cc8b19c2e0393b" + integrity sha512-91UD5KPDik74VKVioPMcbwwvDXN/non8p1wArYAHCHCmd/Pts5MJRiFueSdfomSpNjUtjtn6eSXtwpIL3XVOfQ== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/components" "7.5.2" - "@storybook/core-events" "7.5.2" + "@storybook/core-events" "7.6.4" "@storybook/global" "^5.0.0" - "@storybook/manager-api" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/theming" "7.5.2" - "@storybook/types" "7.5.2" - dequal "^2.0.2" - lodash "^4.17.21" - polished "^4.2.2" - prop-types "^15.7.2" - react-inspector "^6.0.0" - telejson "^7.2.0" - ts-dedent "^2.0.0" + "@types/uuid" "^9.0.1" + dequal "^2.0.2" + polished "^4.2.2" uuid "^9.0.0" -"@storybook/addon-controls@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-7.5.2.tgz#02c35855151cac989df7dee3b76a9eb0b09d7d1d" - integrity sha512-f04VcBSfm3yMT1hvaFEwCRbdwiXQbddfEwhwjEVsqd+CA0s600W4L7B8tT4daXMsU6NsZyibev910IKTnDw6xQ== - dependencies: - "@storybook/blocks" "7.5.2" - "@storybook/client-logger" "7.5.2" - "@storybook/components" "7.5.2" - "@storybook/core-common" "7.5.2" - "@storybook/core-events" "7.5.2" - "@storybook/manager-api" "7.5.2" - "@storybook/node-logger" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/theming" "7.5.2" - "@storybook/types" "7.5.2" +"@storybook/addon-controls@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/addon-controls/-/addon-controls-7.6.4.tgz#8f8651a1e929f5f8506d025bcc5c3e454444b1c3" + integrity sha512-k4AtZfazmD/nL3JAtLGAB7raPhkhUo0jWnaZWrahd9h1Fm13mBU/RW+JzTRhCw3Mp2HPERD7NI5Qcd2fUP6WDA== + dependencies: + "@storybook/blocks" "7.6.4" lodash "^4.17.21" ts-dedent "^2.0.0" -"@storybook/addon-docs@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-7.5.2.tgz#58a55912751167dfcf998ae5207d0c300e17991d" - integrity sha512-KxX4XuxK6YcI2mUosFkAlueMon/nby6mp3GRHenuK+nobY0ecfILqSTbsOeO1wqPxALBoq7fLnrgYhdDlandgQ== +"@storybook/addon-docs@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/addon-docs/-/addon-docs-7.6.4.tgz#e15ab003482d5c43da43edae8557ac6e0988017e" + integrity sha512-PbFMbvC9sK3sGdMhwmagXs9TqopTp9FySji+L8O7W9SHRC6wSmdwoWWPWybkOYxr/z/wXi7EM0azSAX7yQxLbw== dependencies: "@jest/transform" "^29.3.1" "@mdx-js/react" "^2.1.5" - "@storybook/blocks" "7.5.2" - "@storybook/client-logger" "7.5.2" - "@storybook/components" "7.5.2" - "@storybook/csf-plugin" "7.5.2" - "@storybook/csf-tools" "7.5.2" + "@storybook/blocks" "7.6.4" + "@storybook/client-logger" "7.6.4" + "@storybook/components" "7.6.4" + "@storybook/csf-plugin" "7.6.4" + "@storybook/csf-tools" "7.6.4" "@storybook/global" "^5.0.0" "@storybook/mdx2-csf" "^1.0.0" - "@storybook/node-logger" "7.5.2" - "@storybook/postinstall" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/react-dom-shim" "7.5.2" - "@storybook/theming" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/node-logger" "7.6.4" + "@storybook/postinstall" "7.6.4" + "@storybook/preview-api" "7.6.4" + "@storybook/react-dom-shim" "7.6.4" + "@storybook/theming" "7.6.4" + "@storybook/types" "7.6.4" fs-extra "^11.1.0" remark-external-links "^8.0.0" remark-slug "^6.0.0" ts-dedent "^2.0.0" -"@storybook/addon-measure@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-7.5.2.tgz#7908589225bcab26a27e636d02fce0edb4c2621f" - integrity sha512-fkvORLaYVC/yNMFzHRHmzlvniY7sWtpFxaRW+e4++hGXYV4VQjOBlXzdMxQhAg1DCVWD6QV8xnUQPBGrsEklog== +"@storybook/addon-measure@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/addon-measure/-/addon-measure-7.6.4.tgz#0597ae04a27ff596bc8f2015f7c746b33eef78a3" + integrity sha512-73wsJ8PALsgWniR3MA/cmxcFuU6cRruWdIyYzOMgM8ife2Jm3xSkV7cTTXAqXt2H9Uuki4PGnuMHWWFLpPeyVA== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/components" "7.5.2" - "@storybook/core-events" "7.5.2" "@storybook/global" "^5.0.0" - "@storybook/manager-api" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/types" "7.5.2" tiny-invariant "^1.3.1" -"@storybook/addon-viewport@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-7.5.2.tgz#f85136ec35445a9c310c73ec248173a1ef401f79" - integrity sha512-qN5X9vgp0v+WGXyFBHQ/CqjdtmnCoHhUjqXmBxEGBziJz/tZwWwtTGWeUUZpuTjCGiZutLrizOFl5MqQAI+ipg== +"@storybook/addon-storysource@^7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/addon-storysource/-/addon-storysource-7.6.4.tgz#a94c1127af66ed90c149b89a2648e1fdc8739326" + integrity sha512-D63IB8bkqn5ZDq4yjvkcLVfGz3OcAQUohlxSFR1e7COo8jMSTiQWjN7xaVPNOnVJRCj6GrlRlto/hqGl+F+WiQ== + dependencies: + "@storybook/source-loader" "7.6.4" + estraverse "^5.2.0" + tiny-invariant "^1.3.1" + +"@storybook/addon-viewport@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/addon-viewport/-/addon-viewport-7.6.4.tgz#f39601082f48a903c47cae71a84b05428ea20331" + integrity sha512-SoTcHIoqybhYD28v7QExF1EZnl7FfxuP74VDhtze5LyMd2CbqmVnUfwewLCz/3IvCNce0GqdNyg1m6QJ7Eq1uw== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/components" "7.5.2" - "@storybook/core-events" "7.5.2" - "@storybook/global" "^5.0.0" - "@storybook/manager-api" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/theming" "7.5.2" memoizerific "^1.11.3" - prop-types "^15.7.2" "@storybook/addons@^7.0.0": version "7.0.7" @@ -3021,39 +3277,31 @@ "@storybook/preview-api" "7.0.7" "@storybook/types" "7.0.7" -"@storybook/addons@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-7.5.2.tgz#749c597d669ae090864c30c795203e6e04607a46" - integrity sha512-hRiy56zQbz72Pwa4F40srUWXKGNIriNkZ1R0j5KPd8ZqoMk1hIeW0S8E7s1vuM/MplnUE/jFJZqu6HQCvbqmGg== - dependencies: - "@storybook/manager-api" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/types" "7.5.2" - -"@storybook/api@^7.0.0": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@storybook/api/-/api-7.0.7.tgz#ae2c3f435b025f0aac86da1033ad3f0cbceb6ef4" - integrity sha512-0++LcK6PX1Z2HsI9fyZyqvmeFrB5NDMcsbmIvJfA2NfK92UW8y7t6Ft2fq/2jUCJcWT8Jp3xpatUvYb28irfwg== +"@storybook/addons@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-7.6.4.tgz#35d1cf97e8dc1477fc154bfec798d4b829889519" + integrity sha512-YnmLyR/ciALtzoi9HEu+Y+NJWeOVEBo9PRgQaG7zGiNDvOrLY69uU3Ej0+TZlrTqBqce42bRCrDINJfnk0Mfsg== dependencies: - "@storybook/client-logger" "7.0.7" - "@storybook/manager-api" "7.0.7" + "@storybook/manager-api" "7.6.4" + "@storybook/preview-api" "7.6.4" + "@storybook/types" "7.6.4" -"@storybook/blocks@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-7.5.2.tgz#625105555911ebb1415a3e5f4aeedf38e608a340" - integrity sha512-Tf6XE/YcnWQVBJRcJWJzhkahjSymv6QZuxMAiKFD8v48QRJ8kTxz1tBN9676Ux+l1WwtVWxwvd/0kRKKxE70wQ== - dependencies: - "@storybook/channels" "7.5.2" - "@storybook/client-logger" "7.5.2" - "@storybook/components" "7.5.2" - "@storybook/core-events" "7.5.2" - "@storybook/csf" "^0.1.0" - "@storybook/docs-tools" "7.5.2" +"@storybook/blocks@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/blocks/-/blocks-7.6.4.tgz#f5d0de020b886e0fd17021608df5b73e5e39ae69" + integrity sha512-iXinXXhTUBtReREP1Jifpu35DnGg7FidehjvCM8sM4E4aymfb8czdg9DdvG46T2UFUPUct36nnjIdMLWOya8Bw== + dependencies: + "@storybook/channels" "7.6.4" + "@storybook/client-logger" "7.6.4" + "@storybook/components" "7.6.4" + "@storybook/core-events" "7.6.4" + "@storybook/csf" "^0.1.2" + "@storybook/docs-tools" "7.6.4" "@storybook/global" "^5.0.0" - "@storybook/manager-api" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/theming" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/manager-api" "7.6.4" + "@storybook/preview-api" "7.6.4" + "@storybook/theming" "7.6.4" + "@storybook/types" "7.6.4" "@types/lodash" "^4.14.167" color-convert "^2.0.1" dequal "^2.0.2" @@ -3067,15 +3315,15 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/builder-manager@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/builder-manager/-/builder-manager-7.5.2.tgz#326fb75298b0bd534e2adfc28cfe860cc5db1759" - integrity sha512-s4gOudrft/E4lQ19YNrzL2VJwMEpdY6z319fTlc16J1F6XZSytw6CIZPs3x9yX5CKf4/leWnN5etODaOx7NajQ== +"@storybook/builder-manager@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/builder-manager/-/builder-manager-7.6.4.tgz#64d4745f918bf370924b767cc3a767818fa45a47" + integrity sha512-k5+D3fXw7LdMOWd5tF7cIq8L3irrdW6/vmcEHLaJj1EXZ+DvsNCH9xSsLS+6zfrUcxug4oSfRqvF87w6Oz3DtA== dependencies: "@fal-works/esbuild-plugin-global-externals" "^2.1.2" - "@storybook/core-common" "7.5.2" - "@storybook/manager" "7.5.2" - "@storybook/node-logger" "7.5.2" + "@storybook/core-common" "7.6.4" + "@storybook/manager" "7.6.4" + "@storybook/node-logger" "7.6.4" "@types/ejs" "^3.1.1" "@types/find-cache-dir" "^3.2.1" "@yarnpkg/esbuild-plugin-pnp" "^3.0.0-rc.10" @@ -3089,19 +3337,19 @@ process "^0.11.10" util "^0.12.4" -"@storybook/builder-vite@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/builder-vite/-/builder-vite-7.5.2.tgz#af144e71ea07e137650212bcc0af060fae62fdd5" - integrity sha512-j96m5K0ahlAjQY6uUxEbybvmRFc3eMpQ3wiosuunc8NkXtfohXZeRVQowAcVrfPktKMufRNGY86RTYxe7sMABw== - dependencies: - "@storybook/channels" "7.5.2" - "@storybook/client-logger" "7.5.2" - "@storybook/core-common" "7.5.2" - "@storybook/csf-plugin" "7.5.2" - "@storybook/node-logger" "7.5.2" - "@storybook/preview" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/types" "7.5.2" +"@storybook/builder-vite@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/builder-vite/-/builder-vite-7.6.4.tgz#a9baaf41731c1da63a9f70bd015975b638f95bc5" + integrity sha512-eqb3mLUfuXd4a7+46cWevQ9qH81FvHy1lrAbZGwp4bQ/Tj0YF8Ej7lKBbg7zoIwiu2zDci+BbMiaDOY1kPtILw== + dependencies: + "@storybook/channels" "7.6.4" + "@storybook/client-logger" "7.6.4" + "@storybook/core-common" "7.6.4" + "@storybook/csf-plugin" "7.6.4" + "@storybook/node-logger" "7.6.4" + "@storybook/preview" "7.6.4" + "@storybook/preview-api" "7.6.4" + "@storybook/types" "7.6.4" "@types/find-cache-dir" "^3.2.1" browser-assert "^1.2.1" es-module-lexer "^0.9.3" @@ -3128,35 +3376,35 @@ resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.0.7.tgz#3f3962be97b447752db99a78ef7beea9f94d75a4" integrity sha512-Om4ovBLNw8pVrBu83MpOKgAuGO9Dpr1Coh2qp8t64WRPkejX1mxOY9IgH723//zH3igx8LCkf9rvBvcrsyaScQ== -"@storybook/channels@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.5.2.tgz#f5ea597a799e13b7307fe79067faede5e13e6619" - integrity sha512-3SgqWq9NS0XX1QxK3riuaOLrReHWwVhI63u6q1ryDD3SttpmAezZETibOAtzDuk2FKgsyHTmAlmcGQf4ZxhOJA== +"@storybook/channels@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-7.6.4.tgz#d0af47f1f049c3ad77bcdefec54253f56b3b0a47" + integrity sha512-Z4PY09/Czl70ap4ObmZ4bgin+EQhPaA3HdrEDNwpnH7A9ttfEO5u5KThytIjMq6kApCCihmEPDaYltoVrfYJJA== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/core-events" "7.5.2" + "@storybook/client-logger" "7.6.4" + "@storybook/core-events" "7.6.4" "@storybook/global" "^5.0.0" qs "^6.10.0" telejson "^7.2.0" tiny-invariant "^1.3.1" -"@storybook/cli@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/cli/-/cli-7.5.2.tgz#f5ef6edfecd048856b4fc9d89e4dfacc610562e5" - integrity sha512-8JPvA/K66zBmRFpRRwsD0JLqZUODRrGmNuAWx+Bj1K8wqbg68MYnOflbkSIxIVxrfhd39OrffV0h8CwKNL9gAg== +"@storybook/cli@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/cli/-/cli-7.6.4.tgz#3680233a32975a400c091341f8b6ae4cdb01c72f" + integrity sha512-GqvaFdkkBMJOdnrVe82XY0V3b+qFMhRNyVoTv2nqB87iMUXZHqh4Pu4LqwaJBsBpuNregvCvVOPe9LGgoOzy4A== dependencies: - "@babel/core" "^7.22.9" - "@babel/preset-env" "^7.22.9" - "@babel/types" "^7.22.5" + "@babel/core" "^7.23.2" + "@babel/preset-env" "^7.23.2" + "@babel/types" "^7.23.0" "@ndelangen/get-tarball" "^3.0.7" - "@storybook/codemod" "7.5.2" - "@storybook/core-common" "7.5.2" - "@storybook/core-events" "7.5.2" - "@storybook/core-server" "7.5.2" - "@storybook/csf-tools" "7.5.2" - "@storybook/node-logger" "7.5.2" - "@storybook/telemetry" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/codemod" "7.6.4" + "@storybook/core-common" "7.6.4" + "@storybook/core-events" "7.6.4" + "@storybook/core-server" "7.6.4" + "@storybook/csf-tools" "7.6.4" + "@storybook/node-logger" "7.6.4" + "@storybook/telemetry" "7.6.4" + "@storybook/types" "7.6.4" "@types/semver" "^7.3.4" "@yarnpkg/fslib" "2.10.3" "@yarnpkg/libzip" "2.3.0" @@ -3173,7 +3421,7 @@ get-port "^5.1.1" giget "^1.0.0" globby "^11.0.2" - jscodeshift "^0.14.0" + jscodeshift "^0.15.1" leven "^3.1.0" ora "^5.4.1" prettier "^2.8.0" @@ -3187,13 +3435,13 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/client-api@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-7.5.2.tgz#ccfd86baacfedd74d4e81a3fe5ca3a85ddb75118" - integrity sha512-GXNCtW3itUux++q2m6cuyA3Lys27sp1RvQqpd6njkN2zGRSmvUdSrHphmyRiilYxsqNiRfFcm7H4hb6hNrgsJQ== +"@storybook/client-api@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-7.6.4.tgz#724764f2459520682a0ce9aa3315317169b821bd" + integrity sha512-EzuOUdbjK78Y4y71drpRg1DC/iuzEMB6FIey64EI8edgfs+HAmEtzH8bNfmX7gxgA82RwxO0TGuXFF0CmWOABA== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/preview-api" "7.5.2" + "@storybook/client-logger" "7.6.4" + "@storybook/preview-api" "7.6.4" "@storybook/client-logger@7.0.7": version "7.0.7" @@ -3202,45 +3450,45 @@ dependencies: "@storybook/global" "^5.0.0" -"@storybook/client-logger@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.5.2.tgz#ffe6fd3cb336fc7dac6670412c4c8bf70e89c1d1" - integrity sha512-7YgLItlmiYDzWYexTaRNuHhtFarh9krsI+8l7Yjn9ryoHSTJUcTWx+yPJm1II+PQR8v/x5UgsxzultjgEurfRQ== +"@storybook/client-logger@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-7.6.4.tgz#7533f5194903f554c297b0d327efee04c5accfbb" + integrity sha512-vJwMShC98tcoFruRVQ4FphmFqvAZX1FqZqjFyk6IxtFumPKTVSnXJjlU1SnUIkSK2x97rgdUMqkdI+wAv/tugQ== dependencies: "@storybook/global" "^5.0.0" -"@storybook/codemod@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/codemod/-/codemod-7.5.2.tgz#d59942fb6d86cdf1c482ddc7a8450d58bfbbbca2" - integrity sha512-PxZg0w4OlmFB4dBzB+sCgwmHNke0n1N8vNooxtcuusrLKlbUfmssYRnQn6yRSJw0WfkUYgI10CWxGaamaOFekA== +"@storybook/codemod@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/codemod/-/codemod-7.6.4.tgz#e3a314ad07f9dc799bd2531bb7ffc6ab3cf15996" + integrity sha512-q4rZVOfozxzbDRH/LzuFDoIGBdXs+orAm18fi6iAx8PeMHe8J/MOXKccNV1zdkm/h7mTQowuRo45KwJHw8vX+g== dependencies: - "@babel/core" "^7.22.9" - "@babel/preset-env" "^7.22.9" - "@babel/types" "^7.22.5" - "@storybook/csf" "^0.1.0" - "@storybook/csf-tools" "7.5.2" - "@storybook/node-logger" "7.5.2" - "@storybook/types" "7.5.2" + "@babel/core" "^7.23.2" + "@babel/preset-env" "^7.23.2" + "@babel/types" "^7.23.0" + "@storybook/csf" "^0.1.2" + "@storybook/csf-tools" "7.6.4" + "@storybook/node-logger" "7.6.4" + "@storybook/types" "7.6.4" "@types/cross-spawn" "^6.0.2" cross-spawn "^7.0.3" globby "^11.0.2" - jscodeshift "^0.14.0" + jscodeshift "^0.15.1" lodash "^4.17.21" prettier "^2.8.0" recast "^0.23.1" -"@storybook/components@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/components/-/components-7.5.2.tgz#5409236b5b1b5d0189707cd76ea99220e3673884" - integrity sha512-OP+o6AoxoQDbqjk/jdQ1arlc1T8601eCL+rS1dJY9EtAFq7Z0LEFtafhEW/Lx8FotfVGjfCNptH9ODhHU6e5Jw== +"@storybook/components@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/components/-/components-7.6.4.tgz#44cf5fa1b52af540157b4dee7d23a46817329ab1" + integrity sha512-K5RvEObJAnX+SbGJbkM1qrZEk+VR2cUhRCSrFnlfMwsn8/60T3qoH7U8bCXf8krDgbquhMwqev5WzDB+T1VV8g== dependencies: "@radix-ui/react-select" "^1.2.2" "@radix-ui/react-toolbar" "^1.0.4" - "@storybook/client-logger" "7.5.2" - "@storybook/csf" "^0.1.0" + "@storybook/client-logger" "7.6.4" + "@storybook/csf" "^0.1.2" "@storybook/global" "^5.0.0" - "@storybook/theming" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/theming" "7.6.4" + "@storybook/types" "7.6.4" memoizerific "^1.11.3" use-resize-observer "^9.1.0" util-deprecate "^1.0.2" @@ -3259,22 +3507,22 @@ use-resize-observer "^9.1.0" util-deprecate "^1.0.2" -"@storybook/core-client@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/core-client/-/core-client-7.5.2.tgz#52f4b680273fdf1d3afe98a5adbbdee882ca7c44" - integrity sha512-mMDSBxc7esMCu0FOkama9XYHzIHYGhBj8roX+XaTaLDYXaw/UajcCuzcO7fFBHNn3Vdqh2ufIxlI7359v3IqPw== +"@storybook/core-client@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/core-client/-/core-client-7.6.4.tgz#d38ddb80bbc6119017a8ba15b88c030cf03d27e0" + integrity sha512-0msqdGd+VYD1dRgAJ2StTu4d543Wveb7LVVujX3PwD/QCxmCaVUHuAoZrekM/H7jZLw546ZIbLZo0xWrADAUMw== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/preview-api" "7.5.2" + "@storybook/client-logger" "7.6.4" + "@storybook/preview-api" "7.6.4" -"@storybook/core-common@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-7.5.2.tgz#7fef2bdb0c9d83ead2a9b5e1f479edb3106c6098" - integrity sha512-js7fIH4wHS08dBuIVsr3JnwMtKn5O1Izc/Zor4t6PntLWkGGX4X/GxbOkasGX5SkCT1qUtB9RpdPd1sUkLhIgw== +"@storybook/core-common@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/core-common/-/core-common-7.6.4.tgz#8ee282058ea4dd8fc0a053c30759f4bf65dab86b" + integrity sha512-qes4+mXqINu0kCgSMFjk++GZokmYjb71esId0zyJsk0pcIPkAiEjnhbSEQkMhbUfcvO1lztoaQTBW2P7Rd1tag== dependencies: - "@storybook/core-events" "7.5.2" - "@storybook/node-logger" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/core-events" "7.6.4" + "@storybook/node-logger" "7.6.4" + "@storybook/types" "7.6.4" "@types/find-cache-dir" "^3.2.1" "@types/node" "^18.0.0" "@types/node-fetch" "^2.6.4" @@ -3301,33 +3549,33 @@ resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.0.7.tgz#9acb6425d0a2a3d25becc21980c2c678c6c5548e" integrity sha512-XNsR2RgaL2vBwuqsu+KA1DzGmB1UFfrAhpxhmyWTKDCniwtTLlaXgfKbqwcrOrPu/o1YswgIup/9UHepRHaf4A== -"@storybook/core-events@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.5.2.tgz#e5185e39fdcb7ab93510f6174798d5f242e1041b" - integrity sha512-DV8bFEFVKDEvaH87KYPXDE0YEV+Y9yjFv2xxmC9pF8l+MWCtVW72RBLhB+gU5NM1bkHrRDNb0lOJfVGKlhxOog== +"@storybook/core-events@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-7.6.4.tgz#55405545dbc9ae5715654d2198ee1f1a3cc34ef7" + integrity sha512-i3xzcJ19ILSy4oJL5Dz9y0IlyApynn5RsGhAMIsW+mcfri+hGfeakq1stNCo0o7jW4Y3A7oluFTtIoK8DOxQdQ== dependencies: ts-dedent "^2.0.0" -"@storybook/core-server@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/core-server/-/core-server-7.5.2.tgz#c87e49f7109d82d389a927127ed673e3eaade4b2" - integrity sha512-4oXpy1L/NyHiz/OXNUFnSeMLA/+lTgQAlVx86pRbEBDj6snt1/NSx2+yZyFtZ/XTnJ22BPpM8IIrgm95ZlQKmA== +"@storybook/core-server@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/core-server/-/core-server-7.6.4.tgz#7732be1437af2affb3d7b0c5528446006a4c72a3" + integrity sha512-mXxZMpCwOhjEPPRjqrTHdiCpFdkc47f46vlgTj02SX+9xKHxslmZ2D3JG/8O4Ab9tG+bBl6lBm3RIrIzaiCu9Q== dependencies: "@aw-web-design/x-default-browser" "1.4.126" "@discoveryjs/json-ext" "^0.5.3" - "@storybook/builder-manager" "7.5.2" - "@storybook/channels" "7.5.2" - "@storybook/core-common" "7.5.2" - "@storybook/core-events" "7.5.2" - "@storybook/csf" "^0.1.0" - "@storybook/csf-tools" "7.5.2" + "@storybook/builder-manager" "7.6.4" + "@storybook/channels" "7.6.4" + "@storybook/core-common" "7.6.4" + "@storybook/core-events" "7.6.4" + "@storybook/csf" "^0.1.2" + "@storybook/csf-tools" "7.6.4" "@storybook/docs-mdx" "^0.1.0" "@storybook/global" "^5.0.0" - "@storybook/manager" "7.5.2" - "@storybook/node-logger" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/telemetry" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/manager" "7.6.4" + "@storybook/node-logger" "7.6.4" + "@storybook/preview-api" "7.6.4" + "@storybook/telemetry" "7.6.4" + "@storybook/types" "7.6.4" "@types/detect-port" "^1.3.0" "@types/node" "^18.0.0" "@types/pretty-hrtime" "^1.0.0" @@ -3355,25 +3603,25 @@ watchpack "^2.2.0" ws "^8.2.3" -"@storybook/csf-plugin@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-7.5.2.tgz#fe4b78d7e913e4666c924f98d48cb7e8f8d9030b" - integrity sha512-ndjn1ia2rQLO1r1z6mXv6nipLzJMwWJp31h16lQUXIBQEOiGKjGGvObiuKaad3nNHxWHpGra4zUg7R+54Yw0Hw== +"@storybook/csf-plugin@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/csf-plugin/-/csf-plugin-7.6.4.tgz#5d18cffc1c92dfd12d8571b2ba9d1456de58d8b2" + integrity sha512-7g9p8s2ITX+Z9iThK5CehPhJOcusVN7JcUEEW+gVF5PlYT+uk/x+66gmQno+scQuNkV9+8UJD6RLFjP+zg2uCA== dependencies: - "@storybook/csf-tools" "7.5.2" + "@storybook/csf-tools" "7.6.4" unplugin "^1.3.1" -"@storybook/csf-tools@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/csf-tools/-/csf-tools-7.5.2.tgz#204532b78740f5a3af399f304dbcb8b4ca856957" - integrity sha512-yXaEDREc2wvkjYkQqDMatJw23f0fEFhMIf/zBNF7YljeYw0j8jAg/7XI5WJJSN2KTxD/feD/yD+6eaLUXvrneQ== +"@storybook/csf-tools@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/csf-tools/-/csf-tools-7.6.4.tgz#4c1ef7a79ecd6f96d7fc1cb092cf2ed942cd65e2" + integrity sha512-6sLayuhgReIK3/QauNj5BW4o4ZfEMJmKf+EWANPEM/xEOXXqrog6Un8sjtBuJS9N1DwyhHY6xfkEiPAwdttwqw== dependencies: - "@babel/generator" "^7.22.9" - "@babel/parser" "^7.22.7" - "@babel/traverse" "^7.22.8" - "@babel/types" "^7.22.5" - "@storybook/csf" "^0.1.0" - "@storybook/types" "7.5.2" + "@babel/generator" "^7.23.0" + "@babel/parser" "^7.23.0" + "@babel/traverse" "^7.23.2" + "@babel/types" "^7.23.0" + "@storybook/csf" "^0.1.2" + "@storybook/types" "7.6.4" fs-extra "^11.1.0" recast "^0.23.1" ts-dedent "^2.0.0" @@ -3392,20 +3640,28 @@ dependencies: type-fest "^2.19.0" +"@storybook/csf@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@storybook/csf/-/csf-0.1.2.tgz#8e7452f0097507f5841b5ade3f5da1525bc9afb2" + integrity sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA== + dependencies: + type-fest "^2.19.0" + "@storybook/docs-mdx@^0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@storybook/docs-mdx/-/docs-mdx-0.1.0.tgz#33ba0e39d1461caf048b57db354b2cc410705316" integrity sha512-JDaBR9lwVY4eSH5W8EGHrhODjygPd6QImRbwjAuJNEnY0Vw4ie3bPkeGfnacB3OBW6u/agqPv2aRlR46JcAQLg== -"@storybook/docs-tools@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/docs-tools/-/docs-tools-7.5.2.tgz#ae59ac6b061c5471ed70f461f61d4d24c8fd8c51" - integrity sha512-mBiZFhzMA2ub7wX0ho3UqKqKXO+xUi/rqb4KV4PihLKlhThEdzKyYrIZO4W90NOmlp1yUJJcjG8D8SUPuHQoTw== +"@storybook/docs-tools@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/docs-tools/-/docs-tools-7.6.4.tgz#504b8654f348a109b69cc77cdab556f0bf9c2304" + integrity sha512-2eGam43aD7O3cocA72Z63kRi7t/ziMSpst0qB218QwBWAeZjT4EYDh8V6j/Xhv6zVQL3msW7AglrQP5kCKPvPA== dependencies: - "@storybook/core-common" "7.5.2" - "@storybook/preview-api" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/core-common" "7.6.4" + "@storybook/preview-api" "7.6.4" + "@storybook/types" "7.6.4" "@types/doctrine" "^0.0.3" + assert "^2.1.0" doctrine "^3.0.0" lodash "^4.17.21" @@ -3435,19 +3691,19 @@ telejson "^7.0.3" ts-dedent "^2.0.0" -"@storybook/manager-api@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-7.5.2.tgz#bb22c4d92fa8e31223a09e6ea089b03eda7db45e" - integrity sha512-WX8GjBkITRQzhQ08WEAVjdDW8QqqIQhWOpFzXUYCxCNzt1eSALI31QQ+M1/MYymw+TOkotC/SMcn/puIAm4rdA== +"@storybook/manager-api@7.6.4", "@storybook/manager-api@^7.0.0": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/manager-api/-/manager-api-7.6.4.tgz#edf5d553a78987ad8602700b7200391776010f48" + integrity sha512-RFb/iaBJfXygSgXkINPRq8dXu7AxBicTGX7MxqKXbz5FU7ANwV7abH6ONBYURkSDOH9//TQhRlVkF5u8zWg3bw== dependencies: - "@storybook/channels" "7.5.2" - "@storybook/client-logger" "7.5.2" - "@storybook/core-events" "7.5.2" - "@storybook/csf" "^0.1.0" + "@storybook/channels" "7.6.4" + "@storybook/client-logger" "7.6.4" + "@storybook/core-events" "7.6.4" + "@storybook/csf" "^0.1.2" "@storybook/global" "^5.0.0" - "@storybook/router" "7.5.2" - "@storybook/theming" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/router" "7.6.4" + "@storybook/theming" "7.6.4" + "@storybook/types" "7.6.4" dequal "^2.0.2" lodash "^4.17.21" memoizerific "^1.11.3" @@ -3456,25 +3712,25 @@ telejson "^7.2.0" ts-dedent "^2.0.0" -"@storybook/manager@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/manager/-/manager-7.5.2.tgz#9ca25f9e57058c55bd517c3e13770ad772d6fd8f" - integrity sha512-5l1z9SpCFQBcHjC5mbfWQ8mPTYFxD8GQ9mNZ6PPrj47yu9TyCRYSQj7A8ZXJiIY1ZEg4a2BCW7fPUYG+lX6Drw== +"@storybook/manager@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/manager/-/manager-7.6.4.tgz#11ea1ce8f37a069c96e594a716957f0d6c7690f3" + integrity sha512-Ug2ejfKgKre8h/RJbkumukwAA44TbvTPEjDcJmyFdAI+kHYhOYdKPEC2UNmVYz8/4HjwMTJQ3M7t/esK8HHY4A== "@storybook/mdx2-csf@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@storybook/mdx2-csf/-/mdx2-csf-1.0.0.tgz#ce4b2e44c9082bf382db835eef611b0097b7d771" integrity sha512-dBAnEL4HfxxJmv7LdEYUoZlQbWj9APZNIbOaq0tgF8XkxiIbzqvgB0jhL/9UOrysSDbQWBiCRTu2wOVxedGfmw== -"@storybook/node-logger@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-7.5.2.tgz#4ed36afac7b784eebaf11f4ebf657744b42a7458" - integrity sha512-VIBuwPJOylu8vJofk1VfmqxlhXgbBgV0pCTo/UzdQAbc3w5y+qNRemf8goWxYEY+L9p6oUXqm/i9+bNGyX7/Mw== +"@storybook/node-logger@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-7.6.4.tgz#e471ee117bbd329522113dd98e5a42e83e259f9c" + integrity sha512-GDkEnnDj4Op+PExs8ZY/P6ox3wg453CdEIaR8PR9TxF/H/T2fBL6puzma3hN2CMam6yzfAL8U+VeIIDLQ5BZdQ== -"@storybook/postinstall@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/postinstall/-/postinstall-7.5.2.tgz#0a4924f7b2919e698626c3dfa3ee6c8e948beb42" - integrity sha512-fKgyV1fAgckDoxQkUGJl5uzjzGC5esC/nITiCjccZFrqxt9mgmz4VAUkMeseD5tfWQ5oFA0Xdgtrrcl39+chnw== +"@storybook/postinstall@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/postinstall/-/postinstall-7.6.4.tgz#baefcec351ac79ee711ad27b65bf1ec28e545da6" + integrity sha512-7uoB82hSzlFSdDMS3hKQD+AaeSvPit/fAMvXCBxn0/D0UGJUZcq4M9JcKBwEHkZJcbuDROgOTJ6TUeXi/FWO0w== "@storybook/preview-api@7.0.7": version "7.0.7" @@ -3497,17 +3753,17 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/preview-api@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-7.5.2.tgz#72512c11369975904894c6f50036f10d3c329e59" - integrity sha512-rpmHR/09UBSnorDBTcE7JgHUQjZLO146NCI+vbI7Pqfb4QX/8lhwkFr4cuHRAR16mv6DAJbDVoPETO0Z/CH9aw== +"@storybook/preview-api@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/preview-api/-/preview-api-7.6.4.tgz#df103fbdfada5ceee540f6ea68001c0d2c718113" + integrity sha512-KhisNdQX5NdfAln+spLU4B82d804GJQp/CnI5M1mm/taTnjvMgs/wTH9AmR89OPoq+tFZVW0vhy2zgPS3ar71A== dependencies: - "@storybook/channels" "7.5.2" - "@storybook/client-logger" "7.5.2" - "@storybook/core-events" "7.5.2" - "@storybook/csf" "^0.1.0" + "@storybook/channels" "7.6.4" + "@storybook/client-logger" "7.6.4" + "@storybook/core-events" "7.6.4" + "@storybook/csf" "^0.1.2" "@storybook/global" "^5.0.0" - "@storybook/types" "7.5.2" + "@storybook/types" "7.6.4" "@types/qs" "^6.9.5" dequal "^2.0.2" lodash "^4.17.21" @@ -3517,41 +3773,41 @@ ts-dedent "^2.0.0" util-deprecate "^1.0.2" -"@storybook/preview@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/preview/-/preview-7.5.2.tgz#85c35c0931bb6f096f1fc6ed2e2b25eb55f8a0d0" - integrity sha512-dA5VpHp0D9nh9/wOzWP8At1wtz/SiaMBbwaiEOFTFUGcPerrkroEWadIlSSB7vgQJ9yWiD4l3KDaS8ANzHWtPQ== +"@storybook/preview@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/preview/-/preview-7.6.4.tgz#36cca1d10fd3729f1a68789d95bfc400e33aa616" + integrity sha512-p9xIvNkgXgTpSRphOMV9KpIiNdkymH61jBg3B0XyoF6IfM1S2/mQGvC89lCVz1dMGk2SrH4g87/WcOapkU5ArA== -"@storybook/react-dom-shim@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-7.5.2.tgz#0f937849d2e208d40e7086bd4e872670184f328d" - integrity sha512-x7h3TTLRLs8mrsCBKXbvjBRFms73XrNlm0Lo5Tu/Tf//+pwOFq+2sGBkqbRkYd54jNHhpqNF7+UUdzA93ESnbQ== +"@storybook/react-dom-shim@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/react-dom-shim/-/react-dom-shim-7.6.4.tgz#d1f5440c8f1ccd95abcc01117872ce46d0ab9dc3" + integrity sha512-wGJfomlDEBnowNmhmumWDu/AcUInxSoPqUUJPgk2f5oL0EW17fR9fDP/juG3XOEdieMDM0jDX48GML7lyvL2fg== -"@storybook/react-vite@^7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/react-vite/-/react-vite-7.5.2.tgz#b011e96bf2ebcb9ff252ff568330dbcac4ba7c1c" - integrity sha512-faYGER/qU/jeaMEf5kgx4dNeKno+HkCEviXo/bgRswRg7odW5XydlGGSATOYLYxLhWG6jztaYHYIaDk21KoOVA== +"@storybook/react-vite@^7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/react-vite/-/react-vite-7.6.4.tgz#a319711d32376909a0abaa44f41965e025e2f948" + integrity sha512-1NYzCJRO6k/ZyoMzpu1FQiaUaiLNjAvTAB1x3HE7oY/tEIT8kGpzXGYH++LJVWvyP/5dSWlUnRSy2rJvySraiw== dependencies: "@joshwooding/vite-plugin-react-docgen-typescript" "0.3.0" "@rollup/pluginutils" "^5.0.2" - "@storybook/builder-vite" "7.5.2" - "@storybook/react" "7.5.2" + "@storybook/builder-vite" "7.6.4" + "@storybook/react" "7.6.4" "@vitejs/plugin-react" "^3.0.1" magic-string "^0.30.0" - react-docgen "^6.0.2" + react-docgen "^7.0.0" -"@storybook/react@7.5.2", "@storybook/react@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-7.5.2.tgz#42afff95f8ff65d404282336a018c1fb59a5f2fa" - integrity sha512-7X8GtqvRjWmVS112ifChJMxfD15rMVg5m3t6apZqi0uui1S/DImAveHwz8M4FhsElW6MIHs5xK0uJhR9rVQgTA== +"@storybook/react@7.6.4", "@storybook/react@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/react/-/react-7.6.4.tgz#b17c451eb1240399d75c45ccb90a145ab1de44ac" + integrity sha512-XYRP+eylH3JqkCuziwtQGY5vOCeDreOibRYJmj5na6k4QbURjGVB44WCIW04gWVlmBXM9SqLAmserUi3HP890Q== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/core-client" "7.5.2" - "@storybook/docs-tools" "7.5.2" + "@storybook/client-logger" "7.6.4" + "@storybook/core-client" "7.6.4" + "@storybook/docs-tools" "7.6.4" "@storybook/global" "^5.0.0" - "@storybook/preview-api" "7.5.2" - "@storybook/react-dom-shim" "7.5.2" - "@storybook/types" "7.5.2" + "@storybook/preview-api" "7.6.4" + "@storybook/react-dom-shim" "7.6.4" + "@storybook/types" "7.6.4" "@types/escodegen" "^0.0.6" "@types/estree" "^0.0.51" "@types/node" "^18.0.0" @@ -3576,23 +3832,34 @@ memoizerific "^1.11.3" qs "^6.10.0" -"@storybook/router@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/router/-/router-7.5.2.tgz#d01d52f541b2fe817873660ba1e6cce5e4ab93f3" - integrity sha512-jlh48TVUlqvGkU8MnkVp9SrCHomWGtQGx1WMK94NMyOPVPTLWzM6LjIybgmHz0MTe4lpzmbiIOfSlU3pPX054w== +"@storybook/router@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/router/-/router-7.6.4.tgz#13112bd9d6709bebe4072d923e4921b660f8f00c" + integrity sha512-5MQ7Z4D7XNPN2yhFgjey7hXOYd6s8CggUqeAwhzGTex90SMCkKHSz1hfkcXn1ZqBPaall2b53uK553OvPLp9KQ== dependencies: - "@storybook/client-logger" "7.5.2" + "@storybook/client-logger" "7.6.4" memoizerific "^1.11.3" qs "^6.10.0" -"@storybook/telemetry@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/telemetry/-/telemetry-7.5.2.tgz#b64b833b161ef890d91222f332045119a10f21b3" - integrity sha512-tUgrcIx1vTMhTySp11JbBnWLsaMUNlil5yuOWEJy5i71E4Xy/2hYUtLfxzgXWd/0W7eTl4p2tjUk9uS8AP+S0Q== +"@storybook/source-loader@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/source-loader/-/source-loader-7.6.4.tgz#ef930e2dd947f45cbfaf845fa21035d82ac25c8d" + integrity sha512-1wb/3bVpJZ/3r3qUrLK8jb0kLuvwjNi5T1kci5huREdc1TrIxZXoPw9EiyjcMCZzCURkoj7euNLrLHGyzdBTLg== + dependencies: + "@storybook/csf" "^0.1.2" + "@storybook/types" "7.6.4" + estraverse "^5.2.0" + lodash "^4.17.21" + prettier "^2.8.0" + +"@storybook/telemetry@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/telemetry/-/telemetry-7.6.4.tgz#b28e8f7abf73b4900d83dfa68a988b6f3df9c24a" + integrity sha512-Q4QpvcgloHUEqC9PGo7tgqkUH91/PjX+74/0Hi9orLo8QmLMgdYS5fweFwgSKoTwDGNg2PaHp/jqvhhw7UmnJA== dependencies: - "@storybook/client-logger" "7.5.2" - "@storybook/core-common" "7.5.2" - "@storybook/csf-tools" "7.5.2" + "@storybook/client-logger" "7.6.4" + "@storybook/core-common" "7.6.4" + "@storybook/csf-tools" "7.6.4" chalk "^4.1.0" detect-package-manager "^2.0.1" fetch-retry "^5.0.2" @@ -3609,13 +3876,13 @@ "@storybook/global" "^5.0.0" memoizerific "^1.11.3" -"@storybook/theming@7.5.2", "@storybook/theming@~7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-7.5.2.tgz#0608912cf0b8817d9c53d7e3c378e6a99c147444" - integrity sha512-DZBTcYErSYvmTYsGz7lKtiIcBe8flBw5Ojp52r3O4GcRYG4AbuUwwVvehz+O1cWaS+UW3HavrcgapERH7ZHd1A== +"@storybook/theming@7.6.4", "@storybook/theming@~7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-7.6.4.tgz#cc81d0aee5fc80fe383cb6790e3a0e2ad80d2185" + integrity sha512-Z/dcC5EpkIXelYCkt9ojnX6D7qGOng8YHxV/OWlVE9TrEGYVGPOEfwQryR0RhmGpDha1TYESLYrsDb4A8nJ1EA== dependencies: "@emotion/use-insertion-effect-with-fallbacks" "^1.0.0" - "@storybook/client-logger" "7.5.2" + "@storybook/client-logger" "7.6.4" "@storybook/global" "^5.0.0" memoizerific "^1.11.3" @@ -3629,12 +3896,12 @@ "@types/express" "^4.7.0" file-system-cache "^2.0.0" -"@storybook/types@7.5.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.5.2.tgz#38f2e4a4cb0bb402b840d9e7f7762c0d113dc63b" - integrity sha512-RDKHo6WUES+4nt7uZMfankjxdpYX2EI2GpJ2n2RPcnhzmb/ub1huNTjbzDEYMqY24SppljZeIN57m3Ar6L6f9A== +"@storybook/types@7.6.4": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@storybook/types/-/types-7.6.4.tgz#3bb50b46286cc83484848c3c450c32cc2071eb21" + integrity sha512-qyiiXPCvol5uVgfubcIMzJBA0awAyFPU+TyUP1mkPYyiTHnsHYel/mKlSdPjc8a97N3SlJXHOCx41Hde4IyJgg== dependencies: - "@storybook/channels" "7.5.2" + "@storybook/channels" "7.6.4" "@types/babel__core" "^7.0.0" "@types/express" "^4.7.0" file-system-cache "2.3.0" @@ -3721,106 +3988,101 @@ "@svgr/hast-util-to-babel-ast" "^7.0.0" svg-parser "^2.0.4" +"@swc/core-darwin-arm64@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.100.tgz#f582c5bbc9c49506f728fc1d14dff33c2cc226d5" + integrity sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw== + "@swc/core-darwin-arm64@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.36.tgz#37f15d0edda0e78837bdab337d69777d2fecfa40" integrity sha512-lsP+C8p9cC/Vd9uAbtxpEnM8GoJI/MMnVuXak7OlxOtDH9/oTwmAcAQTfNGNaH19d2FAIRwf+5RbXCPnxa2Zjw== -"@swc/core-darwin-arm64@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.92.tgz#0498d3584cf877e39107c94705c38fa4a8c04789" - integrity sha512-v7PqZUBtIF6Q5Cp48gqUiG8zQQnEICpnfNdoiY3xjQAglCGIQCjJIDjreZBoeZQZspB27lQN4eZ43CX18+2SnA== +"@swc/core-darwin-x64@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.100.tgz#d84f5c0bb4603c252884d011a698ed7c634b1505" + integrity sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA== "@swc/core-darwin-x64@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.36.tgz#da6327511b62a78c2992749dd9ed813a9345608b" integrity sha512-jaLXsozWN5xachl9fPxDMi5nbWq1rRxPAt6ISeiYB6RJk0MQKH1634pOweBBem2pUDDzwDFXFw6f22LTm/cFvA== -"@swc/core-darwin-x64@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.92.tgz#1728e7ebbfe37b56c07d99e29dde78bfa90cf8d1" - integrity sha512-Q3XIgQfXyxxxms3bPN+xGgvwk0TtG9l89IomApu+yTKzaIIlf051mS+lGngjnh9L0aUiCp6ICyjDLtutWP54fw== - "@swc/core-linux-arm-gnueabihf@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.36.tgz#4272d94f376e5b90e6453d56f52f2618e2f7b825" integrity sha512-vcBdTHjoEpvJDbFlgto+S6VwAHzLA9GyCiuNcTU2v4KNQlFzhbO4A4PMfMCb/Z0RLJEr16tirfHdWIxjU3h8nw== -"@swc/core-linux-arm-gnueabihf@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.92.tgz#6f7c20833b739f8911c936c9783976ded2c449dc" - integrity sha512-tnOCoCpNVXC+0FCfG84PBZJyLlz0Vfj9MQhyhCvlJz9hQmvpf8nTdKH7RHrOn8VfxtUBLdVi80dXgIFgbvl7qA== +"@swc/core-linux-arm64-gnu@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.100.tgz#1ed4b92b373882d8f338c4e0a0aa64cdaa6106f1" + integrity sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw== "@swc/core-linux-arm64-gnu@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.36.tgz#d5c39fa52803ec0891c861588e5c4deb89652f63" integrity sha512-o7f5OsvwWppJo+qIZmrGO5+XC6DPt6noecSbRHjF6o1YAcR13ETPC14k1eC9H1YbQwpyCFNVAFXyNcUbCeQyrQ== -"@swc/core-linux-arm64-gnu@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.92.tgz#bb01dd9b922b0c076c38924013bd10036ce39c7c" - integrity sha512-lFfGhX32w8h1j74Iyz0Wv7JByXIwX11OE9UxG+oT7lG0RyXkF4zKyxP8EoxfLrDXse4Oop434p95e3UNC3IfCw== +"@swc/core-linux-arm64-musl@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.100.tgz#9db560f7459e42e65ec02670d6a8316e7c850cfc" + integrity sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA== "@swc/core-linux-arm64-musl@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.36.tgz#2a47ba9b438790f2e32584ca0698ef053cc3ddba" integrity sha512-FSHPngMi3c0fuGt9yY2Ubn5UcELi3EiPLJxBSC3X8TF9atI/WHZzK9PE9Gtn0C/LyRh4CoyOugDtSOPzGYmLQg== -"@swc/core-linux-arm64-musl@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.92.tgz#0070165eed2805475c98eb732bab8bdca955932e" - integrity sha512-rOZtRcLj57MSAbiecMsqjzBcZDuaCZ8F6l6JDwGkQ7u1NYR57cqF0QDyU7RKS1Jq27Z/Vg21z5cwqoH5fLN+Sg== +"@swc/core-linux-x64-gnu@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.100.tgz#228826ea48879bf1e73683fbef4373e3e762e424" + integrity sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA== "@swc/core-linux-x64-gnu@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.36.tgz#5e239123452231092eac7d6bd007949b5a7e38fb" integrity sha512-PHSsH2rek5pr3e0K09VgWAbrWK2vJhaI7MW9TPoTjyACYjcs3WwjcjQ30MghXUs2Dc/bXjWAOi9KFTjq/uCyFg== -"@swc/core-linux-x64-gnu@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.92.tgz#d9785f93b9121eeef0f54e8d845dd216698e0115" - integrity sha512-qptoMGnBL6v89x/Qpn+l1TH1Y0ed+v0qhNfAEVzZvCvzEMTFXphhlhYbDdpxbzRmCjH6GOGq7Y+xrWt9T1/ARg== +"@swc/core-linux-x64-musl@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.100.tgz#09a234dbbf625d071ecb663680e997a62d230d49" + integrity sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ== "@swc/core-linux-x64-musl@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.36.tgz#ed2a26e32d4d4e6f7cbf9f34d50cd38feb78d8dd" integrity sha512-4LfMYQHzozHCKkIcmQy83b+4SpI+mOp6sYNbXqSRz5dYvTVjegKZXe596P1U/87cK2cgR4uYvkgkgBXquaWvwQ== -"@swc/core-linux-x64-musl@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.92.tgz#8fe5cf244695bf4f0bc7dc7df450a9bd1bfccc2b" - integrity sha512-g2KrJ43bZkCZHH4zsIV5ErojuV1OIpUHaEyW1gf7JWKaFBpWYVyubzFPvPkjcxHGLbMsEzO7w/NVfxtGMlFH/Q== +"@swc/core-win32-arm64-msvc@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.100.tgz#add1c82884c10a9054ed6a48f884097aa85c6d2b" + integrity sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw== "@swc/core-win32-arm64-msvc@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.36.tgz#d8fbba50bfbf5e39aa4826c8c46978c4b1fdfbe7" integrity sha512-7y3dDcun79TAjCyk3Iv0eOMw1X/KNQbkVyKOGqnEgq9g22F8F1FoUGKHNTzUqVdzpHeJSsHgW5PlkEkl3c/d9w== -"@swc/core-win32-arm64-msvc@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.92.tgz#d6150785455c813a8e62f4e4b0a22773baf398eb" - integrity sha512-3MCRGPAYDoQ8Yyd3WsCMc8eFSyKXY5kQLyg/R5zEqA0uthomo0m0F5/fxAJMZGaSdYkU1DgF73ctOWOf+Z/EzQ== +"@swc/core-win32-ia32-msvc@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.100.tgz#e0b6c5ae7f3250adeeb88dae83558d3f45148c56" + integrity sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A== "@swc/core-win32-ia32-msvc@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.36.tgz#108830d0282a80d0f2d77bee7773d2985d389346" integrity sha512-zK0VR3B4LX5hzQ+7eD+K+FkxJlJg5Lo36BeahMzQ+/i0IURpnuyFlW88sdkFkMsc2swdU6bpvxLZeIRQ3W4OUg== -"@swc/core-win32-ia32-msvc@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.92.tgz#8142166bceafbaa209d440b36fdc8cd4b4f82768" - integrity sha512-zqTBKQhgfWm73SVGS8FKhFYDovyRl1f5dTX1IwSKynO0qHkRCqJwauFJv/yevkpJWsI2pFh03xsRs9HncTQKSA== +"@swc/core-win32-x64-msvc@1.3.100": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.100.tgz#34721dff151d7dcf165675f18aeed0a12264d88c" + integrity sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ== "@swc/core-win32-x64-msvc@1.3.36": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.36.tgz#96d9b1077a6877f6583f5d7405f8b9380b9364fc" integrity sha512-2bIjr9DhAckGiXZEvj6z2z7ECPcTimG+wD0VuQTvr+wkx46uAJKl5Kq+Zk+dd15ErL7JGUtCet1T7bf1k4FwvQ== -"@swc/core-win32-x64-msvc@1.3.92": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.92.tgz#4ba542875fc690b579232721ccec7873e139646a" - integrity sha512-41bE66ddr9o/Fi1FBh0sHdaKdENPTuDpv1IFHxSg0dJyM/jX8LbkjnpdInYXHBxhcLVAPraVRrNsC4SaoPw2Pg== - "@swc/core@^1.3.1": version "1.3.36" resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.36.tgz#c82fd4e7789082aeff47a622ef3701fffaf835e7" @@ -3837,24 +4099,23 @@ "@swc/core-win32-ia32-msvc" "1.3.36" "@swc/core-win32-x64-msvc" "1.3.36" -"@swc/core@^1.3.85": - version "1.3.92" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.92.tgz#f51808cdb6cbb90b0877b9a51806eea9a70eafca" - integrity sha512-vx0vUrf4YTEw59njOJ46Ha5i0cZTMYdRHQ7KXU29efN1MxcmJH2RajWLPlvQarOP1ab9iv9cApD7SMchDyx2vA== +"@swc/core@^1.3.96": + version "1.3.100" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.100.tgz#8fa36f26a35137620234b084224c9fa9b8a0fee2" + integrity sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw== dependencies: "@swc/counter" "^0.1.1" "@swc/types" "^0.1.5" optionalDependencies: - "@swc/core-darwin-arm64" "1.3.92" - "@swc/core-darwin-x64" "1.3.92" - "@swc/core-linux-arm-gnueabihf" "1.3.92" - "@swc/core-linux-arm64-gnu" "1.3.92" - "@swc/core-linux-arm64-musl" "1.3.92" - "@swc/core-linux-x64-gnu" "1.3.92" - "@swc/core-linux-x64-musl" "1.3.92" - "@swc/core-win32-arm64-msvc" "1.3.92" - "@swc/core-win32-ia32-msvc" "1.3.92" - "@swc/core-win32-x64-msvc" "1.3.92" + "@swc/core-darwin-arm64" "1.3.100" + "@swc/core-darwin-x64" "1.3.100" + "@swc/core-linux-arm64-gnu" "1.3.100" + "@swc/core-linux-arm64-musl" "1.3.100" + "@swc/core-linux-x64-gnu" "1.3.100" + "@swc/core-linux-x64-musl" "1.3.100" + "@swc/core-win32-arm64-msvc" "1.3.100" + "@swc/core-win32-ia32-msvc" "1.3.100" + "@swc/core-win32-x64-msvc" "1.3.100" "@swc/counter@^0.1.1": version "0.1.2" @@ -4021,18 +4282,6 @@ "@types/googlepay" "*" "@types/paypal-checkout-components" "*" -"@types/chai-subset@^1.3.3": - version "1.3.4" - resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.4.tgz#7938fa929dd12db451457e4d6faa27bcd599a729" - integrity sha512-CCWNXrJYSUIojZ1149ksLl3AN9cmZ5djf+yUoVVV+NuYrtydItQVlL2ZDqyC6M6O9LWRnVf8yYDxbXHO2TfQZg== - dependencies: - "@types/chai" "*" - -"@types/chai@*", "@types/chai@^4.3.5": - version "4.3.9" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.9.tgz#144d762491967db8c6dea38e03d2206c2623feec" - integrity sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg== - "@types/chart.js@^2.9.21": version "2.9.37" resolved "https://registry.yarnpkg.com/@types/chart.js/-/chart.js-2.9.37.tgz#8af70862b154fedf938b5b87debdb3a70f6e3208" @@ -4146,10 +4395,10 @@ resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.3.tgz#e892d293c92c9c1d3f9af72c15a554fbc7e0895a" integrity sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA== -"@types/doctrine@^0.0.6": - version "0.0.6" - resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.6.tgz#12ede1f7cd3797be5856277c85f031299ccd2641" - integrity sha512-KlEqPtaNBHBJ2/fVA4yLdD0Tc8zw34pKU4K5SHBIEwtLJ8xxumIC1xeG+4S+/9qhVj2MqC7O3Ld8WvDG4HqlgA== +"@types/doctrine@^0.0.9": + version "0.0.9" + resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.9.tgz#d86a5f452a15e3e3113b99e39616a9baa0f9863f" + integrity sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA== "@types/ejs@^3.1.1": version "3.1.2" @@ -4713,6 +4962,11 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.10.tgz#637d3c8431f112edf6728ac9bdfadfe029540f48" integrity sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A== +"@types/uuid@^9.0.1": + version "9.0.7" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.7.tgz#b14cebc75455eeeb160d5fe23c2fcc0c64f724d8" + integrity sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g== + "@types/warning@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" @@ -4909,12 +5163,12 @@ "@typescript-eslint/types" "5.60.1" eslint-visitor-keys "^3.3.0" -"@vitejs/plugin-react-swc@^3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.4.0.tgz#53ca6a07423abadec92f967e188d5ba49b350830" - integrity sha512-m7UaA4Uvz82N/0EOVpZL4XsFIakRqrFKeSNxa1FBLSXGvWrWRBwmZb4qxk+ZIVAZcW3c3dn5YosomDgx62XWcQ== +"@vitejs/plugin-react-swc@^3.5.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.5.0.tgz#1fadff5148003e8091168c431e44c850f9a39e74" + integrity sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig== dependencies: - "@swc/core" "^1.3.85" + "@swc/core" "^1.3.96" "@vitejs/plugin-react@^3.0.1": version "3.1.0" @@ -4927,78 +5181,123 @@ magic-string "^0.27.0" react-refresh "^0.14.0" -"@vitest/coverage-v8@^0.34.6": - version "0.34.6" - resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-0.34.6.tgz#931d9223fa738474e00c08f52b84e0f39cedb6d1" - integrity sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw== +"@vitest/coverage-v8@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.0.4.tgz#49193139399c37ddf16c23d96892ef32cd67a69a" + integrity sha512-xD6Yuql6RW0Ir/JJIs6rVrmnG2/KOWJF+IRX1oJQk5wGKGxbtdrYPbl+WTUn/4ICCQ2G20zbE1e8/nPNyAG5Vg== dependencies: "@ampproject/remapping" "^2.2.1" "@bcoe/v8-coverage" "^0.2.3" - istanbul-lib-coverage "^3.2.0" + debug "^4.3.4" + istanbul-lib-coverage "^3.2.2" istanbul-lib-report "^3.0.1" istanbul-lib-source-maps "^4.0.1" - istanbul-reports "^3.1.5" - magic-string "^0.30.1" + istanbul-reports "^3.1.6" + magic-string "^0.30.5" + magicast "^0.3.2" picocolors "^1.0.0" - std-env "^3.3.3" + std-env "^3.5.0" test-exclude "^6.0.0" - v8-to-istanbul "^9.1.0" + v8-to-istanbul "^9.2.0" + +"@vitest/expect@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.0.1.tgz#5e63902316a3c65948c6e36f284046962601fb88" + integrity sha512-3cdrb/eKD/0tygDX75YscuHEHMUJ70u3UoLSq2eqhWks57AyzvsDQbyn53IhZ0tBN7gA8Jj2VhXiOV2lef7thw== + dependencies: + "@vitest/spy" "1.0.1" + "@vitest/utils" "1.0.1" + chai "^4.3.10" -"@vitest/expect@0.34.6": - version "0.34.6" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.34.6.tgz#608a7b7a9aa3de0919db99b4cc087340a03ea77e" - integrity sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw== +"@vitest/expect@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.0.4.tgz#2751018b6e527841043e046ff424304453a0a024" + integrity sha512-/NRN9N88qjg3dkhmFcCBwhn/Ie4h064pY3iv7WLRsDJW7dXnEgeoa8W9zy7gIPluhz6CkgqiB3HmpIXgmEY5dQ== dependencies: - "@vitest/spy" "0.34.6" - "@vitest/utils" "0.34.6" + "@vitest/spy" "1.0.4" + "@vitest/utils" "1.0.4" chai "^4.3.10" -"@vitest/runner@0.34.6": - version "0.34.6" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-0.34.6.tgz#6f43ca241fc96b2edf230db58bcde5b974b8dcaf" - integrity sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ== +"@vitest/runner@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.0.1.tgz#d94cab9e3008dba52f89e811540184334766ab61" + integrity sha512-/+z0vhJ0MfRPT3AyTvAK6m57rzlew/ct8B2a4LMv7NhpPaiI2QLGyOBMB3lcioWdJHjRuLi9aYppfOv0B5aRQA== + dependencies: + "@vitest/utils" "1.0.1" + p-limit "^5.0.0" + pathe "^1.1.1" + +"@vitest/runner@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.0.4.tgz#c4dcb88c07f40b91293ff1331747ee58fad6d5e4" + integrity sha512-rhOQ9FZTEkV41JWXozFM8YgOqaG9zA7QXbhg5gy6mFOVqh4PcupirIJ+wN7QjeJt8S8nJRYuZH1OjJjsbxAXTQ== + dependencies: + "@vitest/utils" "1.0.4" + p-limit "^5.0.0" + pathe "^1.1.1" + +"@vitest/snapshot@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.0.1.tgz#9d2a01c64726afa62264175554690e5ce148d4a5" + integrity sha512-wIPtPDGSxEZ+DpNMc94AsybX6LV6uN6sosf5TojyP1m2QbKwiRuLV/5RSsjt1oWViHsTj8mlcwrQQ1zHGO0fMw== dependencies: - "@vitest/utils" "0.34.6" - p-limit "^4.0.0" + magic-string "^0.30.5" pathe "^1.1.1" + pretty-format "^29.7.0" -"@vitest/snapshot@0.34.6": - version "0.34.6" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-0.34.6.tgz#b4528cf683b60a3e8071cacbcb97d18b9d5e1d8b" - integrity sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w== +"@vitest/snapshot@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.0.4.tgz#7020983b3963b473237fea08d347ea83b266b9bb" + integrity sha512-vkfXUrNyNRA/Gzsp2lpyJxh94vU2OHT1amoD6WuvUAA12n32xeVZQ0KjjQIf8F6u7bcq2A2k969fMVxEsxeKYA== dependencies: - magic-string "^0.30.1" + magic-string "^0.30.5" pathe "^1.1.1" - pretty-format "^29.5.0" + pretty-format "^29.7.0" + +"@vitest/spy@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.0.1.tgz#d82af1c4d935e08443bf20432ba55afd001ac71f" + integrity sha512-yXwm1uKhBVr/5MhVeSmtNqK+0q2RXIchJt8kokEKdrWLtkPeDgdbZ6SjR1VQGZuNdWL6sSBnLayIyVvcS0qLfA== + dependencies: + tinyspy "^2.2.0" -"@vitest/spy@0.34.6": - version "0.34.6" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-0.34.6.tgz#b5e8642a84aad12896c915bce9b3cc8cdaf821df" - integrity sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ== +"@vitest/spy@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.0.4.tgz#e182c78fb9b1178ff789ad7eb4560ba6750e6e9b" + integrity sha512-9ojTFRL1AJVh0hvfzAQpm0QS6xIS+1HFIw94kl/1ucTfGCaj1LV/iuJU4Y6cdR03EzPDygxTHwE1JOm+5RCcvA== dependencies: - tinyspy "^2.1.1" + tinyspy "^2.2.0" -"@vitest/ui@^0.34.6": - version "0.34.6" - resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-0.34.6.tgz#86a9d58d1514aaea6a4b27ddd3c430646afca488" - integrity sha512-/fxnCwGC0Txmr3tF3BwAbo3v6U2SkBTGR9UB8zo0Ztlx0BTOXHucE0gDHY7SjwEktCOHatiGmli9kZD6gYSoWQ== +"@vitest/ui@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-1.0.4.tgz#810aa36bdd0d984483ae0c50d5163012d8191c7a" + integrity sha512-gd4p6e7pjukSe4joWS5wpnm/JcEfzCZUYkYWQOORqJK1mDJ0MOaXa/9BbPOEVO5TcvdnKvFJUdJpFHnqoyYwZA== dependencies: - "@vitest/utils" "0.34.6" - fast-glob "^3.3.0" - fflate "^0.8.0" - flatted "^3.2.7" + "@vitest/utils" "1.0.4" + fast-glob "^3.3.2" + fflate "^0.8.1" + flatted "^3.2.9" pathe "^1.1.1" picocolors "^1.0.0" sirv "^2.0.3" -"@vitest/utils@0.34.6": - version "0.34.6" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-0.34.6.tgz#38a0a7eedddb8e7291af09a2409cb8a189516968" - integrity sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A== +"@vitest/utils@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.0.1.tgz#ab2bf6de50845649b252a9d263765ab7f16bd6a2" + integrity sha512-MGPCHkzXbbAyscrhwGzh8uP1HPrTYLWaj1WTDtWSGrpe2yJWLRN9mF9ooKawr6NMOg9vTBtg2JqWLfuLC7Dknw== + dependencies: + diff-sequences "^29.6.3" + loupe "^2.3.7" + pretty-format "^29.7.0" + +"@vitest/utils@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.0.4.tgz#6e673eaf87a2ff28a12688d17bdbb62cc22bf773" + integrity sha512-gsswWDXxtt0QvtK/y/LWukN7sGMYmnCcv1qv05CsY6cU/Y1zpGX1QuvLs+GO1inczpE6Owixeel3ShkjhYtGfA== dependencies: - diff-sequences "^29.4.3" - loupe "^2.3.6" - pretty-format "^29.5.0" + diff-sequences "^29.6.3" + loupe "^2.3.7" + pretty-format "^29.7.0" "@xmldom/xmldom@^0.8.3": version "0.8.10" @@ -5066,10 +5365,10 @@ acorn-walk@^7.2.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== +acorn-walk@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f" + integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA== acorn@^7.1.1, acorn@^7.4.1: version "7.4.1" @@ -5086,11 +5385,6 @@ acorn@^8.8.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== -acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - address@^1.0.1: version "1.2.2" resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" @@ -5401,6 +5695,17 @@ assert@^2.0.0: object-is "^1.0.1" util "^0.12.0" +assert@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" + integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== + dependencies: + call-bind "^1.0.2" + is-nan "^1.3.2" + object-is "^1.1.5" + object.assign "^4.1.4" + util "^0.12.5" + assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -5411,13 +5716,6 @@ ast-types-flow@^0.0.7: resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== -ast-types@0.15.2: - version "0.15.2" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.15.2.tgz#39ae4809393c4b16df751ee563411423e85fb49d" - integrity sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg== - dependencies: - tslib "^2.0.1" - ast-types@^0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.16.1.tgz#7a9da1617c9081bc121faafe91711b4c8bb81da2" @@ -5800,6 +6098,16 @@ browserslist@^4.21.9, browserslist@^4.22.1: node-releases "^2.0.13" update-browserslist-db "^1.0.13" +browserslist@^4.22.2: + version "4.22.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" + integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== + dependencies: + caniuse-lite "^1.0.30001565" + electron-to-chromium "^1.4.601" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -5914,6 +6222,11 @@ caniuse-lite@^1.0.30001541: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001559.tgz#95a982440d3d314c471db68d02664fb7536c5a30" integrity sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA== +caniuse-lite@^1.0.30001565: + version "1.0.30001570" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz#b4e5c1fa786f733ab78fc70f592df6b3f23244ca" + integrity sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw== + canvg@^3.0.6: version "3.0.10" resolved "https://registry.yarnpkg.com/canvg/-/canvg-3.0.10.tgz#8e52a2d088b6ffa23ac78970b2a9eebfae0ef4b3" @@ -6549,14 +6862,6 @@ css-select@^5.1.0: domutils "^3.0.1" nth-check "^2.0.1" -css-vendor@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d" - integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ== - dependencies: - "@babel/runtime" "^7.8.3" - is-in-browser "^1.0.2" - css-what@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" @@ -6613,10 +6918,10 @@ cypress-real-events@^1.11.0: resolved "https://registry.yarnpkg.com/cypress-real-events/-/cypress-real-events-1.11.0.tgz#292fe5281c5b6e955524e766ab7fec46930c7763" integrity sha512-4LXVRsyq+xBh5TmlEyO1ojtBXtN7xw720Pwb9rEE9rkJuXmeH3VyoR1GGayMGr+Itqf11eEjfDewtDmcx6PWPQ== -cypress-vite@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/cypress-vite/-/cypress-vite-1.4.2.tgz#56a93d1d6329306e27ce2f2ba30787fde0e51d1c" - integrity sha512-uKsCo6KC1KJgubDCs7PqqI0AVXaYDPLocNvZplw2kJ2Z8M1793oCcr9D2/dKxYllRkhfFuYPPNjme/Kr2YWojQ== +cypress-vite@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/cypress-vite/-/cypress-vite-1.5.0.tgz#471ecc1175c7ab51b3b132c595dc3c7e222fe944" + integrity sha512-vvTMqJZgI3sN2ylQTi4OQh8LRRjSrfrIdkQD5fOj+EC/e9oHkxS96lif1SyDF1PwailG1tnpJE+VpN6+AwO/rg== dependencies: chokidar "^3.5.3" debug "^4.3.4" @@ -7113,6 +7418,11 @@ electron-to-chromium@^1.4.535: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.572.tgz#ed9876658998138fe9e3aa47ecfa0bf914192a86" integrity sha512-RlFobl4D3ieetbnR+2EpxdzFl9h0RAJkPK3pfiwMug2nhBin2ZCsGIAJWdpNniLz43sgXam/CgipOmvTA+rUiA== +electron-to-chromium@^1.4.601: + version "1.4.613" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.613.tgz#529e4fc65576ecfd055d7d4619fade4fac446af2" + integrity sha512-r4x5+FowKG6q+/Wj0W9nidx7QO31BJwmR2uEo+Qh3YLGQ8SbBAFuDFpTxzly/I2gsbrFwBuIjrMp423L3O5U3w== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -7339,7 +7649,7 @@ esbuild-register@^3.5.0: dependencies: debug "^4.3.4" -esbuild@^0.18.0, esbuild@^0.18.10, esbuild@^0.18.2: +esbuild@^0.18.0, esbuild@^0.18.2: version "0.18.20" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== @@ -7367,6 +7677,34 @@ esbuild@^0.18.0, esbuild@^0.18.10, esbuild@^0.18.2: "@esbuild/win32-ia32" "0.18.20" "@esbuild/win32-x64" "0.18.20" +esbuild@^0.19.3: + version "0.19.8" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.8.tgz#ad05b72281d84483fa6b5345bd246c27a207b8f1" + integrity sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w== + optionalDependencies: + "@esbuild/android-arm" "0.19.8" + "@esbuild/android-arm64" "0.19.8" + "@esbuild/android-x64" "0.19.8" + "@esbuild/darwin-arm64" "0.19.8" + "@esbuild/darwin-x64" "0.19.8" + "@esbuild/freebsd-arm64" "0.19.8" + "@esbuild/freebsd-x64" "0.19.8" + "@esbuild/linux-arm" "0.19.8" + "@esbuild/linux-arm64" "0.19.8" + "@esbuild/linux-ia32" "0.19.8" + "@esbuild/linux-loong64" "0.19.8" + "@esbuild/linux-mips64el" "0.19.8" + "@esbuild/linux-ppc64" "0.19.8" + "@esbuild/linux-riscv64" "0.19.8" + "@esbuild/linux-s390x" "0.19.8" + "@esbuild/linux-x64" "0.19.8" + "@esbuild/netbsd-x64" "0.19.8" + "@esbuild/openbsd-x64" "0.19.8" + "@esbuild/sunos-x64" "0.19.8" + "@esbuild/win32-arm64" "0.19.8" + "@esbuild/win32-ia32" "0.19.8" + "@esbuild/win32-x64" "0.19.8" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -7823,6 +8161,21 @@ execa@^7.0.0: signal-exit "^3.0.7" strip-final-newline "^3.0.0" +execa@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + executable@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" @@ -7962,10 +8315,10 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -8034,7 +8387,7 @@ fflate@^0.4.8: resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== -fflate@^0.8.0: +fflate@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.1.tgz#1ed92270674d2ad3c73f077cd0acf26486dae6c9" integrity sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ== @@ -8195,7 +8548,7 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -flatted@^3.2.7: +flatted@^3.2.9: version "3.2.9" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== @@ -8343,6 +8696,11 @@ fsevents@^2.3.2, fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -8446,6 +8804,11 @@ get-stream@^6.0.0, get-stream@^6.0.1: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -8892,6 +9255,11 @@ human-signals@^4.3.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.0.tgz#2095c3cd5afae40049403d4b811235b03879db50" integrity sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ== +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + husky@^3.0.1: version "3.1.0" resolved "https://registry.yarnpkg.com/husky/-/husky-3.1.0.tgz#5faad520ab860582ed94f0c1a77f0f04c90b57c0" @@ -8909,11 +9277,6 @@ husky@^3.0.1: run-node "^1.0.0" slash "^3.0.0" -hyphenate-style-name@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" - integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== - iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -9243,11 +9606,6 @@ is-gzip@^1.0.0: resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83" integrity sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ== -is-in-browser@^1.0.2, is-in-browser@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835" - integrity sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g== - is-installed-globally@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -9266,7 +9624,7 @@ is-map@^2.0.1, is-map@^2.0.2: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== -is-nan@^1.2.1: +is-nan@^1.2.1, is-nan@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== @@ -9468,7 +9826,7 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== -istanbul-lib-coverage@^3.0.0: +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== @@ -9507,7 +9865,7 @@ istanbul-lib-source-maps@^4.0.1: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.1.5: +istanbul-reports@^3.1.6: version "3.1.6" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== @@ -9709,20 +10067,21 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== -jscodeshift@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.14.0.tgz#7542e6715d6d2e8bde0b4e883f0ccea358b46881" - integrity sha512-7eCC1knD7bLUPuSCwXsMZUH51O8jIcoVyKtI6P0XM0IVzlGjckPy3FIwQlorzbN0Sg79oK+RlohN32Mqf/lrYA== - dependencies: - "@babel/core" "^7.13.16" - "@babel/parser" "^7.13.16" - "@babel/plugin-proposal-class-properties" "^7.13.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.13.8" - "@babel/plugin-proposal-optional-chaining" "^7.13.12" - "@babel/plugin-transform-modules-commonjs" "^7.13.8" - "@babel/preset-flow" "^7.13.13" - "@babel/preset-typescript" "^7.13.0" - "@babel/register" "^7.13.16" +jscodeshift@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.15.1.tgz#6c7a9572acdfa4f54098e958f71a05716a4e546b" + integrity sha512-hIJfxUy8Rt4HkJn/zZPU9ChKfKZM1342waJ1QC2e2YsPcWhM+3BJ4dcfQCzArTrk1jJeNLB341H+qOcEHRxJZg== + dependencies: + "@babel/core" "^7.23.0" + "@babel/parser" "^7.23.0" + "@babel/plugin-transform-class-properties" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.23.0" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.11" + "@babel/plugin-transform-optional-chaining" "^7.23.0" + "@babel/plugin-transform-private-methods" "^7.22.5" + "@babel/preset-flow" "^7.22.15" + "@babel/preset-typescript" "^7.23.0" + "@babel/register" "^7.22.15" babel-core "^7.0.0-bridge.0" chalk "^4.1.2" flow-parser "0.*" @@ -9730,7 +10089,7 @@ jscodeshift@^0.14.0: micromatch "^4.0.4" neo-async "^2.5.0" node-dir "^0.1.17" - recast "^0.21.0" + recast "^0.23.3" temp "^0.8.4" write-file-atomic "^2.3.0" @@ -9857,76 +10216,6 @@ jsprim@^2.0.2: json-schema "0.4.0" verror "1.10.0" -jss-plugin-camel-case@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz#27ea159bab67eb4837fa0260204eb7925d4daa1c" - integrity sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw== - dependencies: - "@babel/runtime" "^7.3.1" - hyphenate-style-name "^1.0.3" - jss "10.10.0" - -jss-plugin-default-unit@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz#db3925cf6a07f8e1dd459549d9c8aadff9804293" - integrity sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-global@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz#1c55d3c35821fab67a538a38918292fc9c567efd" - integrity sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-nested@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz#db872ed8925688806e77f1fc87f6e62264513219" - integrity sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - tiny-warning "^1.0.2" - -jss-plugin-props-sort@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz#67f4dd4c70830c126f4ec49b4b37ccddb680a5d7" - integrity sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - -jss-plugin-rule-value-function@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz#7d99e3229e78a3712f78ba50ab342e881d26a24b" - integrity sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g== - dependencies: - "@babel/runtime" "^7.3.1" - jss "10.10.0" - tiny-warning "^1.0.2" - -jss-plugin-vendor-prefixer@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz#c01428ef5a89f2b128ec0af87a314d0c767931c7" - integrity sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg== - dependencies: - "@babel/runtime" "^7.3.1" - css-vendor "^2.0.8" - jss "10.10.0" - -jss@10.10.0, jss@^10.10.0: - version "10.10.0" - resolved "https://registry.yarnpkg.com/jss/-/jss-10.10.0.tgz#a75cc85b0108c7ac8c7b7d296c520a3e4fbc6ccc" - integrity sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw== - dependencies: - "@babel/runtime" "^7.3.1" - csstype "^3.0.2" - is-in-browser "^1.1.3" - tiny-warning "^1.0.2" - "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea" @@ -10121,10 +10410,13 @@ load-tsconfig@^0.2.3: resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.3.tgz#08af3e7744943caab0c75f8af7f1703639c3ef1f" integrity sha512-iyT2MXws+dc2Wi6o3grCFtGXpeMvHmJqS27sMPGtV2eUu4PeFnG+33I8BlFK1t1NWMjOpcx9bridn5yxLDX2gQ== -local-pkg@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963" - integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g== +local-pkg@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.0.tgz#093d25a346bae59a99f80e75f6e9d36d7e8c925c" + integrity sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg== + dependencies: + mlly "^1.4.2" + pkg-types "^1.0.3" locate-path@^3.0.0: version "3.0.0" @@ -10238,7 +10530,7 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3 dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^2.3.6: +loupe@^2.3.6, loupe@^2.3.7: version "2.3.7" resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== @@ -10291,13 +10583,22 @@ magic-string@^0.27.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" -magic-string@^0.30.0, magic-string@^0.30.1: +magic-string@^0.30.0, magic-string@^0.30.5: version "0.30.5" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9" integrity sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA== dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" +magicast@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.2.tgz#42dcade5573ed8f10f5540f9d04964e21dba9130" + integrity sha512-Fjwkl6a0syt9TFN0JSYpOybxiMCkYNEeOTnOTNRbjphirLakznZXAqrXgj/7GG3D1dvETONNwrBfinvAbpunDg== + dependencies: + "@babel/parser" "^7.23.3" + "@babel/types" "^7.23.3" + source-map-js "^1.0.2" + make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -10583,7 +10884,7 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.2.0, mlly@^1.4.0: +mlly@^1.2.0, mlly@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.4.2.tgz#7cf406aa319ff6563d25da6b36610a93f2a8007e" integrity sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg== @@ -10684,6 +10985,11 @@ nanoid@^3.3.6: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -10748,6 +11054,11 @@ node-releases@^2.0.13: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + node-releases@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -11049,10 +11360,10 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-limit@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" - integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== +p-limit@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" + integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== dependencies: yocto-queue "^1.0.0" @@ -11380,7 +11691,7 @@ postcss-load-config@^4.0.1: lilconfig "^2.0.5" yaml "^2.1.1" -postcss@^8.3.11, postcss@^8.4.27: +postcss@^8.3.11: version "8.4.31" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== @@ -11389,6 +11700,15 @@ postcss@^8.3.11, postcss@^8.4.27: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^8.4.32: + version "8.4.32" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9" + integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.0.2" + postinstall@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/postinstall/-/postinstall-0.6.0.tgz#0b1b3b9bc2f4b2d492601cea77da06154f9aae17" @@ -11460,7 +11780,7 @@ pretty-format@^29.0.0, pretty-format@^29.4.3: ansi-styles "^5.0.0" react-is "^18.0.0" -pretty-format@^29.2.1, pretty-format@^29.5.0, pretty-format@^29.7.0: +pretty-format@^29.2.1, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== @@ -11746,17 +12066,17 @@ react-docgen-typescript@^2.2.2: resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c" integrity sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg== -react-docgen@^6.0.2: - version "6.0.4" - resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-6.0.4.tgz#85eeebac5fdeb781dbf610fdc429c20a4f06131c" - integrity sha512-gF+p+1ZwC2eO66bt763Tepmh5q9kDiFIrqW3YjUV/a+L96h0m5+/wSFQoOHL2cffyrPMZMxP03IgbggJ11QbOw== +react-docgen@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-7.0.1.tgz#b6528fe45385908645ffbee1ec0d65709e1e047c" + integrity sha512-rCz0HBIT0LWbIM+///LfRrJoTKftIzzwsYDf0ns5KwaEjejMHQRtphcns+IXFHDNY9pnz6G8l/JbbI6pD4EAIA== dependencies: "@babel/core" "^7.18.9" "@babel/traverse" "^7.18.9" "@babel/types" "^7.18.9" "@types/babel__core" "^7.18.0" "@types/babel__traverse" "^7.18.0" - "@types/doctrine" "^0.0.6" + "@types/doctrine" "^0.0.9" "@types/resolve" "^1.20.2" doctrine "^3.0.0" resolve "^1.22.1" @@ -11801,11 +12121,6 @@ react-input-autosize@^2.2.2: dependencies: prop-types "^15.5.8" -react-inspector@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-6.0.1.tgz#1a37f0165d9df81ee804d63259eaaeabe841287d" - integrity sha512-cxKSeFTf7jpSSVddm66sKdolG90qURAX3g1roTeaN6x0YEbtWc8JpmFN9+yIqLNH2uEkYerWLtJZIXRIFuBKrg== - react-is@18.1.0: version "18.1.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.1.0.tgz#61aaed3096d30eacf2a2127118b5b41387d32a67" @@ -12087,20 +12402,21 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -recast@^0.21.0: - version "0.21.5" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.21.5.tgz#e8cd22bb51bcd6130e54f87955d33a2b2e57b495" - integrity sha512-hjMmLaUXAm1hIuTqOdeYObMslq/q+Xff6QE3Y2P+uoHAg2nmVlLBps2hzh1UJDdMtDTMXOFewK6ky51JQIeECg== +recast@^0.23.1: + version "0.23.1" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.1.tgz#ee415a5561d2f99f02318ea8db81ad3a2267a6ff" + integrity sha512-RokaBcoxSjXUDzz1TXSZmZsSW6ZpLmlA3GGqJ8uuTrQ9hZhEz+4Tpsc+gRvYRJ2BU4H+ZyUlg91eSGDw7bwy7g== dependencies: - ast-types "0.15.2" + assert "^2.0.0" + ast-types "^0.16.1" esprima "~4.0.0" source-map "~0.6.1" tslib "^2.0.1" -recast@^0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.1.tgz#ee415a5561d2f99f02318ea8db81ad3a2267a6ff" - integrity sha512-RokaBcoxSjXUDzz1TXSZmZsSW6ZpLmlA3GGqJ8uuTrQ9hZhEz+4Tpsc+gRvYRJ2BU4H+ZyUlg91eSGDw7bwy7g== +recast@^0.23.3: + version "0.23.4" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.4.tgz#ca1bac7bfd3011ea5a28dfecb5df678559fb1ddf" + integrity sha512-qtEDqIZGVcSZCHniWwZWbRy79Dc6Wp3kT/UmDA2RJKBPg7+7k51aQBZirHmUGn5uvHf2rg8DkjizrN26k61ATw== dependencies: assert "^2.0.0" ast-types "^0.16.1" @@ -12456,11 +12772,23 @@ rimraf@^2.6.1, rimraf@^2.6.3: optionalDependencies: fsevents "~2.3.2" -rollup@^3.27.1: - version "3.29.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" - integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== +rollup@^4.2.0: + version "4.6.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.6.1.tgz#351501c86b5b4f976dde8c5837516452b59921f8" + integrity sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ== optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.6.1" + "@rollup/rollup-android-arm64" "4.6.1" + "@rollup/rollup-darwin-arm64" "4.6.1" + "@rollup/rollup-darwin-x64" "4.6.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.6.1" + "@rollup/rollup-linux-arm64-gnu" "4.6.1" + "@rollup/rollup-linux-arm64-musl" "4.6.1" + "@rollup/rollup-linux-x64-gnu" "4.6.1" + "@rollup/rollup-linux-x64-musl" "4.6.1" + "@rollup/rollup-win32-arm64-msvc" "4.6.1" + "@rollup/rollup-win32-ia32-msvc" "4.6.1" + "@rollup/rollup-win32-x64-msvc" "4.6.1" fsevents "~2.3.2" rrweb-cssom@^0.6.0: @@ -12745,6 +13073,11 @@ signal-exit@^4.0.1: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.0.2.tgz#ff55bb1d9ff2114c13b400688fa544ac63c36967" integrity sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-git@^3.19.0: version "3.19.0" resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.19.0.tgz#fe8d0cd86a0e68372b75c0c44a0cb887201c3f7d" @@ -12936,10 +13269,10 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -std-env@^3.3.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.4.3.tgz#326f11db518db751c83fd58574f449b7c3060910" - integrity sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q== +std-env@^3.5.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.6.0.tgz#94807562bddc68fa90f2e02c5fd5b6865bb4e98e" + integrity sha512-aFZ19IgVmhdB2uX599ve2kE6BIE3YMnQ6Gp6BURhW/oIzpXGKr878TQfAQZn1+i0Flcc/UKUy1gOlcfaUBCryg== stop-iteration-iterator@^1.0.0: version "1.0.0" @@ -12953,26 +13286,26 @@ store2@^2.14.2: resolved "https://registry.yarnpkg.com/store2/-/store2-2.14.2.tgz#56138d200f9fe5f582ad63bc2704dbc0e4a45068" integrity sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w== -storybook-dark-mode@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/storybook-dark-mode/-/storybook-dark-mode-3.0.1.tgz#b79e8809fc89da9c06edb5d2d20cba163c256adc" - integrity sha512-3V6XBhkUq63BF6KzyDBbfV5/8sYtF4UtVccH1tK+Lrd4p0tF8k7yHOvVDhFL9hexnKXcLEnbC+42YDTPvjpK+A== +storybook-dark-mode@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/storybook-dark-mode/-/storybook-dark-mode-3.0.3.tgz#7301c58646aae05f754de23046305aa5250546db" + integrity sha512-ZLBLVpkuKTdtUv3DTuOjeP/bE7DHhOxVpDROKc0NtEYq9JHLUu6z05LLZinE3v6QPXQZ9TMQPm3Xe/0BcLEZlw== dependencies: "@storybook/addons" "^7.0.0" - "@storybook/api" "^7.0.0" "@storybook/components" "^7.0.0" "@storybook/core-events" "^7.0.0" "@storybook/global" "^5.0.0" + "@storybook/manager-api" "^7.0.0" "@storybook/theming" "^7.0.0" fast-deep-equal "^3.1.3" memoizerific "^1.11.3" -storybook@~7.5.2: - version "7.5.2" - resolved "https://registry.yarnpkg.com/storybook/-/storybook-7.5.2.tgz#73cb6e4f607be09e5000a8d4c7d21d9ed42dcacb" - integrity sha512-wuB5VdmI6teU2z5iiBEZ2ziNeP6g6Da/dGM7+tWQVUl8bmfOmpEgzgEyS1/XqdOfm+HoZplspwM0XMHOLo/Now== +storybook@~7.6.4: + version "7.6.4" + resolved "https://registry.yarnpkg.com/storybook/-/storybook-7.6.4.tgz#4f89d25be3990f0e057020efb0dcb3429dfa179c" + integrity sha512-nQhs9XkrroxjqMoBnnToyc6M8ndbmpkOb1qmULO4chtfMy4k0p9Un3K4TJvDaP8c3wPUFGd4ZaJ1hZNVmIl56Q== dependencies: - "@storybook/cli" "7.5.2" + "@storybook/cli" "7.6.4" stream-shift@^1.0.0: version "1.0.1" @@ -13183,7 +13516,7 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -strip-literal@^1.0.1: +strip-literal@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-1.3.0.tgz#db3942c2ec1699e6836ad230090b84bb458e3a07" integrity sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg== @@ -13423,17 +13756,17 @@ tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tinybench@^2.5.0: +tinybench@^2.5.1: version "2.5.1" resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.5.1.tgz#3408f6552125e53a5a48adee31261686fd71587e" integrity sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg== -tinypool@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.7.0.tgz#88053cc99b4a594382af23190c609d93fddf8021" - integrity sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww== +tinypool@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.1.tgz#b6c4e4972ede3e3e5cda74a3da1679303d386b03" + integrity sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg== -tinyspy@^2.1.1: +tinyspy@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.0.tgz#9dc04b072746520b432f77ea2c2d17933de5d6ce" integrity sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg== @@ -13883,7 +14216,7 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.12.0, util@^0.12.3, util@^0.12.4: +util@^0.12.0, util@^0.12.3, util@^0.12.4, util@^0.12.5: version "0.12.5" resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== @@ -13921,7 +14254,7 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^9.1.0: +v8-to-istanbul@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== @@ -13977,17 +14310,27 @@ victory-vendor@^36.6.8: d3-time "^3.0.0" d3-timer "^3.0.1" -vite-node@0.34.6: - version "0.34.6" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.34.6.tgz#34d19795de1498562bf21541a58edcd106328a17" - integrity sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA== +vite-node@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.0.1.tgz#c16c9df9b5d47b74156a6501c9db5b380d992768" + integrity sha512-Y2Jnz4cr2azsOMMYuVPrQkp3KMnS/0WV8ezZjCy4hU7O5mUHCAVOnFmoEvs1nvix/4mYm74Len8bYRWZJMNP6g== + dependencies: + cac "^6.7.14" + debug "^4.3.4" + pathe "^1.1.1" + picocolors "^1.0.0" + vite "^5.0.0-beta.15 || ^5.0.0" + +vite-node@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.0.4.tgz#36d6c49e3b5015967d883845561ed67abe6553cc" + integrity sha512-9xQQtHdsz5Qn8hqbV7UKqkm8YkJhzT/zr41Dmt5N7AlD8hJXw/Z7y0QiD5I8lnTthV9Rvcvi0QW7PI0Fq83ZPg== dependencies: cac "^6.7.14" debug "^4.3.4" - mlly "^1.4.0" pathe "^1.1.1" picocolors "^1.0.0" - vite "^3.0.0 || ^4.0.0 || ^5.0.0-0" + vite "^5.0.0" vite-plugin-svgr@^3.2.0: version "3.2.0" @@ -13998,45 +14341,80 @@ vite-plugin-svgr@^3.2.0: "@svgr/core" "^7.0.0" "@svgr/plugin-jsx" "^7.0.0" -"vite@^3.0.0 || ^4.0.0 || ^5.0.0-0", "vite@^3.1.0 || ^4.0.0 || ^5.0.0-0", vite@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.0.tgz#ec406295b4167ac3bc23e26f9c8ff559287cff26" - integrity sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw== +vite@^5.0.0, vite@^5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.7.tgz#ad081d735f6769f76b556818500bdafb72c3fe93" + integrity sha512-B4T4rJCDPihrQo2B+h1MbeGL/k/GMAHzhQ8S0LjQ142s6/+l3hHTT095ORvsshj4QCkoWu3Xtmob5mazvakaOw== dependencies: - esbuild "^0.18.10" - postcss "^8.4.27" - rollup "^3.27.1" + esbuild "^0.19.3" + postcss "^8.4.32" + rollup "^4.2.0" optionalDependencies: - fsevents "~2.3.2" + fsevents "~2.3.3" -vitest@^0.34.6: - version "0.34.6" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-0.34.6.tgz#44880feeeef493c04b7f795ed268f24a543250d7" - integrity sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q== +"vite@^5.0.0-beta.15 || ^5.0.0", "vite@^5.0.0-beta.19 || ^5.0.0": + version "5.0.5" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.5.tgz#3eebe3698e3b32cea36350f58879258fec858a3c" + integrity sha512-OekeWqR9Ls56f3zd4CaxzbbS11gqYkEiBtnWFFgYR2WV8oPJRRKq0mpskYy/XaoCL3L7VINDhqqOMNDiYdGvGg== dependencies: - "@types/chai" "^4.3.5" - "@types/chai-subset" "^1.3.3" - "@types/node" "*" - "@vitest/expect" "0.34.6" - "@vitest/runner" "0.34.6" - "@vitest/snapshot" "0.34.6" - "@vitest/spy" "0.34.6" - "@vitest/utils" "0.34.6" - acorn "^8.9.0" - acorn-walk "^8.2.0" + esbuild "^0.19.3" + postcss "^8.4.32" + rollup "^4.2.0" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.0.1.tgz#3ba1307066842bc801084fa384ce0b23941b91f7" + integrity sha512-MHsOj079S28hDsvdDvyD1pRj4dcS51EC5Vbe0xvOYX+WryP8soiK2dm8oULi+oA/8Xa/h6GoJEMTmcmBy5YM+Q== + dependencies: + "@vitest/expect" "1.0.1" + "@vitest/runner" "1.0.1" + "@vitest/snapshot" "1.0.1" + "@vitest/spy" "1.0.1" + "@vitest/utils" "1.0.1" + acorn-walk "^8.3.0" + cac "^6.7.14" + chai "^4.3.10" + debug "^4.3.4" + execa "^8.0.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" + pathe "^1.1.1" + picocolors "^1.0.0" + std-env "^3.5.0" + strip-literal "^1.3.0" + tinybench "^2.5.1" + tinypool "^0.8.1" + vite "^5.0.0-beta.19 || ^5.0.0" + vite-node "1.0.1" + why-is-node-running "^2.2.2" + +vitest@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.0.4.tgz#c4b39ba4fcba674499c90e28f4d8dd16fa1d4eb3" + integrity sha512-s1GQHp/UOeWEo4+aXDOeFBJwFzL6mjycbQwwKWX2QcYfh/7tIerS59hWQ20mxzupTJluA2SdwiBuWwQHH67ckg== + dependencies: + "@vitest/expect" "1.0.4" + "@vitest/runner" "1.0.4" + "@vitest/snapshot" "1.0.4" + "@vitest/spy" "1.0.4" + "@vitest/utils" "1.0.4" + acorn-walk "^8.3.0" cac "^6.7.14" chai "^4.3.10" debug "^4.3.4" - local-pkg "^0.4.3" - magic-string "^0.30.1" + execa "^8.0.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" pathe "^1.1.1" picocolors "^1.0.0" - std-env "^3.3.3" - strip-literal "^1.0.1" - tinybench "^2.5.0" - tinypool "^0.7.0" - vite "^3.1.0 || ^4.0.0 || ^5.0.0-0" - vite-node "0.34.6" + std-env "^3.5.0" + strip-literal "^1.3.0" + tinybench "^2.5.1" + tinypool "^0.8.1" + vite "^5.0.0" + vite-node "1.0.4" why-is-node-running "^2.2.2" w3c-xmlserializer@^4.0.0: