-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
junaid
committed
Jun 18, 2020
0 parents
commit cdfd37c
Showing
14 changed files
with
1,258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
bin/ | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
### Intro | ||
A simple tool to list all the vm instances run in a cloud account. | ||
Supported clouds are AWS, Azure, GCP and DigitalOcean. | ||
|
||
|
||
### Build | ||
|
||
`go build -o bin/cloud-mon main.go` | ||
|
||
|
||
### Config file | ||
|
||
See `scratch/sample-conf.json` for sample config file. | ||
Fill the necessary details in the config file. | ||
Provide config file path with -c parameter. | ||
|
||
`bin/cloud-mon -c /path/to/file.json` | ||
|
||
If you want to exclude any cloud, remove it from config file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package cloudman | ||
|
||
import ( | ||
"github.com/aws/aws-sdk-go/aws" | ||
"github.com/aws/aws-sdk-go/aws/awserr" | ||
"github.com/aws/aws-sdk-go/aws/credentials" | ||
"github.com/aws/aws-sdk-go/aws/session" | ||
"github.com/aws/aws-sdk-go/service/ec2" | ||
"log" | ||
) | ||
|
||
type AWSCloud struct { | ||
credentials AWSCredentials | ||
session *session.Session | ||
} | ||
|
||
func NewAWSCloud(c AWSCredentials) *AWSCloud { | ||
|
||
creds := credentials.NewStaticCredentials(c.AccessKey, c.AccessSecret, "") | ||
|
||
sess, err := session.NewSession(&aws.Config{ | ||
Credentials: creds, | ||
}) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
out := AWSCloud{ | ||
credentials: c, | ||
session: sess, | ||
} | ||
|
||
return &out | ||
|
||
} | ||
|
||
type AWSCredentials struct { | ||
AccessKey string | ||
AccessSecret string | ||
} | ||
|
||
func (c *AWSCloud) GetInstanceListAllRegions() ([]InstanceListResponse, error) { | ||
|
||
rList := []string{ | ||
"ca-central-1", | ||
"eu-central-1", | ||
"eu-west-1", | ||
"eu-west-2", | ||
"eu-south-1", | ||
"eu-west-3", | ||
"eu-north-1", | ||
"me-south-1", | ||
"sa-east-1", | ||
"ap-northeast-3", | ||
"ap-northeast-2", | ||
"ap-southeast-1", | ||
"ap-southeast-2", | ||
"ap-northeast-1", | ||
"us-east-2", | ||
"us-east-1", | ||
"us-west-1", | ||
"us-west-2", | ||
"af-south-1", | ||
"ap-east-1", | ||
"ap-south-1", | ||
} | ||
|
||
var out []InstanceListResponse | ||
|
||
recvChan := make(chan []InstanceListResponse, len(rList)) | ||
|
||
for _, region := range rList { | ||
go func(reg string) { | ||
res, _ := c.GetInstanceList(reg) | ||
recvChan <- res | ||
}(region) | ||
} | ||
|
||
for j := 0; j < len(rList); j++ { | ||
list := <-recvChan | ||
out = append(out, list...) | ||
} | ||
|
||
return out, nil | ||
} | ||
|
||
func (c *AWSCloud) GetInstanceList(region string) ([]InstanceListResponse, error) { | ||
|
||
sess := c.session.Copy(&aws.Config{ | ||
Region: aws.String(region), | ||
}) | ||
client := ec2.New(sess) | ||
|
||
input := &ec2.DescribeInstancesInput{} | ||
|
||
result, err := client.DescribeInstances(input) | ||
if err != nil { | ||
if aerr, ok := err.(awserr.Error); ok { | ||
switch aerr.Code() { | ||
default: | ||
log.Println(aerr.Error()) | ||
} | ||
} else { | ||
// Print the error, cast err to awserr.Error to get the Code and | ||
// Message from an error. | ||
log.Println(err.Error()) | ||
} | ||
return nil, err | ||
} | ||
|
||
var out []InstanceListResponse | ||
for _, res := range result.Reservations { | ||
for _, ins := range res.Instances { | ||
name := c.getInstanceName(ins.Tags) | ||
obj := InstanceListResponse{ | ||
Name: name, | ||
Id: *ins.InstanceId, | ||
Status: *ins.State.Name, | ||
LaunchDate: ins.LaunchTime.String(), | ||
Region: region, | ||
MachineType: *ins.InstanceType, | ||
} | ||
out = append(out, obj) | ||
} | ||
|
||
} | ||
|
||
return out, nil | ||
} | ||
|
||
func (c *AWSCloud) getInstanceName(t []*ec2.Tag) string { | ||
name := "" | ||
for _, tag := range t { | ||
if *tag.Key == "Name" { | ||
name = *tag.Value | ||
} | ||
} | ||
return name | ||
} | ||
|
||
func (c *AWSCloud) GetInstanceDetails() { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package cloudman | ||
|
||
import ( | ||
"context" | ||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" | ||
"github.com/Azure/go-autorest/autorest" | ||
"github.com/Azure/go-autorest/autorest/adal" | ||
"github.com/Azure/go-autorest/autorest/azure" | ||
"log" | ||
) | ||
|
||
type AzureCloud struct { | ||
credentials AzureCredentials | ||
authorizer *autorest.BearerAuthorizer | ||
} | ||
|
||
func NewAzureCloud(c AzureCredentials) *AzureCloud { | ||
|
||
oauthConfig, err := adal.NewOAuthConfig(azure.PublicCloud.ActiveDirectoryEndpoint, c.Tenant) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
|
||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, c.ID, c.Key, azure.PublicCloud.ResourceManagerEndpoint) | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
|
||
authorizer := autorest.NewBearerAuthorizer(spt) | ||
|
||
out := AzureCloud{ | ||
credentials: c, | ||
authorizer: authorizer, | ||
} | ||
|
||
return &out | ||
|
||
} | ||
|
||
type AzureCredentials struct { | ||
ID string | ||
Key string | ||
Tenant string | ||
Subscription string | ||
} | ||
|
||
func (c *AzureCloud) GetInstanceListAllRegions() ([]InstanceListResponse, error) { | ||
|
||
out, err := c.GetInstanceList("") | ||
|
||
return out, err | ||
} | ||
|
||
func (c *AzureCloud) GetInstanceList(project string) ([]InstanceListResponse, error) { | ||
|
||
vmClient := compute.NewVirtualMachinesClient(c.credentials.Subscription) | ||
vmClient.Authorizer = c.authorizer | ||
|
||
res, err := vmClient.List(context.Background(), "application-0jkqy6") | ||
if err != nil { | ||
log.Println(err) | ||
return nil, err | ||
} | ||
vmList := res.Values() | ||
|
||
for err := res.NextWithContext(context.Background()); err != nil; { | ||
log.Println(err) | ||
vmList = append(res.Values()) | ||
} | ||
|
||
var out []InstanceListResponse | ||
for _, vm := range vmList { | ||
//log.Println(*vm.Name) | ||
|
||
obj := InstanceListResponse{ | ||
Name: *vm.Name, | ||
Id: *vm.ID, | ||
Status: *vm.ProvisioningState, | ||
LaunchDate: "", | ||
Region: *vm.Location, | ||
MachineType: string(vm.HardwareProfile.VMSize), | ||
} | ||
out = append(out, obj) | ||
} | ||
|
||
return out, nil | ||
} | ||
|
||
func (c *AzureCloud) GetInstanceDetails() { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package cloudman | ||
|
||
type Cloud interface { | ||
//SetClientCredentials() | ||
GetInstanceListAllRegions() ([]InstanceListResponse, error) | ||
GetInstanceList(region string) ([]InstanceListResponse, error) | ||
GetInstanceDetails() | ||
} | ||
|
||
type InstanceListResponse struct { | ||
Name string | ||
Id string | ||
Status string | ||
LaunchDate string | ||
Region string | ||
MachineType string | ||
Project string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package cloudman | ||
|
||
import ( | ||
"context" | ||
"github.com/digitalocean/godo" | ||
"golang.org/x/oauth2" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type DOCloud struct { | ||
credentials DOCredentials | ||
client *godo.Client | ||
} | ||
|
||
// first login using gcloud cli | ||
// use autogenerated credentials from cli to authenicate as acount level | ||
type TokenSource struct { | ||
AccessToken string | ||
} | ||
|
||
func (t *TokenSource) Token() (*oauth2.Token, error) { | ||
token := &oauth2.Token{ | ||
AccessToken: t.AccessToken, | ||
} | ||
return token, nil | ||
} | ||
func NewDOCloud(c DOCredentials) *DOCloud { | ||
|
||
tokenSource := &TokenSource{ | ||
AccessToken: c.AccessToken, | ||
} | ||
|
||
oauthClient := oauth2.NewClient(context.Background(), tokenSource) | ||
client := godo.NewClient(oauthClient) | ||
|
||
out := DOCloud{ | ||
credentials: c, | ||
client: client, | ||
} | ||
|
||
return &out | ||
|
||
} | ||
|
||
type DOCredentials struct { | ||
AccessToken string | ||
} | ||
|
||
func (c *DOCloud) GetInstanceListAllRegions() ([]InstanceListResponse, error) { | ||
|
||
out, err := c.GetInstanceList("") | ||
return out, err | ||
} | ||
|
||
func (c *DOCloud) GetInstanceList(project string) ([]InstanceListResponse, error) { | ||
|
||
droplets, _, err := c.client.Droplets.List(context.Background(), &godo.ListOptions{ | ||
Page: 0, | ||
PerPage: 100, | ||
}) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var res []InstanceListResponse | ||
|
||
for _, droplet := range droplets { | ||
|
||
obj := InstanceListResponse{ | ||
Name: droplet.Name, | ||
Id: strconv.Itoa(int(droplet.ID)), | ||
Status: droplet.Status, | ||
LaunchDate: droplet.Created, | ||
Region: droplet.Region.Name, | ||
MachineType: droplet.Size.Slug, | ||
Project: "", | ||
} | ||
res = append(res, obj) | ||
} | ||
|
||
return res, nil | ||
} | ||
|
||
// split and extract last part or uri | ||
// e.g https://www.googleapis.com/compute/v1/projects/cloudplex-infrastructure/zones/us-central1-b | ||
func (c *DOCloud) extract(in string) string { | ||
|
||
out := strings.Split(in, "/") | ||
if len(out) > 0 { | ||
return out[len(out)-1] | ||
} else { | ||
return in | ||
} | ||
} | ||
|
||
func (c *DOCloud) GetInstanceDetails() { | ||
|
||
} |
Oops, something went wrong.