Skip to content

Commit 96987c7

Browse files
committed
multiple aws accounts
1 parent 458468f commit 96987c7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+4043
-445
lines changed

.circleci/config.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ jobs:
6060
chmod +x komiser_windows_amd64.exe komiser_darwin_amd64 komiser_linux_amd64
6161
- run:
6262
name: Push Linux binary
63-
command: aws s3 cp komiser_linux_amd64 s3://komiser/2.1.0/linux/komiser --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
63+
command: aws s3 cp komiser_linux_amd64 s3://komiser/2.2.0/linux/komiser --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
6464
- run:
6565
name: Push Windows binary
66-
command: aws s3 cp komiser_windows_amd64.exe s3://komiser/2.1.0/windows/komiser --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
66+
command: aws s3 cp komiser_windows_amd64.exe s3://komiser/2.2.0/windows/komiser --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
6767
- run:
6868
name: Push Mac OS X binary
69-
command: aws s3 cp komiser_darwin_amd64 s3://komiser/2.1.0/osx/komiser --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
69+
command: aws s3 cp komiser_darwin_amd64 s3://komiser/2.2.0/osx/komiser --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
7070
- run:
7171
name: Upload IAM policy
7272
command: aws s3 cp policy.json s3://komiser/policy.json --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
FROM alpine:3.9.4
22
MAINTAINER mlabouardy <mohamed@labouardy.com>
33

4-
ENV VERSION 2.1.0
4+
ENV VERSION 2.2.0
55
ENV PORT 3000
66
ENV DURATION 30
77

@@ -11,4 +11,4 @@ RUN curl -L https://s3.us-east-1.amazonaws.com/komiser/$VERSION/linux/komiser -o
1111
mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
1212

1313
EXPOSE $PORT
14-
ENTRYPOINT komiser start --port $PORT
14+
ENTRYPOINT ["komiser", "start"]

README.md

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,24 @@ Stay under budget by uncovering hidden costs, monitoring increases in spend, and
2828

2929
## Download
3030

31-
Below are the available downloads for the latest version of Komiser (2.1.0). Please download the proper package for your operating system and architecture.
31+
Below are the available downloads for the latest version of Komiser (2.2.0). Please download the proper package for your operating system and architecture.
3232

3333
### Linux:
3434

3535
```
36-
wget https://cli.komiser.io/2.1.0/linux/komiser
36+
wget https://cli.komiser.io/2.2.0/linux/komiser
3737
```
3838

3939
### Windows:
4040

4141
```
42-
wget https://cli.komiser.io/2.1.0/windows/komiser
42+
wget https://cli.komiser.io/2.2.0/windows/komiser
4343
```
4444

4545
### Mac OS X:
4646

4747
```
48-
wget https://cli.komiser.io/2.1.0/osx/komiser
48+
wget https://cli.komiser.io/2.2.0/osx/komiser
4949
```
5050

5151
Docker for Mac is best installed with Homebrew:
@@ -60,7 +60,7 @@ _Note_: make sure to add the execution permission to Komiser `chmod +x komiser`
6060
### Docker:
6161

6262
```
63-
docker run -d -p 3000:3000 -e AWS_ACCESS_KEY_ID="" -e AWS_SECRET_ACCESS_KEY="" -e AWS_DEFAULT_REGION="" --name komiser mlabouardy/komiser:2.1.0
63+
docker run -d -p 3000:3000 -e AWS_ACCESS_KEY_ID="" -e AWS_SECRET_ACCESS_KEY="" -e AWS_DEFAULT_REGION="" --name komiser mlabouardy/komiser:2.2.0
6464
```
6565

6666
## How to use
@@ -100,6 +100,38 @@ komiser start --port 3000 --redis localhost:6379 --duration 30
100100
<img src="https://s3.eu-west-3.amazonaws.com/komiser-assets/images/dashboard-aws.png"/>
101101
</p>
102102

103+
#### Multiple AWS Accounts Support
104+
105+
Komiser support multiple AWS accounts through named profiles that are stored in the `config` and `credentials files`. You can configure additional profiles by using `aws configure` with the `--profile` option, or by adding entries to the `config` and `credentials` files.
106+
107+
The following example shows a credentials file with 3 profiles (production, staging & sandbox accounts):
108+
109+
```
110+
[Production]
111+
aws_access_key_id=<AWS_ACCESS_KEY_ID>
112+
aws_secret_access_key=<AWS_SECRET_ACCESS_KEY>
113+
114+
[Staging]
115+
aws_access_key_id=<AWS_ACCESS_KEY_ID>
116+
aws_secret_access_key=<AWS_SECRET_ACCESS_KEY>
117+
118+
[Sandbox]
119+
aws_access_key_id=<AWS_ACCESS_KEY_ID>
120+
aws_secret_access_key=<AWS_SECRET_ACCESS_KEY>
121+
```
122+
123+
To enable multiple AWS accounts feature, add the --multiple option to Komiser:
124+
125+
```
126+
komiser start --port 3000 --redis localhost:6379 --duration 30 --multiple
127+
```
128+
129+
* If you point your browser to http://localhost:3000, you should be able to see your accounts:
130+
131+
<p align="center">
132+
<img src="https://s3.eu-west-3.amazonaws.com/komiser-assets/images/dashboard-aws-multiple.png"/>
133+
</p>
134+
103135
### GCP
104136

105137
* Create a service account with *Viewer* permission, see [Creating and managing service accounts](https://cloud.google.com/iam/docs/creating-managing-service-accounts) docs.
@@ -153,6 +185,7 @@ komiser start [OPTIONS]
153185
--duration value, -d value Cache expiration time (default: 30 minutes)
154186
--redis value, -r value Redis server (localhost:6379)
155187
--dataset value, -ds value BigQuery dataset name (project-id.dataset-name.table-name)
188+
--multiple, -m Enable multiple AWS accounts feature
156189
```
157190

158191
## Configuring Credentials

dashboard/src/app/app.component.html

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
</div>
5959
</li>
6060
<li>
61-
<a class="see-all" href="javascript:void(0);">
61+
<a class="see-all" routerLink="/notifications">
6262
<strong>See all notifications</strong>
6363
<i class="la la-angle-right"></i>
6464
</a>
@@ -138,11 +138,19 @@
138138
bottom: 0vh;
139139
display: block;
140140
width: 100%;">
141-
<label for="exampleFormControlSelect1">
142-
<i class="la la-cloud" style="margin-left:10px"></i> Select Cloud Provider</label>
141+
<label for="exampleFormControlSelect1" style="font-weight: 700">
142+
<i class="la la-cloud" style="margin-left:10px;"></i> Cloud Provider: </label>
143143
<select class="form-control" (change)="onCloudProviderSelected($event.target.value)">
144144
<option *ngFor="let provider of availableProviders" [value]="provider.value" [selected]="provider.value == currentProvider.value">{{provider.label}}</option>
145145
</select>
146+
<div *ngIf="currentProvider.value == 'aws' && profiles.length > 1" style="margin-top:10px;">
147+
<label for="exampleFormControlSelect1" style="font-weight: 700">
148+
<i class="devicon-redhat-plain" style="margin-left:10px;"></i> AWS Account: </label>
149+
<select class="form-control" (change)="onProfileSelected($event.target.value)">
150+
<option *ngFor="let profile of profiles" [value]="profile" [selected]="profile == currentProfile">{{profile}}</option>
151+
</select>
152+
</div>
153+
146154
</div>
147155

148156
</div>

dashboard/src/app/app.component.ts

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { GcpService } from './gcp.service';
44
import { StoreService } from './store.service';
55
import { not } from '@angular/compiler/src/output/output_ast';
66
import { Subscription } from 'rxjs';
7+
import { Subject } from "rxjs/Subject";
78
import * as moment from 'moment';
89

910
declare var ga: Function;
@@ -17,10 +18,12 @@ export class AppComponent implements OnDestroy {
1718

1819
public accountName: string = 'Username';
1920
public redAlarms: number;
21+
public profiles: Array<string> = [];
22+
public currentProfile: string;
2023
public notifications: Array<Object> = [];
2124
public _subscription: Subscription;
2225
public currentProvider: any;
23-
public availableProviders : Array<any> = [
26+
public availableProviders: Array<any> = [
2427
{
2528
label: 'Amazon Web Services',
2629
value: 'aws'
@@ -29,13 +32,13 @@ export class AppComponent implements OnDestroy {
2932
label: 'Google Cloud Platform',
3033
value: 'gcp'
3134
}
32-
]
35+
];
3336

3437
private _storeService: StoreService;
3538

3639
private providers: Map<String, Object> = new Map<String, Object>();
3740

38-
constructor(private awsService: AwsService, private gcpService: GcpService, private storeService: StoreService){
41+
constructor(private awsService: AwsService, private gcpService: GcpService, private storeService: StoreService) {
3942

4043
this.providers['aws'] = {
4144
label: 'Amazon Web Services',
@@ -49,6 +52,26 @@ export class AppComponent implements OnDestroy {
4952
logo: 'https://cdn.komiser.io/images/gcp.png'
5053
};
5154

55+
//if (this.storeService.getProvider() == 'aws') {
56+
if (localStorage.getItem('profile')) {
57+
this.currentProfile = localStorage.getItem('profile');
58+
} else {
59+
this.currentProfile = 'default';
60+
localStorage.setItem('profile', this.currentProfile);
61+
}
62+
63+
this.awsService.getProfiles().subscribe(profiles => {
64+
this.profiles = profiles;
65+
if (this.profiles.length > 0 && this.profiles.indexOf(this.currentProfile) == -1) {
66+
this.currentProfile = this.profiles[0];
67+
localStorage.setItem('profile', this.currentProfile);
68+
}
69+
}, err => {
70+
this.profiles = [];
71+
})
72+
// }
73+
74+
5275
this.currentProvider = this.providers[this.storeService.getProvider()];
5376
this.storeService.onProviderChanged(this.storeService.getProvider());
5477

@@ -64,22 +87,21 @@ export class AppComponent implements OnDestroy {
6487
})
6588
}
6689

67-
private getAccountName(){
68-
console.log(this.currentProvider);
69-
if (this.currentProvider.value == 'aws'){
90+
private getAccountName() {
91+
if (this.currentProvider.value == 'aws') {
7092
this.awsService.getAccountName().subscribe(data => {
7193
this.accountName = data.username;
7294
}, err => {
7395
this.accountName = 'Username';
7496
});
75-
97+
7698
this.awsService.getCloudwatchAlarms().subscribe(data => {
7799
this.redAlarms = data.ALARM;
78100
}, err => {
79101
this.redAlarms = 0;
80102
});
81103
} else {
82-
this.redAlarms = 0;
104+
this.redAlarms = 0;
83105

84106
this.gcpService.getProjects().subscribe(data => {
85107
this.accountName = data[0].name;
@@ -90,17 +112,24 @@ export class AppComponent implements OnDestroy {
90112
}
91113

92114
ngOnDestroy() {
93-
this._subscription.unsubscribe();
94-
}
95-
96-
public calcMoment(timestamp){
97-
return moment(timestamp).fromNow();
98-
}
99-
100-
public onCloudProviderSelected(provider){
101-
this.currentProvider = this.providers[provider];
102-
this._storeService.onProviderChanged(provider);
103-
this.getAccountName();
104-
}
115+
this._subscription.unsubscribe();
116+
}
117+
118+
public calcMoment(timestamp) {
119+
return moment(timestamp).fromNow();
120+
}
121+
122+
public onCloudProviderSelected(provider) {
123+
this.currentProvider = this.providers[provider];
124+
this._storeService.onProviderChanged(provider);
125+
this.getAccountName();
126+
}
127+
128+
public onProfileSelected(profile) {
129+
this.currentProfile = profile;
130+
localStorage.setItem('profile', this.currentProfile);
131+
this._storeService.onProfileChanged(profile);
132+
this.getAccountName();
133+
}
105134

106135
}

dashboard/src/app/app.module.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { AwsLimitsComponent } from './limits/aws/aws.component';
3737
import { GcpLimitsComponent } from './limits/gcp/gcp.component';
3838
import { AwsProfileComponent } from './profile/aws/aws.component';
3939
import { GcpProfileComponent } from './profile/gcp/gcp.component';
40+
import { NotificationsComponent } from './notifications/notifications.component';
4041

4142

4243

@@ -76,6 +77,11 @@ const appRoutes: Routes = [
7677
component: LimitsComponent,
7778
data: { title: 'Service Limits Checks - Komiser' }
7879
},
80+
{
81+
path: 'notifications',
82+
component: NotificationsComponent,
83+
data: { title: 'Notifications - Komiser' }
84+
},
7985
{ path: '',
8086
component: DashboardComponent,
8187
data: { title: 'Dashboard - Komiser' }
@@ -108,7 +114,8 @@ const appRoutes: Routes = [
108114
AwsLimitsComponent,
109115
GcpLimitsComponent,
110116
AwsProfileComponent,
111-
GcpProfileComponent
117+
GcpProfileComponent,
118+
NotificationsComponent
112119
],
113120
imports: [
114121
RouterModule.forRoot(

0 commit comments

Comments
 (0)