fix launch issue
This commit is contained in:
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 13:00:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -17,6 +18,12 @@ depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# Get the inspector
|
||||
inspector = inspect(op.get_bind())
|
||||
|
||||
# Check if the column exists
|
||||
columns = [col['name'] for col in inspector.get_columns('instances')]
|
||||
if 'connection_token' not in columns:
|
||||
op.add_column('instances', sa.Column('connection_token', sa.String(64), nullable=True, unique=True))
|
||||
|
||||
|
||||
|
||||
@@ -842,3 +842,42 @@ def deploy_stack():
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Error deploying stack: {str(e)}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@launch_api.route('/save-instance', methods=['POST'])
|
||||
@csrf.exempt
|
||||
def save_instance():
|
||||
try:
|
||||
if not request.is_json:
|
||||
return jsonify({'error': 'Request must be JSON'}), 400
|
||||
|
||||
data = request.get_json()
|
||||
required_fields = ['name', 'port', 'domains', 'stack_id', 'stack_name', 'status', 'repository', 'branch']
|
||||
|
||||
if not all(field in data for field in required_fields):
|
||||
missing_fields = [field for field in required_fields if field not in data]
|
||||
return jsonify({'error': f'Missing required fields: {", ".join(missing_fields)}'}), 400
|
||||
|
||||
# Save instance data
|
||||
instance_data = {
|
||||
'name': data['name'],
|
||||
'port': data['port'],
|
||||
'domains': data['domains'],
|
||||
'stack_id': data['stack_id'],
|
||||
'stack_name': data['stack_name'],
|
||||
'status': data['status'],
|
||||
'repository': data['repository'],
|
||||
'branch': data['branch'],
|
||||
'created_at': datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
# Save to database using KeyValueSettings
|
||||
KeyValueSettings.set_value(f'instance_{data["name"]}', instance_data)
|
||||
|
||||
return jsonify({
|
||||
'message': 'Instance data saved successfully',
|
||||
'data': instance_data
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Error saving instance data: {str(e)}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
@@ -99,6 +99,18 @@ function initializeSteps() {
|
||||
</div>
|
||||
`;
|
||||
stepsContainer.appendChild(stackDeployStep);
|
||||
|
||||
// Add Save Instance Data step
|
||||
const saveDataStep = document.createElement('div');
|
||||
saveDataStep.className = 'step-item';
|
||||
saveDataStep.innerHTML = `
|
||||
<div class="step-icon"><i class="fas fa-save"></i></div>
|
||||
<div class="step-content">
|
||||
<h5>Saving Instance Data</h5>
|
||||
<p class="step-status">Storing instance information...</p>
|
||||
</div>
|
||||
`;
|
||||
stepsContainer.appendChild(saveDataStep);
|
||||
}
|
||||
|
||||
async function startLaunch(data) {
|
||||
@@ -250,7 +262,10 @@ async function startLaunch(data) {
|
||||
const stackDeployStep = document.querySelectorAll('.step-item')[6];
|
||||
stackDeployStep.classList.remove('active');
|
||||
stackDeployStep.classList.add('completed');
|
||||
stackDeployStep.querySelector('.step-status').textContent = 'Successfully deployed stack';
|
||||
stackDeployStep.querySelector('.step-status').textContent =
|
||||
stackResult.data.status === 'existing' ?
|
||||
'Using existing stack' :
|
||||
'Successfully deployed stack';
|
||||
|
||||
// Add stack details
|
||||
const stackDetails = document.createElement('div');
|
||||
@@ -279,7 +294,9 @@ async function startLaunch(data) {
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<span class="badge bg-success">Deployed</span>
|
||||
<span class="badge bg-${stackResult.data.status === 'existing' ? 'info' : 'success'}">
|
||||
${stackResult.data.status === 'existing' ? 'Existing' : 'Deployed'}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -290,7 +307,70 @@ async function startLaunch(data) {
|
||||
`;
|
||||
stackDeployStep.querySelector('.step-content').appendChild(stackDetails);
|
||||
|
||||
// Save instance data
|
||||
await updateStep(8, 'Saving Instance Data', 'Storing instance information...');
|
||||
try {
|
||||
const instanceData = {
|
||||
name: data.instanceName,
|
||||
port: data.port,
|
||||
domains: data.webAddresses,
|
||||
stack_id: stackResult.data.id,
|
||||
stack_name: stackResult.data.name,
|
||||
status: stackResult.data.status,
|
||||
repository: data.repository,
|
||||
branch: data.branch
|
||||
};
|
||||
console.log('Saving instance data:', instanceData);
|
||||
const saveResult = await saveInstanceData(instanceData);
|
||||
console.log('Save result:', saveResult);
|
||||
await updateStep(8, 'Saving Instance Data', 'Instance data saved successfully');
|
||||
} catch (error) {
|
||||
console.error('Error saving instance data:', error);
|
||||
await updateStep(8, 'Saving Instance Data', `Error: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Update the step to show success
|
||||
const saveDataStep = document.querySelectorAll('.step-item')[7];
|
||||
saveDataStep.classList.remove('active');
|
||||
saveDataStep.classList.add('completed');
|
||||
saveDataStep.querySelector('.step-status').textContent = 'Successfully saved instance data';
|
||||
|
||||
// Add instance details
|
||||
const instanceDetails = document.createElement('div');
|
||||
instanceDetails.className = 'mt-3';
|
||||
instanceDetails.innerHTML = `
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title mb-3">Instance Information</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Property</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Internal Port</td>
|
||||
<td>${data.port}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Domains</td>
|
||||
<td><a href="https://${data.webAddresses.join(', ')}" target="_blank">${data.webAddresses.join(', ')}</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
saveDataStep.querySelector('.step-content').appendChild(instanceDetails);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Launch failed:', error);
|
||||
await updateStep(8, 'Saving Instance Data', `Error: ${error.message}`);
|
||||
showError(error.message);
|
||||
}
|
||||
}
|
||||
@@ -1021,3 +1101,81 @@ async function deployStack(dockerComposeContent, stackName, port) {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Add new function to save instance data
|
||||
async function saveInstanceData(instanceData) {
|
||||
try {
|
||||
console.log('Saving instance data:', instanceData);
|
||||
|
||||
// First check if instance already exists
|
||||
const checkResponse = await fetch('/instances');
|
||||
const text = await checkResponse.text();
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(text, 'text/html');
|
||||
|
||||
// Look for an existing instance with the same name
|
||||
const existingInstance = Array.from(doc.querySelectorAll('table tbody tr')).find(row => {
|
||||
const nameCell = row.querySelector('td:first-child');
|
||||
return nameCell && nameCell.textContent.trim() === instanceData.port;
|
||||
});
|
||||
|
||||
if (existingInstance) {
|
||||
console.log('Instance already exists:', instanceData.port);
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
name: instanceData.port,
|
||||
company: 'loading...',
|
||||
rooms_count: 0,
|
||||
conversations_count: 0,
|
||||
data_size: 0.0,
|
||||
payment_plan: 'Basic',
|
||||
main_url: `https://${instanceData.domains[0]}`,
|
||||
status: 'inactive',
|
||||
port: instanceData.port,
|
||||
stack_id: instanceData.stack_id,
|
||||
stack_name: instanceData.stack_name,
|
||||
repository: instanceData.repository,
|
||||
branch: instanceData.branch
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// If instance doesn't exist, create it
|
||||
const response = await fetch('/instances/add', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: instanceData.port,
|
||||
company: 'loading...',
|
||||
rooms_count: 0,
|
||||
conversations_count: 0,
|
||||
data_size: 0.0,
|
||||
payment_plan: 'Basic',
|
||||
main_url: `https://${instanceData.domains[0]}`,
|
||||
status: 'inactive',
|
||||
port: instanceData.port,
|
||||
stack_id: instanceData.stack_id,
|
||||
stack_name: instanceData.stack_name,
|
||||
repository: instanceData.repository,
|
||||
branch: instanceData.branch
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error('Error response:', errorText);
|
||||
throw new Error(`Failed to save instance data: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
console.log('Instance data saved:', result);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Error saving instance data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@
|
||||
</div>
|
||||
|
||||
<div id="stepsContainer" class="launch-steps-container">
|
||||
<!-- Your custom steps will be added here -->
|
||||
<!-- Steps will be added here by JavaScript -->
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-4">
|
||||
@@ -68,6 +68,9 @@
|
||||
url: '{{ portainer_settings.url if portainer_settings else "" }}',
|
||||
api_key: '{{ portainer_settings.api_key if portainer_settings else "" }}'
|
||||
};
|
||||
|
||||
// Pass CSRF token to JavaScript
|
||||
window.csrfToken = '{{ csrf_token }}';
|
||||
</script>
|
||||
<script src="{{ url_for('static', filename='js/launch_progress.js') }}"></script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user