Skip to content

Commit

Permalink
Add discover mode
Browse files Browse the repository at this point in the history
  • Loading branch information
zanetworker committed Jan 16, 2024
1 parent ccf862e commit 5c129ca
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 38 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,43 @@ To use this tool, you need to have Go installed on your machine. Visit [Go's off
1. Clone the repository to your local machine.
2. Navigate to the cloned directory and build the tool with Go:

## Run in Manual Interactive Mode
```sh
go build -o hcp-sizer
```

3. Run the calculator `./hcp-sizer`
4. Follow the interactive prompts to enter your cluster's specifications and choose the calculation method.


## Run in Discovery Mode

The HCP Sizer application has a special '_discover_' mode, which allows it to _discover_ needed input from a cluster directly. In this mode, the application will automatically fetch data from a Kubernetes cluster and perform sizing calculations without interactive prompts. This is particularly useful for continuous monitoring or periodic data fetching scenarios.

### How to Enable Discovery Mode
To run the HCP Sizer in _discovery_ mode, use the -d or --discover flag when starting the application. Here's how you can do it:

```sh
./hcp-sizer --discover
````

Or, using the shorthand flag version:

```sh
./hcp-sizer -d
```

### What Happens in discovery Mode
When running in daemon mode, the application performs the following actions:

* Initializes a connection to the Kubernetes cluster using the configured Kubernetes client.
* Fetches the current resource data (CPU, memory, and maximum pods) for nodes labeled as control-plane.
* Performs the sizing calculations based on the fetched data.
* Outputs the calculation results to the console.
* This process is done once, immediately after the application starts.
* Logging and Output


# Use the release binaries


Expand Down
12 changes: 6 additions & 6 deletions discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type NodeResourceInfo struct {
NodeName string
CPU float64 // CPUs in the node
Memory float64 // Memory in GiB
MaxPods int // Max Pods, needs custom logic for OpenShift
MaxPods int // Max Pods
}

func FetchClusterDataTwo(clientset *kubernetes.Clientset) ([]NodeResourceInfo, error) {
Expand All @@ -68,8 +68,8 @@ func FetchClusterDataTwo(clientset *kubernetes.Clientset) ([]NodeResourceInfo, e
cpu := node.Status.Allocatable.Cpu().MilliValue()
memory := node.Status.Allocatable.Memory().Value()
memoryInGiB := float64(memory) / (1024 * 1024 * 1024)
// Placeholder for maxPods logic
maxPods := inferMaxPodsFromNode(node) // Implement this function based on your setup

maxPods := inferMaxPodsFromNode(node)

nodesResourceInfo = append(nodesResourceInfo, NodeResourceInfo{
NodeName: node.Name,
Expand All @@ -88,12 +88,12 @@ func inferMaxPodsFromNode(node corev1.Node) int {
// The value is a Quantity, which needs to be parsed to an int
maxPods, b := allocatablePods.AsInt64()
if b != true {
// Handle error or use a default value if parsing fails
return 250 // Example default value
// Return the defult if the value cannot be parsed or if scale didn't happen
return 250
}
return int(maxPods)
}

// Default value if the allocatable pods are not set
return 250 // Adjust this default value based on your needs
return 250
}
70 changes: 38 additions & 32 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ func calculateETCDStorage(podCount float64) float64 {
}

func calculateMaxHCPs(workerCPUs, workerMemory, maxPods, apiRate float64, useLoadBased bool) float64 {
// print all values for debugging
//print all values for debugging
fmt.Printf("workerCPUs: %f\n", workerCPUs)
fmt.Printf("workerMemory: %f\n", workerMemory)
fmt.Printf("maxPods: %f\n", maxPods)
fmt.Printf("apiRate: %f\n", apiRate)
fmt.Printf("useLoadBased: %t\n", useLoadBased)
fmt.Printf("Using Load-based: %t\n", useLoadBased)

maxHCPsByCPU := workerCPUs / cpuRequestPerHCP
maxHCPsByMemory := workerMemory / memoryRequestPerHCP
Expand Down Expand Up @@ -118,22 +118,48 @@ func promptForSelection(promptLabel string, items []string) int {
return -1
}

var discoverMode bool

func init() {
rootCmd.PersistentFlags().BoolVarP(&discoverMode, "discover", "d", false, "Run the application in discover mode")
}

var rootCmd = &cobra.Command{
Use: "hcp-sizer",
Short: "An HCP Sizing Calculator based on Science!",
Run: func(cmd *cobra.Command, args []string) {
resources := ServerResources{}
if discoverMode {
clientset, err := InitializeKubernetesClientForExternalUse()
if err != nil {
fmt.Println("Failed to initialize Kubernetes client:", err)
os.Exit(1)
}

resources.WorkerCPUs = promptForInput("Enter the number of vCPUs on the worker node")
resources.WorkerMemory = promptForInput("Enter the memory (in GiB) on the worker node")
resources.MaxPods = promptForInput("Enter the maximum number of pods on the worker node (usually 250 or 500)")
resources.PodCount = promptForInput("Enter the number of pods you plan to run on your cluster (for ETCD storage calculation)")
resources.CalculationMethod = promptForSelection("Select Calculation Method", []string{"Request-Based", "Load-Based"})
resources.UseLoadBased = resources.CalculationMethod == 1
nodeResources, err := FetchClusterDataTwo(clientset)
if err != nil {
fmt.Println("Failed to fetch data from Kubernetes cluster:", err)
os.Exit(1)
}

// for simplicity, let's pick the first node we see
resources.WorkerCPUs = nodeResources[0].CPU
resources.WorkerMemory = nodeResources[0].Memory
resources.MaxPods = float64(nodeResources[0].MaxPods)
resources.PodCount = promptForInput("Enter the number of pods you plan to run on your cluster (for ETCD storage calculation)")
resources.CalculationMethod = promptForSelection("Select Calculation Method", []string{"Request-Based", "Load-Based"})
resources.UseLoadBased = resources.CalculationMethod == 1
} else {
// add flag for command
resources.WorkerCPUs = promptForInput("Enter the number of vCPUs on the worker node")
resources.WorkerMemory = promptForInput("Enter the memory (in GiB) on the worker node")
resources.MaxPods = promptForInput("Enter the maximum number of pods on the worker node (usually 250 or 500)")
resources.PodCount = promptForInput("Enter the number of pods you plan to run on your cluster (for ETCD storage calculation)")
resources.CalculationMethod = promptForSelection("Select Calculation Method", []string{"Request-Based", "Load-Based"})
resources.UseLoadBased = resources.CalculationMethod == 1
}
// Check evaluation method, request-based or load-based (request is the more generic method)
// load-based is preferred when data about QPS is available (e.g. from an existing cluster)

if resources.UseLoadBased {
green := color.New(color.FgGreen)

Expand All @@ -153,34 +179,14 @@ var rootCmd = &cobra.Command{
// Print the results
italitYellow.Printf("Maximum HCPs that can be hosted: %.2f\n", math.Floor(resources.MaxHCPs))
italitYellow.Printf("Estimated HCP ETCD Storage Requirement: %.3f GiB\n", resources.EtcdStorage)

},
}

func main() {
//if err := rootCmd.Execute(); err != nil {
// fmt.Println(err)
// os.Exit(1)
//}

clientset, err := InitializeKubernetesClientForExternalUse()
if err != nil {
fmt.Println("Failed to initialize Kubernetes client:", err)
os.Exit(1)
}

resources, err := FetchClusterDataTwo(clientset)
if err != nil {
fmt.Println("Failed to fetch data from Kubernetes cluster:", err)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}

// for simplicity, let's pick the first node we see
resources = []NodeResourceInfo{resources[0]}
for _, resource := range resources {
fmt.Printf("NodeName: %s\n", resource.NodeName)
fmt.Printf("CPU: %f\n", resource.CPU)
fmt.Printf("Memory: %f\n", resource.Memory)
fmt.Printf("MaxPods: %d\n", resource.MaxPods)
}

}

0 comments on commit 5c129ca

Please sign in to comment.