environment variables fixed

This commit is contained in:
2025-07-04 14:24:35 +03:00
parent 9f87ea5995
commit 4d7b5019d3
13 changed files with 136 additions and 20 deletions

4
.env.example Normal file
View File

@@ -0,0 +1,4 @@
# API Configuration
VITE_API_URL=http://141.196.166.241:8003
# Add other environment variables as needed

View File

@@ -69,3 +69,21 @@ No additional environment variables are required to run the application in devel
## Browser Support
The application is optimized for modern browsers that support ES6+ features.
## Environment Configuration
The application uses environment variables for configuration. To set up your environment:
1. Copy `.env.example` to `.env`:
```bash
cp .env.example .env
```
2. Edit `.env` and set your environment variables:
```env
VITE_API_URL=http://your-api-server:port
```
The following environment variables are available:
- `VITE_API_URL`: The URL of the API server (default: http://141.196.166.241:8003)

View File

@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { Grid, Paper, Typography, Box, Divider } from '@mui/material';
import StorageIcon from '@mui/icons-material/Storage';
import ComputerIcon from '@mui/icons-material/Computer';
import { config } from '../../config/env';
interface VM {
name: string;
@@ -21,7 +22,7 @@ interface VMPlacementData {
}>;
}
const ENDPOINT = 'http://141.196.166.241:8003/prom/get_chart_data/vm_placement';
const ENDPOINT = `${config.apiUrl}/prom/get_chart_data/vm_placement`;
const REFRESH_INTERVAL = 30000; // 30 seconds
const SummaryStats: React.FC = () => {

View File

@@ -1,7 +1,8 @@
import { useState, useEffect } from 'react';
import { VMDetails, GainBeforeData, MigrationAdviceData } from './types';
import { config } from '../../config/env';
const API_BASE_URL = 'http://141.196.166.241:8003';
const API_BASE_URL = config.apiUrl;
const REFRESH_INTERVAL = 30000; // 30 seconds
interface GainAfterData {
@@ -23,13 +24,20 @@ export const useMigrationData = () => {
try {
setIsLoadingGainData(true);
// Log the request start
console.log('Fetching migration data...');
const [gainResponse, migrationResponse] = await Promise.all([
fetch(`${API_BASE_URL}/prom/get_chart_data/gain_before`),
fetch(`${API_BASE_URL}/prom/get_chart_data/migration`)
]);
// Log the response status
console.log('Gain Response Status:', gainResponse.status);
console.log('Migration Response Status:', migrationResponse.status);
if (!gainResponse.ok || !migrationResponse.ok) {
throw new Error('Failed to fetch migration data');
throw new Error(`Failed to fetch migration data: Gain Status ${gainResponse.status}, Migration Status ${migrationResponse.status}`);
}
const [gainData, migrationData] = await Promise.all([
@@ -37,10 +45,26 @@ export const useMigrationData = () => {
migrationResponse.json()
]);
// Log the received data
console.log('Received Gain Data:', gainData);
console.log('Received Migration Data:', migrationData);
if (!gainData || typeof gainData.cur_power === 'undefined') {
console.error('Invalid gain data format:', gainData);
throw new Error('Invalid gain data format');
}
if (!migrationData || Object.keys(migrationData).length === 0) {
console.warn('No migration advice available:', migrationData);
}
setGainBeforeData(gainData);
setMigrationAdviceData(migrationData);
} catch (error) {
console.error('Error fetching migration data:', error);
// Clear the data on error to prevent showing stale data
setGainBeforeData(null);
setMigrationAdviceData(null);
} finally {
setIsLoadingGainData(false);
}

9
src/config/env.ts Normal file
View File

@@ -0,0 +1,9 @@
// Environment configuration
const getApiUrl = (): string => {
// Use environment variable if available, fallback to development URL
return import.meta.env.VITE_API_URL || 'http://141.196.166.241:8003';
};
export const config = {
apiUrl: getApiUrl(),
} as const;

9
src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}

View File

@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
import { Box, Paper, Typography, Fade, useTheme, AppBar, Toolbar, Chip } from '@mui/material';
import Plot from 'react-plotly.js';
import { Layout, PlotData } from 'plotly.js';
import { config } from '../config/env';
interface DataItem {
now_timestamp: string;
@@ -15,6 +16,8 @@ interface DataItem {
flag: string;
}
const API_BASE_URL = config.apiUrl;
const Maintenance = () => {
const theme = useTheme();
@@ -24,7 +27,7 @@ const Maintenance = () => {
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('http://141.196.166.241:8003/prom/get_chart_data/maintenance/20');
const response = await fetch(`${API_BASE_URL}/prom/get_chart_data/maintenance/20`);
const result = await response.json();
if (result.data && result.data.length > 0) {

View File

@@ -29,9 +29,10 @@ import ResourceDistributionChart from '../components/Migration/ResourceDistribut
import MigrationAdviceCard from '../components/Migration/MigrationAdviceCard';
import VerifiedMigration from '../components/Migration/VerifiedMigration';
import { useMigrationData, useGainAfterData } from '../components/Migration/hooks';
import { config } from '../config/env';
// Constants
const API_BASE_URL = 'http://141.196.166.241:8003';
const API_BASE_URL = config.apiUrl;
const REFRESH_INTERVAL = 30000; // 30 seconds
interface VMPlacementData {
@@ -412,8 +413,7 @@ const Migration = () => {
setMigrationProgress([]);
setHasProgress(true);
// First, send the POST request for migration approval
const approvalResponse = await fetch('http://141.196.166.241:8003/prom/migration/decisions4?run_migration=true', {
const approvalResponse = await fetch(`${API_BASE_URL}/prom/migration/decisions4?run_migration=true`, {
method: 'POST',
headers: {
'accept': 'application/json'
@@ -455,7 +455,7 @@ const Migration = () => {
try {
setIsProcessing(true);
const response = await fetch('http://141.196.166.241:8003/prom/migration/decisions4?run_migration=false', {
const response = await fetch(`${API_BASE_URL}/prom/migration/decisions4?run_migration=false`, {
method: 'POST',
headers: {
'accept': 'application/json'

View File

@@ -23,6 +23,9 @@ import ComputerIcon from '@mui/icons-material/Computer';
import MemoryIcon from '@mui/icons-material/Memory';
import RefreshIcon from '@mui/icons-material/Refresh';
import SaveIcon from '@mui/icons-material/Save';
import { config } from '../config/env';
const API_BASE_URL = config.apiUrl;
// Define the structure of our tree nodes
interface TreeNode {
@@ -108,7 +111,7 @@ const MonitoringSystem: React.FC<MonitoringSystemProps> = ({
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch('http://141.196.166.241:8003/prom/monitoring');
const response = await fetch(`${API_BASE_URL}/prom/monitoring`);
const result: ApiResponse = await response.json();
// Create hierarchical structure

View File

@@ -5,6 +5,7 @@ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import CancelIcon from '@mui/icons-material/Cancel';
import Plot from 'react-plotly.js';
import { Layout, PlotData, Config } from 'plotly.js';
import { config } from '../config/env';
// Extend the Window interface to include Google Charts
declare global {
@@ -26,6 +27,8 @@ interface ChartData {
power_future_min: string;
}
const API_BASE_URL = config.apiUrl;
const Temperature = () => {
const theme = useTheme();
const [data, setData] = useState<ChartData[]>([]);
@@ -52,7 +55,7 @@ const Temperature = () => {
setRefreshing(true);
}
const response = await fetch('http://141.196.166.241:8003/prom/get_chart_data/temperature/20');
const response = await fetch(`${API_BASE_URL}/prom/get_chart_data/temperature/20`);
const result = await response.json();
if (result.data && result.data.length > 0) {
@@ -337,7 +340,7 @@ const Temperature = () => {
const handleTemperatureDecision = async (approval: boolean) => {
try {
setDecisionLoading(true);
const response = await fetch('http://141.196.166.241:8003/prom/temperature/decisions?approval=' + approval, {
const response = await fetch(`${API_BASE_URL}/prom/temperature/decisions?approval=${approval}`, {
method: 'POST',
headers: {
'accept': 'application/json',

View File

@@ -25,6 +25,7 @@ import ScienceIcon from '@mui/icons-material/Science';
import SpeedIcon from '@mui/icons-material/Speed';
import ComputerIcon from '@mui/icons-material/Computer';
import { stressService } from '../services/stressService';
import { config } from '../config/env';
const PageTitle = styled(Typography)(({ theme }) => ({
display: 'flex',
@@ -78,6 +79,8 @@ interface VM {
ip: string;
}
const API_BASE_URL = config.apiUrl;
const Test = () => {
const [stressLevel, setStressLevel] = useState<'low' | 'medium' | 'high'>('low');
const [stressedVMs, setStressedVMs] = useState<string[]>([]);
@@ -106,7 +109,7 @@ const Test = () => {
const fetchVMs = async () => {
setIsLoadingVMs(true);
try {
const response = await fetch('http://141.196.166.241:8003/prom/monitoring');
const response = await fetch(`${API_BASE_URL}/prom/monitoring`);
const data: MonitoringResponse = await response.json();
// Extract VMs from the optimization space

View File

@@ -1,6 +1,7 @@
import axios from 'axios';
import { config } from '../config/env';
const BASE_URL = 'http://141.196.166.241:8003';
const BASE_URL = config.apiUrl;
export interface MonitoringConfig {
migration: {
@@ -71,11 +72,46 @@ class MonitoringService {
throw new Error('Invalid configuration: Missing required sections');
}
// Ensure script_time_unit has valid values
if (!config.migration.script_time_unit ||
!config.environmental.script_time_unit ||
!config.preventive.script_time_unit) {
throw new Error('Invalid configuration: Missing script_time_unit values');
// Validate migration configuration
const { migration } = config;
if (!migration.script_time_unit ||
!migration.virtual_machine_estimation ||
!migration.migration_advices ||
!migration.block_list) {
throw new Error('Invalid migration configuration: Missing required fields');
}
// Validate estimation configuration
const { virtual_machine_estimation } = migration;
if (!virtual_machine_estimation.estimation_method || !virtual_machine_estimation.model_type) {
throw new Error('Invalid estimation configuration: Missing required fields');
}
// Validate migration advice configuration
const { migration_advices } = migration;
if (!migration_advices.migration_method || !migration_advices.migration_weights) {
throw new Error('Invalid migration advice configuration: Missing required fields');
}
// Validate weights
const { migration_weights } = migration_advices;
if (!migration_weights.power || !migration_weights.balance ||
!migration_weights.overload || !migration_weights.allocation) {
throw new Error('Invalid weights configuration: Missing required fields');
}
// Validate environmental configuration
if (!config.environmental.script_time_unit ||
!config.environmental.number_of_steps ||
!config.environmental.model_type) {
throw new Error('Invalid environmental configuration: Missing required fields');
}
// Validate preventive configuration
if (!config.preventive.script_time_unit ||
!config.preventive.number_of_steps ||
!config.preventive.model_type) {
throw new Error('Invalid preventive configuration: Missing required fields');
}
// Log the configuration being sent
@@ -103,7 +139,9 @@ class MonitoringService {
throw new Error(`Failed to start monitoring: Status ${response.status}`);
}
console.log('Monitoring started successfully:', response.data);
// Log the response data
console.log('Monitoring started successfully. Response:', response.data);
return;
} catch (error) {
if (axios.isCancel(error)) {

View File

@@ -1,6 +1,7 @@
import axios from 'axios';
import { config } from '../config/env';
const BASE_URL = 'http://141.196.166.241:8003';
const BASE_URL = config.apiUrl;
export interface StressConfig {
vms: string[];