Compare commits

..

6 Commits

Author SHA1 Message Date
Girish Ramakrishnan 9522b8aa8d appstore: include provider as part of state
(cherry picked from commit 6533ba4581)
2026-01-29 14:39:30 +01:00
Girish Ramakrishnan fd881b4c61 9.0.18 changes 2026-01-29 14:30:24 +01:00
Girish Ramakrishnan 424ca715c9 ami: do not set domain provider by default
(cherry picked from commit b5f5b096d4)
2026-01-29 14:29:43 +01:00
Girish Ramakrishnan fe3c5f7a1b ami: add instanceId input box
(cherry picked from commit dce05140bf)
2026-01-29 14:29:36 +01:00
Girish Ramakrishnan e601fc93d6 setup: setupToken is not used anymore
(cherry picked from commit 2b80c6c1ad)
2026-01-29 14:29:30 +01:00
Girish Ramakrishnan 8f7076e4ef setup: set initial value for tls config
(cherry picked from commit 94a62b040b)
2026-01-29 14:29:01 +01:00
4 changed files with 38 additions and 47 deletions
+4
View File
@@ -3118,3 +3118,7 @@
* backup: add synology C2
* mail: update haraka to 3.1.2
* csp/robots: add common patterns
[9.0.18]
* ami & cloud images: fix setup
+13 -16
View File
@@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
const i18n = useI18n();
const t = i18n.t;
import { ref } from 'vue';
import { ref, watch } from 'vue';
import { TextInput, InputGroup, MaskedInput, Button, FormGroup, Checkbox, SingleSelect } from '@cloudron/pankow';
import { ENDPOINTS_OVH } from '../constants.js';
import DomainsModel from '../models/DomainsModel.js';
@@ -53,15 +53,6 @@ function needsPort80(dnsProvider, tlsProvider) {
(tlsProvider === 'letsencrypt-prod' || tlsProvider === 'letsencrypt-staging'));
}
function setDefaultTlsProvider(p) {
// wildcard LE won't work without automated DNS
if (p === 'manual' || p === 'noop' || p === 'wildcard') {
tlsProvider.value = 'letsencrypt-prod';
} else {
tlsProvider.value = 'letsencrypt-prod-wildcard';
}
}
function resetFields() {
dnsConfig.value.accessKeyId = '';
dnsConfig.value.accessKey = '';
@@ -86,10 +77,16 @@ function resetFields() {
dnsConfig.value.username = '';
}
function onProviderChange(p) {
setDefaultTlsProvider(p);
resetFields(p);
}
watch(provider, (p) => {
resetFields();
// wildcard LE won't work without automated DNS
if (p === 'manual' || p === 'noop' || p === 'wildcard') {
tlsProvider.value = 'letsencrypt-prod';
} else {
tlsProvider.value = 'letsencrypt-prod-wildcard';
}
}, { immediate: true });
const gcdnsFileParseError = ref('');
function onGcdnsFileInputChange(event) {
@@ -130,7 +127,7 @@ function onGcdnsFileInputChange(event) {
<div>
<FormGroup>
<label for="providerInput">{{ $t('domains.domainDialog.provider') }} <sup><a href="https://docs.cloudron.io/domains/#dns-providers" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<SingleSelect v-model="provider" @select="onProviderChange" :disabled="disabled" :options="DomainsModel.providers" option-key="value" option-label="name" required />
<SingleSelect v-model="provider" :disabled="disabled" :options="DomainsModel.providers" option-key="value" option-label="name" required />
</FormGroup>
<div class="warning-label" v-show="provider === 'wildcard'" v-html="$t('domains.domainDialog.wildcardInfo', { domain: domain })"></div>
@@ -323,7 +320,7 @@ function onGcdnsFileInputChange(event) {
<FormGroup v-if="showAdvanced">
<label>Certificate provider <sup><a href="https://docs.cloudron.io/certificates/#certificate-providers" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<SingleSelect v-model="tlsProvider" :options="tlsProviders" option-key="value" option-label="name"/>
<SingleSelect v-model="tlsProvider" :options="tlsProviders" option-key="value" option-label="name" required/>
</FormGroup>
</div>
+19 -31
View File
@@ -19,6 +19,7 @@ const ipProviders = [
{ name: 'Network Interface', value: 'network-interface' }
];
const serverProvider = ref('');
const formError = ref({});
const busy = ref(false);
const ready = ref(false);
@@ -27,11 +28,10 @@ const progressMessage = ref('');
const taskMinutesActive = ref(0);
const domain = ref('');
const instanceId = ref('');
const setupToken = ref('');
const zoneName = ref('');
const provider = ref('');
const dnsConfig = ref(DomainsModel.createEmptyConfig());
const tlsProvider = ref('letsenc-prod-wildcard');
const tlsProvider = ref('letsencrypt-prod-wildcard');
const showAdvanced = ref(false);
const customNameservers = ref(false);
const ipv4Provider = ref('generic');
@@ -59,7 +59,7 @@ async function waitForDnsSetup () {
if (!result.setup.active) {
if (!result.adminFqdn || result.setup.errorMessage) { // setup reset or errored. start over
formError.value.dnsWait = result.setup.errorMessage;
formError.value.generic = result.setup.errorMessage;
waitingForDnsSetup.value = false;
} else { // proceed to activation
window.location.href = 'https://' + result.adminFqdn + '/activation.html' + (window.location.search);
@@ -100,23 +100,13 @@ async function onSubmit() {
ip: ipv6Provider.value === 'fixed' ? ipv6Address.value : '',
ifname: ipv6Provider.value === 'network-interface' ? ipv6Interface.value : '',
},
providerToken: instanceId.value,
setupToken: setupToken.value,
providerToken: instanceId.value, // currently only for AMI
};
const [error] = await provisionModel.setup(data);
busy.value = false; // so we can come back to this view if dns setup errors later
if (error) {
if (error.status === 422) {
if (provider.value === 'ami') {
formError.value.ami = error.body.message;
} else {
formError.value.setup = error.body.message;
}
} else {
formError.value.generic = error.body ? error.body.message : 'Internal error';
}
formError.value.generic = error.body ? error.body.message : 'Internal error';
return;
}
@@ -133,26 +123,23 @@ watchEffect(() => {
});
onMounted(async () => {
const search = decodeURIComponent(window.location.search).slice(1).split('&').map(function (item) { return item.split('='); }).reduce(function (o, k) { o[k[0]] = k[1]; return o; }, {});
const [error, status] = await provisionModel.status();
if (error) return console.error(error);
if (redirectIfNeeded(status, 'setup')) return; // redirected to some other view...
if (status.provider === 'digitalocean' || status.provider === 'digitalocean-mp') {
serverProvider.value = status.provider;
if (serverProvider.value === 'digitalocean' || serverProvider.value === 'digitalocean-mp') {
provider.value = 'digitalocean';
} else if (status.provider === 'linode' || status.provider === 'linode-oneclick' || status.provider === 'linode-stackscript') {
} else if (serverProvider.value === 'linode' || serverProvider.value === 'linode-oneclick' || serverProvider.value === 'linode-stackscript') {
provider.value = 'linode';
} else if (status.provider === 'vultr' || status.provider === 'vultr-mp') {
} else if (serverProvider.value === 'vultr' || serverProvider.value === 'vultr-mp') {
provider.value = 'vultr';
} else if (status.provider === 'gce') {
} else if (serverProvider.value === 'gce') {
provider.value = 'gcdns';
} else if (status.provider === 'ami') {
// aws marketplace made a policy change that they one cannot provide route53 IAM credentials
provider.value = 'wildcard';
} else { // some default to make the form not feel "empty"
provider.value = 'digitalocean';
} else if (serverProvider.value === 'ami') {
// aws marketplace made a policy change that they one cannot provide route53 IAM credentials
// we used to have wildcard here but it shows some ugly warnings
}
const [error2, result] = await provisionModel.detectIp();
@@ -161,9 +148,6 @@ onMounted(async () => {
ipv4Provider.value = result.ipv4 ? 'generic' : 'noop';
ipv6Provider.value = result.ipv6 ? 'generic' : 'noop';
instanceId.value = search.instanceId;
setupToken.value = search.setupToken;
ready.value = true;
if (status.setup.active) return waitForDnsSetup();
@@ -189,14 +173,18 @@ onMounted(async () => {
<div class="view" v-else style="max-width: 500px">
<h1 style="text-align: center">Domain Setup</h1>
<div class="text-danger" v-if="formError.dnsWait">{{ formError.dnsWait }}</div>
<div class="text-danger" v-if="formError.setup">{{ formError.setup }}</div>
<div class="text-danger" v-if="formError.generic">{{ formError.generic }}</div>
<form ref="form" @submit.prevent="onSubmit()" @input="checkValidity()">
<fieldset :disabled="busy">
<input type="submit" style="display: none"/>
<FormGroup v-if="serverProvider === 'ami'">
<label for="amiInstanceIdInput">EC2 Instance ID</label>
<TextInput id="amiInstanceIdInput" v-model="instanceId" placeholder="i-0123456789abcdef0" required />
<small class="helper-text">Can be found in the AWS Console</small>
</FormGroup>
<FormGroup>
<label for="domainInput">Domain <sup><a href="https://docs.cloudron.io/installation/#domain-setup" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></label>
<TextInput id="domainInput" v-model="domain" placeholder="example.com" required />
+2
View File
@@ -48,6 +48,7 @@ const apps = require('./apps.js'),
semver = require('semver'),
settings = require('./settings.js'),
superagent = require('@cloudron/superagent'),
system = require('./system.js'),
users = require('./users.js'),
volumes = require('./volumes.js');
@@ -103,6 +104,7 @@ async function getState() {
const mailStats = await Promise.all(mailDomains.map(d => mail.getStats(d.domain)));
const state = {
provider: system.getProvider(),
userCount: (await users.list()).length,
groupCount: (await groups.list()).length,
domains: (await domains.list()).map(d => d.provider),