forked from BLC/AyposWeb
environment variables fixed
This commit is contained in:
4
.env.example
Normal file
4
.env.example
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# API Configuration
|
||||||
|
VITE_API_URL=http://141.196.166.241:8003
|
||||||
|
|
||||||
|
# Add other environment variables as needed
|
||||||
18
README.md
18
README.md
@@ -69,3 +69,21 @@ No additional environment variables are required to run the application in devel
|
|||||||
## Browser Support
|
## Browser Support
|
||||||
|
|
||||||
The application is optimized for modern browsers that support ES6+ features.
|
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)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { Grid, Paper, Typography, Box, Divider } from '@mui/material';
|
import { Grid, Paper, Typography, Box, Divider } from '@mui/material';
|
||||||
import StorageIcon from '@mui/icons-material/Storage';
|
import StorageIcon from '@mui/icons-material/Storage';
|
||||||
import ComputerIcon from '@mui/icons-material/Computer';
|
import ComputerIcon from '@mui/icons-material/Computer';
|
||||||
|
import { config } from '../../config/env';
|
||||||
|
|
||||||
interface VM {
|
interface VM {
|
||||||
name: string;
|
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 REFRESH_INTERVAL = 30000; // 30 seconds
|
||||||
|
|
||||||
const SummaryStats: React.FC = () => {
|
const SummaryStats: React.FC = () => {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { VMDetails, GainBeforeData, MigrationAdviceData } from './types';
|
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
|
const REFRESH_INTERVAL = 30000; // 30 seconds
|
||||||
|
|
||||||
interface GainAfterData {
|
interface GainAfterData {
|
||||||
@@ -23,13 +24,20 @@ export const useMigrationData = () => {
|
|||||||
try {
|
try {
|
||||||
setIsLoadingGainData(true);
|
setIsLoadingGainData(true);
|
||||||
|
|
||||||
|
// Log the request start
|
||||||
|
console.log('Fetching migration data...');
|
||||||
|
|
||||||
const [gainResponse, migrationResponse] = await Promise.all([
|
const [gainResponse, migrationResponse] = await Promise.all([
|
||||||
fetch(`${API_BASE_URL}/prom/get_chart_data/gain_before`),
|
fetch(`${API_BASE_URL}/prom/get_chart_data/gain_before`),
|
||||||
fetch(`${API_BASE_URL}/prom/get_chart_data/migration`)
|
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) {
|
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([
|
const [gainData, migrationData] = await Promise.all([
|
||||||
@@ -37,10 +45,26 @@ export const useMigrationData = () => {
|
|||||||
migrationResponse.json()
|
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);
|
setGainBeforeData(gainData);
|
||||||
setMigrationAdviceData(migrationData);
|
setMigrationAdviceData(migrationData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching migration data:', error);
|
console.error('Error fetching migration data:', error);
|
||||||
|
// Clear the data on error to prevent showing stale data
|
||||||
|
setGainBeforeData(null);
|
||||||
|
setMigrationAdviceData(null);
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoadingGainData(false);
|
setIsLoadingGainData(false);
|
||||||
}
|
}
|
||||||
|
|||||||
9
src/config/env.ts
Normal file
9
src/config/env.ts
Normal 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
9
src/env.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_API_URL: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import { Box, Paper, Typography, Fade, useTheme, AppBar, Toolbar, Chip } from '@mui/material';
|
import { Box, Paper, Typography, Fade, useTheme, AppBar, Toolbar, Chip } from '@mui/material';
|
||||||
import Plot from 'react-plotly.js';
|
import Plot from 'react-plotly.js';
|
||||||
import { Layout, PlotData } from 'plotly.js';
|
import { Layout, PlotData } from 'plotly.js';
|
||||||
|
import { config } from '../config/env';
|
||||||
|
|
||||||
interface DataItem {
|
interface DataItem {
|
||||||
now_timestamp: string;
|
now_timestamp: string;
|
||||||
@@ -15,6 +16,8 @@ interface DataItem {
|
|||||||
flag: string;
|
flag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const API_BASE_URL = config.apiUrl;
|
||||||
|
|
||||||
const Maintenance = () => {
|
const Maintenance = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@@ -24,7 +27,7 @@ const Maintenance = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
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();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.data && result.data.length > 0) {
|
if (result.data && result.data.length > 0) {
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ import ResourceDistributionChart from '../components/Migration/ResourceDistribut
|
|||||||
import MigrationAdviceCard from '../components/Migration/MigrationAdviceCard';
|
import MigrationAdviceCard from '../components/Migration/MigrationAdviceCard';
|
||||||
import VerifiedMigration from '../components/Migration/VerifiedMigration';
|
import VerifiedMigration from '../components/Migration/VerifiedMigration';
|
||||||
import { useMigrationData, useGainAfterData } from '../components/Migration/hooks';
|
import { useMigrationData, useGainAfterData } from '../components/Migration/hooks';
|
||||||
|
import { config } from '../config/env';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const API_BASE_URL = 'http://141.196.166.241:8003';
|
const API_BASE_URL = config.apiUrl;
|
||||||
const REFRESH_INTERVAL = 30000; // 30 seconds
|
const REFRESH_INTERVAL = 30000; // 30 seconds
|
||||||
|
|
||||||
interface VMPlacementData {
|
interface VMPlacementData {
|
||||||
@@ -412,8 +413,7 @@ const Migration = () => {
|
|||||||
setMigrationProgress([]);
|
setMigrationProgress([]);
|
||||||
setHasProgress(true);
|
setHasProgress(true);
|
||||||
|
|
||||||
// First, send the POST request for migration approval
|
const approvalResponse = await fetch(`${API_BASE_URL}/prom/migration/decisions4?run_migration=true`, {
|
||||||
const approvalResponse = await fetch('http://141.196.166.241:8003/prom/migration/decisions4?run_migration=true', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'accept': 'application/json'
|
'accept': 'application/json'
|
||||||
@@ -455,7 +455,7 @@ const Migration = () => {
|
|||||||
try {
|
try {
|
||||||
setIsProcessing(true);
|
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',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'accept': 'application/json'
|
'accept': 'application/json'
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import ComputerIcon from '@mui/icons-material/Computer';
|
|||||||
import MemoryIcon from '@mui/icons-material/Memory';
|
import MemoryIcon from '@mui/icons-material/Memory';
|
||||||
import RefreshIcon from '@mui/icons-material/Refresh';
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
||||||
import SaveIcon from '@mui/icons-material/Save';
|
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
|
// Define the structure of our tree nodes
|
||||||
interface TreeNode {
|
interface TreeNode {
|
||||||
@@ -108,7 +111,7 @@ const MonitoringSystem: React.FC<MonitoringSystemProps> = ({
|
|||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
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();
|
const result: ApiResponse = await response.json();
|
||||||
|
|
||||||
// Create hierarchical structure
|
// Create hierarchical structure
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import Plot from 'react-plotly.js';
|
import Plot from 'react-plotly.js';
|
||||||
import { Layout, PlotData, Config } from 'plotly.js';
|
import { Layout, PlotData, Config } from 'plotly.js';
|
||||||
|
import { config } from '../config/env';
|
||||||
|
|
||||||
// Extend the Window interface to include Google Charts
|
// Extend the Window interface to include Google Charts
|
||||||
declare global {
|
declare global {
|
||||||
@@ -26,6 +27,8 @@ interface ChartData {
|
|||||||
power_future_min: string;
|
power_future_min: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const API_BASE_URL = config.apiUrl;
|
||||||
|
|
||||||
const Temperature = () => {
|
const Temperature = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [data, setData] = useState<ChartData[]>([]);
|
const [data, setData] = useState<ChartData[]>([]);
|
||||||
@@ -52,7 +55,7 @@ const Temperature = () => {
|
|||||||
setRefreshing(true);
|
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();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.data && result.data.length > 0) {
|
if (result.data && result.data.length > 0) {
|
||||||
@@ -337,7 +340,7 @@ const Temperature = () => {
|
|||||||
const handleTemperatureDecision = async (approval: boolean) => {
|
const handleTemperatureDecision = async (approval: boolean) => {
|
||||||
try {
|
try {
|
||||||
setDecisionLoading(true);
|
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',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'accept': 'application/json',
|
'accept': 'application/json',
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import ScienceIcon from '@mui/icons-material/Science';
|
|||||||
import SpeedIcon from '@mui/icons-material/Speed';
|
import SpeedIcon from '@mui/icons-material/Speed';
|
||||||
import ComputerIcon from '@mui/icons-material/Computer';
|
import ComputerIcon from '@mui/icons-material/Computer';
|
||||||
import { stressService } from '../services/stressService';
|
import { stressService } from '../services/stressService';
|
||||||
|
import { config } from '../config/env';
|
||||||
|
|
||||||
const PageTitle = styled(Typography)(({ theme }) => ({
|
const PageTitle = styled(Typography)(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -78,6 +79,8 @@ interface VM {
|
|||||||
ip: string;
|
ip: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const API_BASE_URL = config.apiUrl;
|
||||||
|
|
||||||
const Test = () => {
|
const Test = () => {
|
||||||
const [stressLevel, setStressLevel] = useState<'low' | 'medium' | 'high'>('low');
|
const [stressLevel, setStressLevel] = useState<'low' | 'medium' | 'high'>('low');
|
||||||
const [stressedVMs, setStressedVMs] = useState<string[]>([]);
|
const [stressedVMs, setStressedVMs] = useState<string[]>([]);
|
||||||
@@ -106,7 +109,7 @@ const Test = () => {
|
|||||||
const fetchVMs = async () => {
|
const fetchVMs = async () => {
|
||||||
setIsLoadingVMs(true);
|
setIsLoadingVMs(true);
|
||||||
try {
|
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();
|
const data: MonitoringResponse = await response.json();
|
||||||
|
|
||||||
// Extract VMs from the optimization space
|
// Extract VMs from the optimization space
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import axios from 'axios';
|
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 {
|
export interface MonitoringConfig {
|
||||||
migration: {
|
migration: {
|
||||||
@@ -71,11 +72,46 @@ class MonitoringService {
|
|||||||
throw new Error('Invalid configuration: Missing required sections');
|
throw new Error('Invalid configuration: Missing required sections');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure script_time_unit has valid values
|
// Validate migration configuration
|
||||||
if (!config.migration.script_time_unit ||
|
const { migration } = config;
|
||||||
!config.environmental.script_time_unit ||
|
if (!migration.script_time_unit ||
|
||||||
!config.preventive.script_time_unit) {
|
!migration.virtual_machine_estimation ||
|
||||||
throw new Error('Invalid configuration: Missing script_time_unit values');
|
!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
|
// Log the configuration being sent
|
||||||
@@ -103,7 +139,9 @@ class MonitoringService {
|
|||||||
throw new Error(`Failed to start monitoring: Status ${response.status}`);
|
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;
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (axios.isCancel(error)) {
|
if (axios.isCancel(error)) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import axios from 'axios';
|
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 {
|
export interface StressConfig {
|
||||||
vms: string[];
|
vms: string[];
|
||||||
|
|||||||
Reference in New Issue
Block a user