Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add Read System #70

Merged
merged 2 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ ARG GID=0
ARG USER=root
ARG GROUP=root
#-------------------------------------------------------------
RUN apt-get update
RUN apt-get install ca-certificates -y
RUN apt-get update && apt-get install -y ca-certificates curl && rm -rf /var/lib/apt/lists/*
#-------------------------------------------------------------
# User Set
RUN if [ "${USER}" != "root" ]; then \
Expand Down
85 changes: 85 additions & 0 deletions config/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path/filepath"
Expand Down Expand Up @@ -180,3 +181,87 @@ func (fpm *FileProfileManager) LoadCredentialsByProfile(profileName string, prov
return nil, errors.New("unsupported provider")
}
}

// ValidateProfiles checks that at least one profile exists, each profile has at least one credential,
// and that all provided credentials have non-empty required fields.
func (fpm *FileProfileManager) ValidateProfiles() error {
fpm.mu.Lock()
defer fpm.mu.Unlock()

// Open the profile file
file, err := os.Open(fpm.profileFilePath)
if err != nil {
return fmt.Errorf("unable to open profile file: %v", err)
}
defer file.Close()

// Read the file content
data, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("unable to read profile file: %v", err)
}

// Unmarshal JSON data into profiles
var profiles []struct {
ProfileName string `json:"profileName"`
Credentials models.ProfileCredentials `json:"credentials"`
}

if err := json.Unmarshal(data, &profiles); err != nil {
return fmt.Errorf("unable to parse profile JSON: %v", err)
}

// Check if there are any profiles
if len(profiles) == 0 {
return errors.New("no profiles found")
}

// Validate each profile's credentials
for _, profile := range profiles {
if profile.ProfileName == "" {
return errors.New("a profile has an empty name")
}

creds := profile.Credentials

// Flag to check if at least one credential is present
hasAtLeastOneCredential := false

// Validate AWS credentials if present
if creds.AWS.AccessKey != "" || creds.AWS.SecretKey != "" {
hasAtLeastOneCredential = true
if creds.AWS.AccessKey == "" {
return fmt.Errorf("AWS AccessKey for profile '%s' is missing", profile.ProfileName)
}
if creds.AWS.SecretKey == "" {
return fmt.Errorf("AWS SecretKey for profile '%s' is missing", profile.ProfileName)
}
}

// Validate NCP credentials if present
if creds.NCP.AccessKey != "" || creds.NCP.SecretKey != "" {
hasAtLeastOneCredential = true
if creds.NCP.AccessKey == "" {
return fmt.Errorf("NCP AccessKey for profile '%s' is missing", profile.ProfileName)
}
if creds.NCP.SecretKey == "" {
return fmt.Errorf("NCP SecretKey for profile '%s' is missing", profile.ProfileName)
}
}

// Validate GCP credentials if present
if creds.GCP.PrivateKeyID != "" {
hasAtLeastOneCredential = true
if creds.GCP.PrivateKeyID == "" {
return fmt.Errorf("GCP PrivateKeyID for profile '%s' is missing", profile.ProfileName)
}
}

// Ensure that at least one credential is present
if !hasAtLeastOneCredential {
return fmt.Errorf("profile '%s' must have at least one set of credentials (AWS, NCP, or GCP)", profile.ProfileName)
}
}

return nil
}
8 changes: 8 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ services:
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
# Health check configuration
# OK [ 2xx ,3xx}, ERR [4xx,5xx,...etc]
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3300/readyZ"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s

##################
## OPTIONAL ##
Expand Down
55 changes: 55 additions & 0 deletions websrc/controllers/healthCheckHandlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
Copyright 2023 The Cloud-Barista Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers

import (
"net/http"
"time"

"github.com/cloud-barista/mc-data-manager/config"
"github.com/cloud-barista/mc-data-manager/models"
"github.com/labstack/echo/v4"
)

// GetSystemReadyHandler godoc
//
// @ID GetSystemReadyHandler
// @Summary Get System Ready Handler
// @Description Get System Ready
// @Tags [Ready]
// @Produce json
// @Success 200 {object} models.BasicResponse "System is Ready"
// @Failure 404 {object} models.BasicResponse "Profile Load , Failed: err"
// @Router /readyZ [Get]
func GetSystemReadyHandler(ctx echo.Context) error {
start := time.Now()
logger, logstrings := pageLogInit(ctx, "healthcheck-task", "Ready?", start)
credentailManger := config.NewProfileManager()
err := credentailManger.ValidateProfiles()
if err != nil {
errStr := "Profile Load , Failed : " + err.Error()
logger.Error().Msg(errStr)
return ctx.JSON(http.StatusNotFound, models.BasicResponse{
Result: logstrings.String(),
Error: &errStr,
})
}
jobEnd(logger, "System is Ready", start)
return ctx.JSON(http.StatusOK, models.BasicResponse{
Result: logstrings.String(),
Error: nil,
})
}
2 changes: 1 addition & 1 deletion websrc/controllers/publicfunc.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func pageLogInit(c echo.Context, pageName, pageInfo string, startTime time.Time)
logger := parentLogger.Output(multiWriter)

// Log page access information
logger.Info().Msgf("%s post page accessed", pageName)
logger.Info().Msgf("%s page accessed", pageName)
logger.Info().Msg(pageInfo)
logger.Info().Str("start time", startTime.Format(time.RFC3339))

Expand Down
1 change: 1 addition & 0 deletions websrc/serve/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ func InitServer(port string, addIP ...string) *echo.Echo {
e.GET("/swagger/*", echoSwagger.WrapHandler)

e.GET("/", controllers.MainGetHandler)
e.GET("/readyZ", controllers.GetSystemReadyHandler)

migrationGroup := e.Group("/migrate")
routes.MigrationRoutes(migrationGroup)
Expand Down