├── _config.yml ├── docs ├── _config.yml ├── imgs │ ├── architecture.png │ ├── architecture_global.png │ └── reachability_flow.png ├── load-balancing.md ├── requirements.md ├── migrations.md ├── plugins_examples │ └── BeforeRequestPlugin.go ├── index.md ├── reachability.md ├── groups.md ├── contributing.md ├── plugins.md ├── https.md ├── rate-limiting.md ├── healthcheck.md ├── architecture.md ├── service-management.md └── services.md ├── dashboard ├── .dockerignore ├── .browserslistrc ├── .postcssrc.js ├── public │ ├── favicon.ico │ ├── assets │ │ ├── logo.png │ │ ├── gAPIlogo.PNG │ │ └── webfonts │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff │ │ │ ├── fa-regular-400.woff2 │ │ │ └── fa-solid-900.woff2 │ └── index.html ├── src │ ├── assets │ │ ├── logo.png │ │ └── gAPIlogo.png │ ├── store │ │ ├── modules │ │ │ ├── services-groups │ │ │ │ ├── getters.js │ │ │ │ ├── index.js │ │ │ │ ├── mutations.js │ │ │ │ └── actions.js │ │ │ ├── full-screen │ │ │ │ ├── getters.js │ │ │ │ ├── mutations.js │ │ │ │ ├── actions.js │ │ │ │ └── index.js │ │ │ ├── user_permissions │ │ │ │ ├── getters.js │ │ │ │ ├── mutations.js │ │ │ │ ├── index.js │ │ │ │ └── actions.js │ │ │ ├── plugins │ │ │ │ ├── getters.js │ │ │ │ ├── mutations.js │ │ │ │ ├── index.js │ │ │ │ └── actions.js │ │ │ ├── users │ │ │ │ ├── getters.js │ │ │ │ ├── index.js │ │ │ │ ├── mutations.js │ │ │ │ └── actions.js │ │ │ └── apps-groups │ │ │ │ ├── getters.js │ │ │ │ ├── index.js │ │ │ │ ├── mutations.js │ │ │ │ └── actions.js │ │ └── actions.js │ ├── configs │ │ ├── random.js │ │ ├── chartColors.js │ │ ├── permissions.js │ │ └── urls.js │ ├── api │ │ ├── api.js │ │ ├── plugins.js │ │ ├── user_permissions.js │ │ ├── analytics.js │ │ ├── auth.js │ │ ├── http.js │ │ └── users.js │ ├── components │ │ ├── charts │ │ │ ├── Pie.vue │ │ │ ├── BarChart.vue │ │ │ ├── LineChart.vue │ │ │ └── DoughnutChart.vue │ │ ├── InformationPanel.vue │ │ ├── plugins │ │ │ └── PluginsList.vue │ │ └── modals │ │ │ ├── ErrorMessage.vue │ │ │ ├── SuccessModal.vue │ │ │ └── ConfirmationModal.vue │ ├── views │ │ ├── Plugins │ │ │ └── Plugins.vue │ │ ├── Analytics │ │ │ ├── Realtime.vue │ │ │ ├── ByApplication.vue │ │ │ ├── ByApi.vue │ │ │ └── Live │ │ │ │ └── LiveRequests.vue │ │ ├── ServiceGroup │ │ │ └── ServiceGroupList.vue │ │ ├── Home.vue │ │ ├── Service │ │ │ ├── ServiceLogs.vue │ │ │ └── ViewService.vue │ │ ├── Users │ │ │ ├── ListUsers.vue │ │ │ └── NewUser.vue │ │ └── ServiceDiscovery │ │ │ ├── ListServicesGroup.vue │ │ │ └── NewApplicationGroup.vue │ ├── libs │ │ └── string_utils.js │ ├── App.vue │ ├── main.js │ ├── auth.js │ ├── utils.js │ └── store.js ├── .env.development ├── .env-example ├── .env.production ├── .gitignore ├── babel.config.js ├── .eslintrc.js ├── Dockerfile ├── package.json └── index.js ├── api ├── swagger │ ├── .gitignore │ ├── package.json │ ├── README.md │ ├── service │ │ ├── AuthenticationService.js │ │ ├── AnalyticsService.js │ │ └── AdminService.js │ ├── controllers │ │ ├── Authentication.js │ │ ├── Analytics.js │ │ └── Admin.js │ ├── utils │ │ └── writer.js │ ├── .swagger-codegen-ignore │ └── index.js ├── servicediscovery │ ├── constants │ │ ├── db.go │ │ └── mongo.go │ ├── utils │ │ └── utils.go │ ├── service │ │ └── service-repository.go │ ├── servicegroup │ │ └── service-group-repository.go │ ├── appgroups │ │ └── app-group-repository.go │ └── validator.go ├── utils │ ├── bool.go │ ├── file.go │ ├── errors.go │ ├── array.go │ ├── date.go │ └── printer.go ├── server │ ├── migrations │ │ └── oracle │ │ │ ├── 1557849129827_add_other_info_to_logs_table.sql │ │ │ ├── 1562949036664_add_logs_enabled_to_service.sql │ │ │ ├── 1560442956597_insert_req_logs_duration_error_gapi_config.sql │ │ │ ├── 1560442964103_insert_req_logs_duration_success_gapi_config.sql │ │ │ ├── 1559742108237_create_oauth_clients_table.sql │ │ │ ├── 1560442148818_create_gapi_configurations.sql │ │ │ ├── 1557849224827_add_request_logs_index_name_index.sql │ │ │ ├── 1560530781898_create_user_permissions.sql │ │ │ ├── 1557849124827_create_request_logs_table_indexes.sql │ │ │ ├── 1557849234827_create_api_analytics_table.sql │ │ │ ├── 1557849123807_create_services_hosts_table.sql │ │ │ ├── 1557849123677_create_services_apps_table.sql │ │ │ ├── 1557849123607_create_services_groups_table.sql │ │ │ ├── 1557849123509_create_users_table.sql │ │ │ ├── 1557849124807_create_request_logs_table.sql │ │ │ └── 1557849123707_create_services_table.sql │ └── go.mod ├── user_permission │ ├── models │ │ └── user_permission.go │ ├── providers │ │ └── provider.go │ └── user_permission.go ├── logs │ ├── logworkrequest.go │ ├── models │ │ └── requestlogging.go │ ├── workerqueue.go │ ├── providers │ │ └── elastic.go │ └── worker.go ├── plugins │ ├── interfaces.go │ ├── configuration.go │ ├── constants.go │ ├── general_plugin.go │ ├── plugins.go │ └── before_request_plugin.go ├── oauth_clients │ ├── providers.go │ ├── oauth_clients.go │ ├── oauth_clients-mongo.go │ └── oauth_clients-oracle.go ├── oci8.pc ├── build_plugins.sh ├── notifications │ ├── notifications.go │ └── slack.go ├── thirdpartyauthentication │ ├── user_information.go │ └── oauth.go ├── migrations │ └── oracle │ │ └── 1560530781898_create_user_permissions.sql ├── rabbit-listener │ └── go.mod ├── controllers │ ├── dependencyinjector.go │ ├── plugins.go │ ├── analytics.go │ ├── gapi.go │ ├── authentication.go │ └── api_documentation.go ├── routes │ ├── authentication.go │ ├── plugins.go │ ├── api_documentation.go │ ├── routes.go │ ├── gapi.go │ ├── analytics.go │ ├── user_permission.go │ ├── apps-groups.go │ └── users.go ├── database │ ├── pagination.go │ ├── oracle.go │ ├── database.go │ ├── mongo.go │ └── migrations │ │ └── oracle.go ├── start.sh ├── http │ ├── utils.go │ └── httpresponse.go ├── config │ ├── constants.go │ └── urls.go ├── users │ ├── models │ │ └── user.go │ ├── providers │ │ └── users-repository.go │ └── userservice.go ├── install.sh ├── api-analytics │ └── api-analytics.go ├── authentication │ └── ldap.go ├── build.sh ├── rabbit │ └── rabbit.go ├── sockets │ ├── requestscounter.go │ └── listener.go ├── go.mod ├── ratelimiting │ └── metric.go ├── mongodb-update.js ├── configs-example │ └── gAPI.json ├── Dockerfile-rabbitlistener └── Dockerfile ├── .gitignore ├── nginx └── sites-enabled │ ├── gapi-socket │ └── gapi-api ├── README.md ├── CONTRIBUTING.md ├── LICENSE ├── docker-compose.yml └── .env.example /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /dashboard/.dockerignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules -------------------------------------------------------------------------------- /dashboard/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 -------------------------------------------------------------------------------- /api/swagger/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | package-lock.json 3 | .swagger-codegen/* 4 | -------------------------------------------------------------------------------- /dashboard/.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } -------------------------------------------------------------------------------- /dashboard/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/favicon.ico -------------------------------------------------------------------------------- /docs/imgs/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/docs/imgs/architecture.png -------------------------------------------------------------------------------- /dashboard/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/src/assets/logo.png -------------------------------------------------------------------------------- /dashboard/public/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/logo.png -------------------------------------------------------------------------------- /dashboard/src/assets/gAPIlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/src/assets/gAPIlogo.png -------------------------------------------------------------------------------- /docs/imgs/architecture_global.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/docs/imgs/architecture_global.png -------------------------------------------------------------------------------- /docs/imgs/reachability_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/docs/imgs/reachability_flow.png -------------------------------------------------------------------------------- /api/servicediscovery/constants/db.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const ( 4 | SERVICE_NAME = "/service-discovery" 5 | ) 6 | -------------------------------------------------------------------------------- /dashboard/public/assets/gAPIlogo.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/gAPIlogo.PNG -------------------------------------------------------------------------------- /api/utils/bool.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func BoolToInt(b bool) int { 4 | if b { 5 | return 1 6 | } 7 | return 0 8 | } 9 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/services-groups/getters.js: -------------------------------------------------------------------------------- 1 | export const groups = state => { 2 | return state.groups; 3 | }; 4 | -------------------------------------------------------------------------------- /dashboard/.env.development: -------------------------------------------------------------------------------- 1 | API_PROTOCOL=http 2 | API_HOST=localhost 3 | API_PORT=8080 4 | SOCKET_HOST=localhost 5 | SOCKET_PORT=5000 -------------------------------------------------------------------------------- /dashboard/src/configs/random.js: -------------------------------------------------------------------------------- 1 | export function randomBetween(x, y) { 2 | return Math.floor(Math.random() * y + x); 3 | } 4 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/full-screen/getters.js: -------------------------------------------------------------------------------- 1 | export const isFullscreen = state => { 2 | return state.isFullscreen; 3 | }; 4 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/user_permissions/getters.js: -------------------------------------------------------------------------------- 1 | export const permissions = state => { 2 | return state.permissions; 3 | }; 4 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849129827_add_other_info_to_logs_table.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE gapi_request_logs 2 | ADD other_info CLOB default '{}' -------------------------------------------------------------------------------- /api/server/migrations/oracle/1562949036664_add_logs_enabled_to_service.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE gapi_services 2 | ADD logs_enabled number(1) default 1 -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /api/user_permission/models/user_permission.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type UserPermission struct { 4 | UserId string 5 | ServiceId string 6 | } 7 | -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /dashboard/public/assets/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Glintt/gAPI/HEAD/dashboard/public/assets/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /dashboard/.env-example: -------------------------------------------------------------------------------- 1 | API_PROTOCOL=#API_PROTOCOL# 2 | API_HOST=#API_HOST# 3 | API_PORT=#API_HOST# 4 | SOCKET_HOST=#SOCKET_HOST# 5 | SOCKET_PORT=#SOCKET_PORT# -------------------------------------------------------------------------------- /dashboard/.env.production: -------------------------------------------------------------------------------- 1 | API_PROTOCOL=#API_PROTOCOL# 2 | API_HOST=#API_HOST# 3 | API_PORT=#API_HOST# 4 | SOCKET_HOST=#SOCKET_HOST# 5 | SOCKET_PORT=#SOCKET_PORT# -------------------------------------------------------------------------------- /dashboard/src/store/modules/user_permissions/mutations.js: -------------------------------------------------------------------------------- 1 | export const updatePermissions = (state, permissions) => { 2 | state.permissions = permissions; 3 | }; 4 | -------------------------------------------------------------------------------- /api/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io/ioutil" 5 | ) 6 | 7 | func LoadJsonFile(location string) ([]byte, error) { 8 | return ioutil.ReadFile(location) 9 | } 10 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/plugins/getters.js: -------------------------------------------------------------------------------- 1 | export const plugins = state => { 2 | return state.plugins; 3 | }; 4 | 5 | export const active = state => { 6 | return state.active; 7 | }; 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | api/configs/ 2 | **/bin/ 3 | 4 | dashboard/node_modules 5 | **/.env.* 6 | **/package-lock.json 7 | .env 8 | !.env.example 9 | 10 | *.exe 11 | 12 | .vagrant 13 | .vscode -------------------------------------------------------------------------------- /api/logs/logworkrequest.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import "github.com/Glintt/gAPI/api/logs/models" 4 | 5 | type LogWorkRequest struct { 6 | Name string 7 | LogToSave models.RequestLogging 8 | } 9 | -------------------------------------------------------------------------------- /api/plugins/interfaces.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import routing "github.com/qiangxue/fasthttp-routing" 4 | 5 | type BeforeRequestEntryPlugin interface { 6 | Call(c *routing.Context) error 7 | } 8 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/plugins/mutations.js: -------------------------------------------------------------------------------- 1 | export const plugins = (state, obj) => { 2 | state.plugins = obj; 3 | }; 4 | 5 | export const active = (state, obj) => { 6 | state.active = obj; 7 | }; 8 | -------------------------------------------------------------------------------- /api/utils/errors.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | 5 | ) 6 | 7 | func PreventCrash(){ 8 | if r := recover(); r != nil { 9 | LogMessage("Publish Log Panic recover", DebugLogType) 10 | } 11 | } -------------------------------------------------------------------------------- /dashboard/src/store/modules/full-screen/mutations.js: -------------------------------------------------------------------------------- 1 | export const openFullScreen = state => { 2 | state.isFullscreen = true; 3 | }; 4 | 5 | export const closeFullScreen = state => { 6 | state.isFullscreen = false; 7 | }; 8 | -------------------------------------------------------------------------------- /api/oauth_clients/providers.go: -------------------------------------------------------------------------------- 1 | package oauth_clients 2 | 3 | var OAuthClientsMethods = map[string]map[string]interface{}{ 4 | "mongo": { 5 | "find": FindOAuthClientMongo, 6 | }, 7 | "oracle": { 8 | "find": FindOAuthClientOracle}} 9 | -------------------------------------------------------------------------------- /dashboard/src/api/api.js: -------------------------------------------------------------------------------- 1 | export const api = { 2 | serviceDiscovery: require("@/api/service-discovery"), 3 | oauth: require("@/api/auth"), 4 | analytics: require("@/api/analytics"), 5 | plugins: require("@/api/plugins") 6 | }; 7 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1560442956597_insert_req_logs_duration_error_gapi_config.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO gapi_configurations (id, config_key, config_value) 2 | VALUES ('5ce8297c18549b0001c370c6', 'GAPI_REQUEST_LOGS_ERRORS_DURATION_DAYS', '90') -------------------------------------------------------------------------------- /api/server/migrations/oracle/1560442964103_insert_req_logs_duration_success_gapi_config.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO gapi_configurations (id, config_key, config_value) 2 | VALUES ('5cd9718fec062900012c0f29', 'GAPI_REQUEST_LOGS_SUCCESS_DURATION_DAYS', '15') -------------------------------------------------------------------------------- /dashboard/src/store/modules/full-screen/actions.js: -------------------------------------------------------------------------------- 1 | export const openFullScreen = ({ commit }) => { 2 | commit("openFullScreen"); 3 | }; 4 | 5 | export const closeFullScreen = ({ commit }) => { 6 | commit("closeFullScreen"); 7 | }; 8 | -------------------------------------------------------------------------------- /api/oci8.pc: -------------------------------------------------------------------------------- 1 | prefix=/usr 2 | includedir=${prefix}/include/oracle/18.3/client64 3 | libdir=${prefix}/lib/oracle/18.3/client64/lib 4 | 5 | Name: oci8 6 | Description: Oracle Instant Client 7 | Version: 18.3 8 | Cflags: -I${includedir} 9 | Libs: -L${libdir} -lclntsh -------------------------------------------------------------------------------- /api/servicediscovery/constants/mongo.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | const ( 4 | SERVICES_COLLECTION = "services" 5 | SERVICE_GROUP_COLLECTION = "services_groups" 6 | SERVICE_APPS_GROUP_COLLECTION = "services_apps_groups" 7 | PAGE_LENGTH = 10 8 | ) 9 | -------------------------------------------------------------------------------- /dashboard/src/configs/chartColors.js: -------------------------------------------------------------------------------- 1 | export const colors = [ 2 | "#009688", 3 | "#00BCD4", 4 | "#03A9F4", 5 | "#2196F3", 6 | "#3F51B5", 7 | "#F44336", 8 | "#4CAF50", 9 | "#FFC107", 10 | "#FF9800", 11 | "#FF5722", 12 | "#607D8B" 13 | ]; 14 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/users/getters.js: -------------------------------------------------------------------------------- 1 | export const usersList = state => { 2 | return state.users; 3 | }; 4 | 5 | export const user = state => { 6 | return state.user; 7 | }; 8 | 9 | export const alert = state => { 10 | return state.alert; 11 | }; 12 | -------------------------------------------------------------------------------- /dashboard/src/components/charts/Pie.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /dashboard/src/components/InformationPanel.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /api/build_plugins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd $1 4 | 5 | for d in */ ; do 6 | echo "Building plugins in: $d" 7 | cd $d 8 | for fi in *.go; do 9 | name=$(echo "$fi" | cut -f 1 -d '.') 10 | echo "Building $name" 11 | go build -buildmode=plugin -o $name.so $name.go 12 | done 13 | cd .. 14 | done -------------------------------------------------------------------------------- /docs/load-balancing.md: -------------------------------------------------------------------------------- 1 | ## Load Balancing 2 | 3 | gAPI implements a simple load balacing component. 4 | 5 | This component calls a random host, from those available and accessible. 6 | 7 | In the future, it will be implement a more complex load balancing algorithm with weights and better decisions between hosts. 8 | -------------------------------------------------------------------------------- /dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1559742108237_create_oauth_clients_table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE gapi_oauth_clients ( 2 | client_id varchar2(255), 3 | client_secret varchar2(255), 4 | created_at date default (sysdate), 5 | updated_at date default (sysdate), 6 | 7 | CONSTRAINT pk_app_clients PRIMARY KEY (client_id, client_secret) 8 | ) -------------------------------------------------------------------------------- /api/server/migrations/oracle/1560442148818_create_gapi_configurations.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 6/4/2019 3:13:25 PM (QP5 v5.206) */ 2 | create table gapi_configurations ( 3 | id varchar2(255) primary key, 4 | config_key varchar(255), 5 | config_value varchar2(255), 6 | 7 | CONSTRAINT unq_gapi_config_key UNIQUE (config_key) 8 | ) -------------------------------------------------------------------------------- /dashboard/src/store/modules/apps-groups/getters.js: -------------------------------------------------------------------------------- 1 | export const groups = state => { 2 | return state.groups; 3 | }; 4 | 5 | export const ungroupedApplications = state => { 6 | return state.ungrouped_applications; 7 | }; 8 | 9 | export const possibleMatches = state => { 10 | return state.possibleMatches; 11 | }; 12 | -------------------------------------------------------------------------------- /dashboard/src/views/Plugins/Plugins.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /api/notifications/notifications.go: -------------------------------------------------------------------------------- 1 | package notifications 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | ) 6 | 7 | var Methods = map[string]interface{}{ 8 | "Slack": SlackNotification} 9 | 10 | 11 | func SendNotification(msg string){ 12 | Methods[config.GApiConfiguration.Notifications.Type].(func(string))(msg) 13 | } -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849224827_add_request_logs_index_name_index.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 4:54:05 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_SERVICES_HOSTS 3 | -- Generated 5/14/2019 4:54:05 PM from GPLATFORM@HSDEV 4 | 5 | CREATE INDEX gapi_req_log_idx_name_index ON gapi_request_logs ( 6 | index_name 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /api/thirdpartyauthentication/user_information.go: -------------------------------------------------------------------------------- 1 | package thirdpartyauthentication 2 | 3 | type UserTokenInformation struct { 4 | Source string 5 | Name string 6 | Active bool 7 | Information string 8 | } 9 | 10 | type ProtectionInfo struct { 11 | Header string 12 | UserInfo string 13 | Cached bool 14 | Error error 15 | } 16 | -------------------------------------------------------------------------------- /api/migrations/oracle/1560530781898_create_user_permissions.sql: -------------------------------------------------------------------------------- 1 | create table gapi_user_services_permissions 2 | ( 3 | user_id varchar2(255), 4 | service_id varchar2(255), 5 | 6 | CONSTRAINT fk_gapi_permissions_service_id FOREIGN KEY (service_id) REFERENCES gapi_services (id), 7 | CONSTRAINT fk_gapi_permissions_user_id FOREIGN KEY (user_id) REFERENCES gapi_users (id) 8 | ) -------------------------------------------------------------------------------- /nginx/sites-enabled/gapi-socket: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | listen 5000; 4 | access_log /var/log/nginx/api_socket.log; 5 | charset utf-8; 6 | 7 | location / { 8 | proxy_pass http://backend:5000; 9 | proxy_set_header Host $host; 10 | proxy_set_header X-Real-IP $remote_addr; 11 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 12 | } 13 | } -------------------------------------------------------------------------------- /api/server/migrations/oracle/1560530781898_create_user_permissions.sql: -------------------------------------------------------------------------------- 1 | create table gapi_user_services_permissions 2 | ( 3 | user_id varchar2(255), 4 | service_id varchar2(255), 5 | 6 | CONSTRAINT fk_gapi_permissions_service_id FOREIGN KEY (service_id) REFERENCES gapi_services (id), 7 | CONSTRAINT fk_gapi_permissions_user_id FOREIGN KEY (user_id) REFERENCES gapi_users (id) 8 | ) -------------------------------------------------------------------------------- /dashboard/src/components/charts/BarChart.vue: -------------------------------------------------------------------------------- 1 | 2 | 17 | -------------------------------------------------------------------------------- /api/plugins/configuration.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | "path" 6 | ) 7 | 8 | func Configurations() config.GApiPluginsConfig { 9 | if config.GApiConfiguration.Plugins.Location == "" { 10 | config.GApiConfiguration.Plugins.Location = path.Dir(PLUGINS_LOCATION) + "/" 11 | } 12 | 13 | return config.GApiConfiguration.Plugins 14 | } 15 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/user_permissions/index.js: -------------------------------------------------------------------------------- 1 | import * as actions from "./actions"; 2 | import * as getters from "./getters"; 3 | import * as mutations from "./mutations"; 4 | 5 | const state = { 6 | permissions: [] 7 | }; 8 | 9 | const namespaced = true; 10 | 11 | export default { 12 | namespaced, 13 | state, 14 | actions, 15 | getters, 16 | mutations 17 | }; 18 | -------------------------------------------------------------------------------- /api/server/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Glintt/gAPI/api/server 2 | 3 | replace github.com/Glintt/gAPI/api => ../ 4 | 5 | require ( 6 | github.com/Glintt/gAPI/api v0.0.0-00010101000000-000000000000 7 | github.com/joho/godotenv v1.3.0 8 | github.com/qiangxue/fasthttp-routing v0.0.0-20160225050629-6ccdc2a18d87 9 | github.com/robfig/cron v1.1.0 10 | github.com/valyala/fasthttp v1.3.0 11 | ) 12 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/plugins/index.js: -------------------------------------------------------------------------------- 1 | import * as actions from "./actions"; 2 | import * as getters from "./getters"; 3 | import * as mutations from "./mutations"; 4 | 5 | const state = { 6 | plugins: {}, 7 | active: {} 8 | }; 9 | 10 | const namespaced = true; 11 | 12 | export default { 13 | namespaced, 14 | state, 15 | actions, 16 | getters, 17 | mutations 18 | }; 19 | -------------------------------------------------------------------------------- /dashboard/src/components/charts/LineChart.vue: -------------------------------------------------------------------------------- 1 | 2 | 16 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/services-groups/index.js: -------------------------------------------------------------------------------- 1 | import * as actions from "./actions"; 2 | import * as getters from "./getters"; 3 | import * as mutations from "./mutations"; 4 | 5 | const state = { 6 | groups: [] 7 | }; 8 | 9 | const namespaced = true; 10 | 11 | export default { 12 | namespaced, 13 | state, 14 | actions, 15 | getters, 16 | mutations 17 | }; 18 | -------------------------------------------------------------------------------- /api/rabbit-listener/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Glintt/gAPI/api/rabbit-listener 2 | 3 | replace github.com/Glintt/gAPI/api => ../ 4 | 5 | require ( 6 | github.com/Glintt/gAPI/api v0.0.0-00010101000000-000000000000 7 | github.com/qiangxue/fasthttp-routing v0.0.0-20160225050629-6ccdc2a18d87 8 | github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 9 | github.com/valyala/fasthttp v1.3.0 10 | ) 11 | -------------------------------------------------------------------------------- /dashboard/src/libs/string_utils.js: -------------------------------------------------------------------------------- 1 | if (!String.prototype.includes) { 2 | String.prototype.includes = function(search, start) { 3 | "use strict"; 4 | if (typeof start !== "number") { 5 | start = 0; 6 | } 7 | 8 | if (start + search.length > this.length) { 9 | return false; 10 | } else { 11 | return this.indexOf(search, start) !== -1; 12 | } 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/full-screen/index.js: -------------------------------------------------------------------------------- 1 | import * as actions from "./actions"; 2 | import * as getters from "./getters"; 3 | import * as mutations from "./mutations"; 4 | 5 | const state = { 6 | isFullscreen: false 7 | }; 8 | 9 | const namespaced = true; 10 | 11 | export default { 12 | namespaced, 13 | state, 14 | actions, 15 | getters, 16 | mutations 17 | }; 18 | -------------------------------------------------------------------------------- /api/controllers/dependencyinjector.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/users" 5 | userModels "github.com/Glintt/gAPI/api/users/models" 6 | routing "github.com/qiangxue/fasthttp-routing" 7 | ) 8 | 9 | func getUserService(c *routing.Context) users.UserService { 10 | userService, _ := users.NewUserServiceWithUser(userModels.GetInternalAPIUser()) 11 | return userService 12 | } -------------------------------------------------------------------------------- /dashboard/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/app"], 3 | plugins: [ 4 | [ 5 | "transform-inline-environment-variables", 6 | { 7 | include: [ 8 | "NODE_ENV", 9 | "API_HOST", 10 | "API_PORT", 11 | "SOCKET_HOST", 12 | "SOCKET_PORT", 13 | "API_PROTOCOL" 14 | ] 15 | } 16 | ] 17 | ] 18 | }; 19 | -------------------------------------------------------------------------------- /dashboard/src/components/charts/DoughnutChart.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | -------------------------------------------------------------------------------- /api/routes/authentication.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/qiangxue/fasthttp-routing" 5 | "github.com/Glintt/gAPI/api/controllers" 6 | ) 7 | 8 | func InitAuthenticationAPI(router *routing.Router) { 9 | router.Post("/oauth/token", controllers.GetTokenHandler) 10 | router.Get("/oauth/authorize", controllers.AuthorizeTokenHandler) 11 | router.Get("/oauth/me", controllers.MeHandler) 12 | } -------------------------------------------------------------------------------- /api/database/pagination.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | 4 | func PageFromTo(page int, page_length int, arrayLen int) (int , int) { 5 | from := ((page-1) * page_length) 6 | to := from + page_length 7 | if from >= arrayLen { 8 | from = arrayLen - page_length 9 | if from < 0 { 10 | from = 0 11 | } 12 | } 13 | 14 | if to >= arrayLen { 15 | to = arrayLen 16 | } 17 | 18 | return from, to 19 | } -------------------------------------------------------------------------------- /api/utils/array.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func ArrayContainsString(s []string, e string) bool { 4 | for _, a := range s { 5 | if a == e { 6 | return true 7 | } 8 | } 9 | return false 10 | } 11 | 12 | func RemoveStringFromArray(s []string, r string) []string { 13 | var s2 []string 14 | for _, v := range s { 15 | if v != r { 16 | s2 = append(s2, v) 17 | } 18 | } 19 | return s2 20 | } 21 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849124827_create_request_logs_table_indexes.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 4:54:05 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_SERVICES_HOSTS 3 | -- Generated 5/14/2019 4:54:05 PM from GPLATFORM@HSDEV 4 | 5 | CREATE INDEX gapi_request_logs_id_index ON gapi_request_logs ( 6 | service_name, method, request_grouper_date, date_time, user_agent, remote_addr, status_code 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /api/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export API_MANAGEMENT_PORT=8080 3 | export ELASTICSEARCH_HOST=localhost 4 | export ELASTICSEARCH_PORT=9200 5 | export SERVICEDISCOVERY_HOST=localhost 6 | export SERVICEDISCOVERY_PORT=8080 7 | export RABBITMQ_HOST=localhost 8 | export RABBITMQ_PORT=5672 9 | export RABBITMQ_USER=gapi 10 | export RABBITMQ_PASSWORD=gapi 11 | export RABBITMQ_QUEUE=gAPI-logqueue 12 | 13 | sh install.sh 14 | go run server.go -------------------------------------------------------------------------------- /dashboard/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | '@vue/prettier' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | } 17 | } -------------------------------------------------------------------------------- /docs/requirements.md: -------------------------------------------------------------------------------- 1 | ## Requirements 2 | 3 | 1. Golang - https://golang.org/ 4 | 2. Node - https://nodejs.org/en/ 5 | 3. RabbitMQ - https://www.rabbitmq.com/ (_Optional_) 6 | 4. Database: 7 | 8 | 1. MongoDB - https://www.mongodb.com/ 9 | 2. Oracle - https://www.oracle.com/database/ 10 | 11 | 5. Elasticsearch - https://www.elastic.co/products/elasticsearch (_Optional_) 12 | 6. Docker - https://www.docker.com/ (_Optional_) 13 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849234827_create_api_analytics_table.sql: -------------------------------------------------------------------------------- 1 | create table gapi_api_analytics 2 | ( 3 | total_requests number, 4 | max_elapsed_time number, 5 | avg_elapsed_time number(8), 6 | min_elapsed_time number, 7 | remote_addr_count CLOB, 8 | user_agent_count CLOB, 9 | status_code_count CLOB, 10 | service_name varchar2(255) NOT NULL, 11 | PRIMARY KEY (service_name) 12 | ) -------------------------------------------------------------------------------- /dashboard/src/store/modules/apps-groups/index.js: -------------------------------------------------------------------------------- 1 | import * as actions from "./actions"; 2 | import * as getters from "./getters"; 3 | import * as mutations from "./mutations"; 4 | 5 | const state = { 6 | groups: [], 7 | ungrouped_applications: [], 8 | possibleMatches: [] 9 | }; 10 | 11 | const namespaced = true; 12 | 13 | export default { 14 | namespaced, 15 | state, 16 | actions, 17 | getters, 18 | mutations 19 | }; 20 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849123807_create_services_hosts_table.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 4:54:05 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_SERVICES_HOSTS 3 | -- Generated 5/14/2019 4:54:05 PM from GPLATFORM@HSDEV 4 | 5 | CREATE TABLE gapi_services_hosts 6 | ( 7 | service_id VARCHAR2 (255), 8 | domain VARCHAR2 (255), 9 | CONSTRAINT fk_gapi_service_id FOREIGN KEY (service_id) REFERENCES gapi_services (id) 10 | ) -------------------------------------------------------------------------------- /api/utils/date.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "time" 4 | 5 | func CurrentDate() string { 6 | return time.Now().Format("2006-01-02") 7 | } 8 | 9 | func CurrentDateWithFormat(format string) string { 10 | return time.Now().Format(format) 11 | } 12 | 13 | func CurrentTimeMilliseconds() int64 { 14 | return time.Now().UnixNano() / int64(time.Millisecond) 15 | } 16 | func NanosecondsToMilliseconds(nano int64) int64 { 17 | return nano / int64(time.Millisecond) 18 | } 19 | -------------------------------------------------------------------------------- /api/routes/plugins.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/authentication" 5 | "github.com/Glintt/gAPI/api/controllers" 6 | 7 | "github.com/qiangxue/fasthttp-routing" 8 | ) 9 | 10 | func InitPluginsRoutes(router *routing.Router) { 11 | router.Get("/plugins", authentication.AdminRequiredMiddleware, controllers.ListPluginsAvailable) 12 | router.Get("/plugins/active", authentication.AdminRequiredMiddleware, controllers.ActivePlugins) 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/views/Analytics/Realtime.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | -------------------------------------------------------------------------------- /api/http/utils.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | routing "github.com/qiangxue/fasthttp-routing" 5 | "strconv" 6 | "errors" 7 | ) 8 | 9 | // ParsePageParam parses page query parameter 10 | func ParsePageParam(c *routing.Context) (int, error){ 11 | page := 1 12 | if c.QueryArgs().Has("page") { 13 | page, err := strconv.Atoi(string(c.QueryArgs().Peek("page"))) 14 | if err != nil { 15 | return page, errors.New("Invalid page provided") 16 | } 17 | } 18 | return page, nil 19 | } -------------------------------------------------------------------------------- /api/routes/api_documentation.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/controllers" 5 | 6 | routing "github.com/qiangxue/fasthttp-routing" 7 | ) 8 | 9 | func InitServiceDocumentationRoutes(router *routing.Router) { 10 | router.To("GET,POST,PUT,PATCH,DELETE", "/api_docs//documentation", controllers.HandleServiceDocumentationRequest) 11 | router.To("GET,POST,PUT,PATCH,DELETE", "/api_docs//*", controllers.HandleServiceDocumentationJSRequest) 12 | } 13 | -------------------------------------------------------------------------------- /api/routes/routes.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | routing "github.com/qiangxue/fasthttp-routing" 5 | ) 6 | 7 | func InitAPIRoutes(router *routing.Router) { 8 | InitServiceDocumentationRoutes(router) 9 | InitGApiRoutes(router) 10 | InitUsersService(router) 11 | InitAuthenticationAPI(router) 12 | InitServiceDiscoveryAPIRoutes(router) 13 | InitUserPermissionsService(router) 14 | InitAnalyticsAPI(router) 15 | InitAppsGroupsApi(router) 16 | InitPluginsRoutes(router) 17 | } 18 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849123677_create_services_apps_table.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 4:54:57 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_SERVICES_APPS_GROUPS 3 | -- Generated 5/14/2019 4:54:56 PM from GPLATFORM@HSDEV 4 | 5 | CREATE TABLE gapi_services_apps_groups 6 | ( 7 | id VARCHAR2 (255), 8 | name VARCHAR2 (255), 9 | 10 | CONSTRAINT unq_gapi_service_appgroup_id UNIQUE (id), 11 | CONSTRAINT unq_gapi_service_appgroup_name UNIQUE (name) 12 | ) -------------------------------------------------------------------------------- /dashboard/src/store/modules/users/index.js: -------------------------------------------------------------------------------- 1 | import * as actions from "./actions"; 2 | import * as getters from "./getters"; 3 | import * as mutations from "./mutations"; 4 | 5 | const state = { 6 | users: [], 7 | user: null, 8 | alert: { 9 | message: "", 10 | classType: "", 11 | showing: false 12 | } 13 | }; 14 | 15 | const namespaced = true; 16 | 17 | export default { 18 | namespaced, 19 | state, 20 | actions, 21 | getters, 22 | mutations 23 | }; 24 | -------------------------------------------------------------------------------- /dashboard/src/configs/permissions.js: -------------------------------------------------------------------------------- 1 | export const AdminPermissions = [ 2 | "ServiceDiscovery.CreateService", 3 | "ServiceDiscovery.DeleteService", 4 | "ServiceDiscovery.UpdateService", 5 | "ServiceDiscovery.ManageService" 6 | ]; 7 | 8 | export function HasPermission(type, user) { 9 | if (!user) return false; 10 | if (user.IsAdmin) { 11 | return true; 12 | } 13 | 14 | if (AdminPermissions.indexOf(type) !== -1) { 15 | return false; 16 | } 17 | 18 | return true; 19 | } 20 | -------------------------------------------------------------------------------- /api/routes/gapi.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/controllers" 5 | "github.com/Glintt/gAPI/api/authentication" 6 | "github.com/qiangxue/fasthttp-routing" 7 | ) 8 | 9 | func InitGApiRoutes(router *routing.Router) { 10 | 11 | router.Get("/reload", authentication.AdminRequiredMiddleware, controllers.ReloadServices) 12 | router.Get("/invalidate-cache", authentication.AdminRequiredMiddleware, controllers.InvalidateCache) 13 | router.Get("/profile-gapi", controllers.ProfileGApiUsage) 14 | } -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849123607_create_services_groups_table.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 4:53:18 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_SERVICES_GROUPS 3 | -- Generated 5/14/2019 4:53:18 PM from GPLATFORM@HSDEV 4 | 5 | CREATE TABLE gapi_services_groups 6 | ( 7 | id VARCHAR2 (255), 8 | name VARCHAR2 (255), 9 | isreachable NUMBER (1, 0) DEFAULT 0, 10 | CONSTRAINT unq_gapi_service_group_id UNIQUE (id), 11 | CONSTRAINT unq_gapi_service_group_name UNIQUE (name) 12 | ) -------------------------------------------------------------------------------- /api/plugins/constants.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | // Go plugin extension 4 | var PLUGIN_EXTENSION = ".so" 5 | 6 | // Plugins location 7 | var PLUGINS_LOCATION = "./custom_plugins" 8 | 9 | // Before request plugins 10 | var BEFORE_REQUEST_PLUGINS_NAME = "BeforeRequest" 11 | 12 | // Lookup for before request plugin 13 | var BeforeRequestEntryPluginLookup = "BeforeRequestEntryPlugin" 14 | 15 | var SERVICE_NAME = "/plugins" 16 | 17 | var PLUGINS_TYPES = []string{BEFORE_REQUEST_PLUGINS_NAME} 18 | 19 | const ( 20 | PLUGINS_COLLECTION = "plugins" 21 | ) 22 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/plugins/actions.js: -------------------------------------------------------------------------------- 1 | const api = require("@/api/plugins"); 2 | 3 | export const updatePlugins = ({ commit }) => { 4 | var pluginsPromise = new Promise(resolve => { 5 | api.all(response => { 6 | commit("plugins", response.body); 7 | resolve(); 8 | }); 9 | }); 10 | 11 | var activePromise = new Promise(resolve => { 12 | api.active(response => { 13 | commit("active", response.body); 14 | resolve(); 15 | }); 16 | }); 17 | 18 | Promise.all([pluginsPromise, activePromise]); 19 | }; 20 | -------------------------------------------------------------------------------- /api/swagger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gapi", 3 | "version": "1.0.0", 4 | "description": "No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)", 5 | "main": "index.js", 6 | "scripts": { 7 | "prestart": "npm install", 8 | "start": "node index.js" 9 | }, 10 | "keywords": [ 11 | "swagger" 12 | ], 13 | "license": "Unlicense", 14 | "private": true, 15 | "dependencies": { 16 | "connect": "^3.2.0", 17 | "js-yaml": "^3.3.0", 18 | "swagger-tools": "0.10.1" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /api/plugins/general_plugin.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "path/filepath" 5 | "plugin" 6 | ) 7 | 8 | type GeneralPlugin struct { 9 | Location string 10 | Filename string 11 | } 12 | 13 | func (p *GeneralPlugin) Load(lookup string) (plugin.Symbol, error) { 14 | mod := filepath.Join(p.Location, p.Filename+PLUGIN_EXTENSION) 15 | plug, err := plugin.Open(mod) 16 | 17 | if err != nil { 18 | return nil, err 19 | } 20 | 21 | symReqEntryPlugin, err := plug.Lookup(lookup) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | return symReqEntryPlugin, nil 27 | } 28 | -------------------------------------------------------------------------------- /dashboard/src/store/actions.js: -------------------------------------------------------------------------------- 1 | import * as api from "../api"; 2 | import * as types from "./mutation-types"; 3 | 4 | export const getAll = ({ commit }) => { 5 | api.listServices(services => { 6 | commit(types.RECEIVE_ALL, { 7 | services 8 | }); 9 | }); 10 | }; 11 | 12 | export const sendMessage = ({ commit }, payload) => { 13 | api.createMessage(payload, message => { 14 | commit(types.RECEIVE_MESSAGE, { 15 | message 16 | }); 17 | }); 18 | }; 19 | 20 | export const switchThread = ({ commit }, payload) => { 21 | commit(types.SWITCH_THREAD, payload); 22 | }; 23 | -------------------------------------------------------------------------------- /dashboard/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.2.0-alpine as dependencies 2 | 3 | ADD package.json /tmp/package.json 4 | RUN cd /tmp && yarn install 5 | 6 | FROM node:12.2.0-alpine 7 | WORKDIR /usr/src/app 8 | 9 | COPY --from=dependencies /tmp/node_modules ./node_modules 10 | 11 | ADD . /usr/src/app 12 | 13 | RUN npm run build 14 | RUN rm -rf ./build 15 | RUN rm -rf ./test 16 | RUN rm -rf ./src 17 | 18 | RUN mv dist/assets/gAPIlogo.PNG dist/assets/gAPIlogo.png 19 | RUN mv public/assets/gAPIlogo.PNG public/assets/gAPIlogo.png 20 | 21 | ENV PORT=80 22 | 23 | EXPOSE 80 24 | 25 | CMD [ "node", "index.js" ] 26 | -------------------------------------------------------------------------------- /api/oauth_clients/oauth_clients.go: -------------------------------------------------------------------------------- 1 | package oauth_clients 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | ) 6 | 7 | type OAuthClient struct { 8 | ClientId string 9 | ClientSecret string 10 | } 11 | 12 | const ( 13 | OAUTH_CLIENTS_COLLECTION = "gapi_oauth_clients" 14 | SERVICE_NAME = "gapi_oauth_clients" 15 | PAGE_LENGTH = 10 16 | ) 17 | 18 | func Find(clientId string, clientSecret string) OAuthClient { 19 | return OAuthClientsMethods[config.GApiConfiguration.ServiceDiscovery.Type]["find"].(func(string, string) OAuthClient)(clientId, clientSecret) 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gAPI 2 | 3 | 4 | gAPI allows to easily manage all your microservices by providing a simple and intuitive dashboard. 5 | 6 | It also provides analytics which are useful to take value from request logs. 7 | 8 | 9 | In order to access more documentation, go to [Github Wiki](https://github.com/Glintt/gAPIManagement/wiki) or access [here](https://glintt.github.io/gAPI/). 10 | 11 | ### Table of Contents 12 | 13 | 1. [Requirements](docs/requirements.md) 14 | 1. [Installation](docs/installation.md) 15 | 1. [Architecture](docs/architecture.md) 16 | 1. [Contributing](docs/contributing.md) 17 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849123509_create_users_table.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 5:23:56 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_USERS 3 | -- Generated 5/14/2019 5:23:55 PM from GPLATFORM@HSDEV 4 | 5 | CREATE TABLE gapi_users 6 | ( 7 | id VARCHAR2 (255), 8 | username VARCHAR2 (255), 9 | email VARCHAR2 (255), 10 | password VARCHAR2 (255), 11 | isadmin NUMBER (1, 0) DEFAULT 0, 12 | 13 | CONSTRAINT unq_gapi_user_id UNIQUE (id), 14 | CONSTRAINT unq_gapi_username UNIQUE (username), 15 | CONSTRAINT unq_gapi_email UNIQUE (email) 16 | ) 17 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/services-groups/mutations.js: -------------------------------------------------------------------------------- 1 | export const updateGroups = (state, obj) => { 2 | state.groups = obj; 3 | }; 4 | 5 | export const updateGroup = (state, obj) => { 6 | state.groups.forEach(element => { 7 | if (element.Id === obj.Id) { 8 | element = obj; 9 | } 10 | }); 11 | }; 12 | 13 | export const groupDeleted = (state, g) => { 14 | let newGroups = state.groups; 15 | console.log(newGroups); 16 | 17 | newGroups = newGroups.filter(obj => { 18 | return obj.Id !== g.Id; 19 | }); 20 | console.log(newGroups); 21 | 22 | state.groups = newGroups; 23 | }; 24 | -------------------------------------------------------------------------------- /api/oauth_clients/oauth_clients-mongo.go: -------------------------------------------------------------------------------- 1 | package oauth_clients 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/database" 5 | 6 | "gopkg.in/mgo.v2/bson" 7 | ) 8 | 9 | func FindOAuthClientMongo(clientId string, clientSecret string) OAuthClient { 10 | session, db := database.GetSessionAndDB(database.MONGO_DB) 11 | query := bson.M{"clientid": clientId, "clientsecret": clientSecret} 12 | 13 | oauthClient := OAuthClient{} 14 | 15 | err := db.C(OAUTH_CLIENTS_COLLECTION).Find(query).One(&oauthClient) 16 | if err != nil { 17 | return OAuthClient{} 18 | } 19 | 20 | database.MongoDBPool.Close(session) 21 | 22 | return oauthClient 23 | } 24 | -------------------------------------------------------------------------------- /dashboard/src/views/ServiceGroup/ServiceGroupList.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 19 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/user_permissions/actions.js: -------------------------------------------------------------------------------- 1 | const userPermissionsAPI = require("@/api/user_permissions"); 2 | 3 | export const get = ({ commit }, payload) => { 4 | userPermissionsAPI.get(payload, response => { 5 | commit("updatePermissions", response.body); 6 | }); 7 | }; 8 | 9 | export const update = ({ commit }, { newPermissions, user }) => { 10 | userPermissionsAPI.update(user, newPermissions, response => { 11 | if (response.status !== 201) { 12 | console.log("Update failed"); 13 | } else { 14 | commit("updatePermissions", newPermissions); 15 | console.log("Update success"); 16 | } 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /api/swagger/README.md: -------------------------------------------------------------------------------- 1 | # Swagger generated server 2 | 3 | ## Overview 4 | This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. 5 | 6 | ### Running the server 7 | To run the server, run: 8 | 9 | ``` 10 | npm start 11 | ``` 12 | 13 | To view the Swagger UI interface: 14 | 15 | ``` 16 | open http://localhost:8080/docs 17 | ``` 18 | 19 | This project leverages the mega-awesome [swagger-tools](https://github.com/apigee-127/swagger-tools) middleware which does most all the work. 20 | -------------------------------------------------------------------------------- /dashboard/src/api/plugins.js: -------------------------------------------------------------------------------- 1 | const HTTP = require("@/api/http"); 2 | 3 | const Endpoints = { 4 | all: "/plugins", 5 | active: "/plugins/active" 6 | }; 7 | 8 | export function all(cb) { 9 | return HTTP.GET(HTTP.PathToCall(Endpoints.all), {}).then( 10 | response => { 11 | cb(response); 12 | }, 13 | response => { 14 | HTTP.handleError(response, cb); 15 | } 16 | ); 17 | } 18 | 19 | export function active(cb) { 20 | return HTTP.GET(HTTP.PathToCall(Endpoints.active), {}).then( 21 | response => { 22 | cb(response); 23 | }, 24 | response => { 25 | HTTP.handleError(response, cb); 26 | } 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/users/mutations.js: -------------------------------------------------------------------------------- 1 | export const usersListUpdated = (state, obj) => { 2 | state.users = obj; 3 | }; 4 | 5 | export const changeUser = (state, user) => { 6 | state.user = user; 7 | }; 8 | 9 | export const updateUser = (state, user) => { 10 | state.user = user; 11 | }; 12 | 13 | export const closeAlert = state => { 14 | state.alert.message = ""; 15 | state.alert.classType = ""; 16 | state.alert.showing = false; 17 | }; 18 | 19 | export const newAlert = (state, alert) => { 20 | state.alert.message = alert.msg; 21 | state.alert.classType = alert.classType; 22 | state.alert.showing = true; 23 | }; 24 | -------------------------------------------------------------------------------- /api/config/constants.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | var CONFIGS_LOCATION = "./configs/" 4 | 5 | var SERVICE_DISCOVERY_CONFIG_FILE = "services.json" 6 | var AUTHENTICATION_CONFIG_FILE = "oauth.json" 7 | 8 | var POST = "POST" 9 | var GET = "GET" 10 | var DELETE = "DELETE" 11 | var PUT = "PUT" 12 | var PATCH = "PATCH" 13 | 14 | const ( 15 | GAPI_API_LOGS_INDEX = "gapi-api-logs" 16 | GAPI_SERVICE_NAME = "GAPI_SERVICES" 17 | ) 18 | 19 | var APPLICATION_JSON = "application/json" 20 | 21 | var SOCKET_PORT_DEFAULT = "5000" 22 | 23 | var MATCHING_URI_REGEX = "((/([\\w?\\-=:.&+#])*)*$)" 24 | 25 | func LoadConfigs() { 26 | LoadGApiConfig() 27 | LoadURLConstants() 28 | } 29 | -------------------------------------------------------------------------------- /api/notifications/slack.go: -------------------------------------------------------------------------------- 1 | package notifications 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/utils" 5 | "github.com/Glintt/gAPI/api/config" 6 | "bytes" 7 | "net/http" 8 | ) 9 | 10 | 11 | func SlackNotification(msg string){ 12 | defer utils.PreventCrash() 13 | 14 | json := []byte(`{"text":"` + msg + `"}`) 15 | 16 | webHookApi := config.GApiConfiguration.Notifications.Slack.WebhookUrl 17 | 18 | req, _ := http.NewRequest("POST", webHookApi, bytes.NewBuffer(json)) 19 | req.Header.Set("Content-Type", "application/json") 20 | 21 | client := &http.Client{} 22 | 23 | resp, _ := client.Do(req) 24 | 25 | defer resp.Body.Close() 26 | } -------------------------------------------------------------------------------- /api/users/models/user.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "golang.org/x/crypto/bcrypt" 5 | "gopkg.in/mgo.v2/bson" 6 | ) 7 | 8 | type User struct { 9 | Id bson.ObjectId `bson:"_id" json:"Id"` 10 | Username string 11 | Password string `json:",omitempty"` 12 | Email string 13 | IsAdmin bool 14 | } 15 | 16 | // GetInternalAPIUser Returns an internal user with admin permissions 17 | func GetInternalAPIUser() User { 18 | return User{ 19 | IsAdmin: true, 20 | } 21 | } 22 | 23 | // GeneratePassword encrypts password 24 | func GeneratePassword(password string) ([]byte, error) { 25 | return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) 26 | } 27 | -------------------------------------------------------------------------------- /docs/migrations.md: -------------------------------------------------------------------------------- 1 | # Database migrations 2 | 3 | gAPI database is based on migrations. 4 | Oracle migrations are stored inside folder _server/migrations/oracle_. 5 | 6 | ## How it works 7 | 8 | There is a migration table which stores all migrations already run. 9 | When the server starts, all new migrations are run and the table updated. 10 | 11 | ## Enable/Disable 12 | 13 | Database migrations can be enabled/disabled by adding an environment variable: **RUN_MIGRATIONS** 14 | 15 | ## Migration naming convention 16 | 17 | ``` 18 | _.sql 19 | ``` 20 | 21 | Example: 22 | 23 | ``` 24 | 1557849123509_create_users_table.sql 25 | ``` 26 | -------------------------------------------------------------------------------- /api/routes/analytics.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/authentication" 5 | "github.com/Glintt/gAPI/api/config" 6 | "github.com/Glintt/gAPI/api/controllers" 7 | 8 | routing "github.com/qiangxue/fasthttp-routing" 9 | ) 10 | 11 | func InitAnalyticsAPI(router *routing.Router) { 12 | analyticsAPI := router.Group(config.ANALYTICS_GROUP) 13 | 14 | analyticsAPI.Get("/applications", authentication.AdminRequiredMiddleware, controllers.ApplicationGroupAnalytics) 15 | analyticsAPI.Get("/api", authentication.AdminRequiredMiddleware, controllers.APIAnalytics) 16 | analyticsAPI.Get("/logs", authentication.AdminRequiredMiddleware, controllers.Logs) 17 | } 18 | -------------------------------------------------------------------------------- /api/servicediscovery/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | "regexp" 6 | "strings" 7 | ) 8 | 9 | func GetMatchURI(uri string) string { 10 | f := func(c rune) bool { 11 | return c == '/' 12 | } 13 | 14 | uriParts := strings.FieldsFunc(uri, f) 15 | 16 | toMatchUri := "/" + strings.Join(uriParts, "/") + "/" 17 | 18 | return toMatchUri 19 | } 20 | 21 | func GetMatchingURIRegex(uri string) string { 22 | s := uri 23 | re := regexp.MustCompile("^(\\^/)?/?") 24 | s = re.ReplaceAllString(s, "^/") 25 | re = regexp.MustCompile("(/(\\.\\*)?)?$") 26 | s = re.ReplaceAllString(s, config.GApiConfiguration.MatchingUriRegex) 27 | return s 28 | } 29 | -------------------------------------------------------------------------------- /api/swagger/service/AuthenticationService.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * Check if token is valid 6 | * 7 | * 8 | * authorization String Authorization token 9 | * no response value expected for this operation 10 | **/ 11 | exports.oauthAuthorizeGET = function(authorization) { 12 | return new Promise(function(resolve, reject) { 13 | resolve(); 14 | }); 15 | } 16 | 17 | 18 | /** 19 | * Request OAuth token to access protected gAPI endpoints 20 | * 21 | * 22 | * body User User information 23 | * no response value expected for this operation 24 | **/ 25 | exports.oauthTokenPOST = function(body) { 26 | return new Promise(function(resolve, reject) { 27 | resolve(); 28 | }); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/services-groups/actions.js: -------------------------------------------------------------------------------- 1 | const serviceDiscoveryAPI = require("@/api/service-discovery"); 2 | 3 | export const fetchGroups = ({ commit }) => { 4 | serviceDiscoveryAPI.listServiceGroups(response => { 5 | commit("updateGroups", response.body); 6 | }); 7 | }; 8 | 9 | export const updateGroup = ({ commit }, group) => { 10 | serviceDiscoveryAPI.updateServiceGroup(group, response => { 11 | commit("updateGroup", response.body); 12 | }); 13 | }; 14 | 15 | export const deleteGroup = ({ commit }, group) => { 16 | serviceDiscoveryAPI.deleteServiceGroup(group.Id, response => { 17 | if (response.status === 200) commit("groupDeleted", group); 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /dashboard/src/api/user_permissions.js: -------------------------------------------------------------------------------- 1 | const HTTP = require("@/api/http"); 2 | 3 | export function get(user, cb) { 4 | return HTTP.GET( 5 | HTTP.PathToCall(`/user-permissions/${user.Username}`), 6 | {} 7 | ).then( 8 | response => { 9 | cb(response); 10 | }, 11 | response => { 12 | HTTP.handleError(response, cb); 13 | } 14 | ); 15 | } 16 | 17 | export function update(user, newPermissions, cb) { 18 | return HTTP.PUT( 19 | HTTP.PathToCall(`/user-permissions/${user.Username}`), 20 | newPermissions, 21 | {} 22 | ).then( 23 | response => { 24 | cb(response); 25 | }, 26 | response => { 27 | HTTP.handleError(response, cb); 28 | } 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /docs/plugins_examples/BeforeRequestPlugin.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/Glintt/gAPI/api/utils" 7 | routing "github.com/qiangxue/fasthttp-routing" 8 | ) 9 | 10 | type beforeRequestEntryPlugin string 11 | 12 | func (g beforeRequestEntryPlugin) Call(c *routing.Context) error { 13 | utils.LogMessage(err.Error(), utils.DebugLogType) 14 | 15 | c.Response.SetBody([]byte(`{"error":true, "msg": "Not authorized to access resource."}`)) 16 | c.Response.SetStatusCode(405) 17 | c.Response.Header.SetContentType("application/json") 18 | c.Abort() 19 | 20 | return errors.New("Return an error which will stop the request") 21 | } 22 | 23 | var BeforeRequestEntryPlugin beforeRequestEntryPlugin 24 | -------------------------------------------------------------------------------- /api/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | go get "github.com/patrickmn/go-cache" 3 | go get "github.com/allegro/bigcache" 4 | go get "github.com/valyala/fasthttp" 5 | go get "github.com/qiangxue/fasthttp-routing" 6 | go get "github.com/streadway/amqp" 7 | go get "gopkg.in/mgo.v2" 8 | go get "github.com/dgrijalva/jwt-go" 9 | go get "github.com/rs/cors" 10 | go get "github.com/ulule/limiter" 11 | go get "golang.org/x/crypto/bcrypt" 12 | go get "github.com/go-ldap/ldap" 13 | go get "github.com/shirou/w32" 14 | go get "github.com/StackExchange/wmi" 15 | go get "github.com/shirou/gopsutil" 16 | go get "github.com/fatih/structs" 17 | go get "github.com/manucorporat/try" 18 | go get "gopkg.in/goracle.v2" 19 | 20 | go get "github.com/graarh/golang-socketio" -------------------------------------------------------------------------------- /nginx/sites-enabled/gapi-api: -------------------------------------------------------------------------------- 1 | 2 | worker_processes 4; 3 | 4 | events { worker_connections 1048; } 5 | 6 | http { 7 | sendfile on; 8 | 9 | upstream app_servers { 10 | server backend:8000; 11 | } 12 | 13 | server { 14 | listen 80; 15 | server_name localhost 16 | 17 | location / { 18 | proxy_pass http://app_servers; 19 | proxy_redirect off; 20 | proxy_set_header Host $host; 21 | proxy_set_header X-Real-IP $remote_addr; 22 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 23 | proxy_set_header X-Forwarded-Host $server_name; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /api/api-analytics/api-analytics.go: -------------------------------------------------------------------------------- 1 | package apianalytics 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/api-analytics/providers" 5 | ) 6 | 7 | const SERVICE_NAME = "api_analytics" 8 | 9 | const ( 10 | LogElasticType = "Elastic" 11 | LogOracleType = "Oracle" 12 | LogRabbitQueueType = "Rabbit" 13 | ) 14 | 15 | var AnalyticsMethods = map[string]map[string]interface{}{ 16 | "Elastic": { 17 | "logs": providers.LogsElastic, 18 | "analytics": providers.APIAnalyticsElastic, 19 | "app_analytics": providers.ApplicationAnalyticsElastic, 20 | }, 21 | 22 | "Oracle": { 23 | "logs": providers.LogsOracle, 24 | "analytics": providers.APIAnalyticsOracle, 25 | "app_analytics": providers.ApplicationAnalyticsOracle, 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/apps-groups/mutations.js: -------------------------------------------------------------------------------- 1 | export const updateGroups = (state, obj) => { 2 | state.groups = obj; 3 | }; 4 | 5 | export const updateGroup = (state, obj) => { 6 | state.groups.forEach(element => { 7 | if (element.Id === obj.Id) { 8 | element = obj; 9 | } 10 | }); 11 | }; 12 | 13 | export const groupDeleted = (state, g) => { 14 | let newGroups = state.groups; 15 | 16 | newGroups = newGroups.filter(obj => { 17 | return obj.Id !== g.Id; 18 | }); 19 | 20 | state.groups = newGroups; 21 | }; 22 | 23 | export const ungroupedApplications = (state, g) => { 24 | state.ungrouped_applications = g; 25 | }; 26 | 27 | export const possibleMatches = (state, g) => { 28 | state.possibleMatches = g; 29 | }; 30 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # gAPIManagement 2 | 3 | gAPIManagement allows to easily manage all your microservices by providing a simple and intuitive dashboard. 4 | 5 | It also provides analytics which are useful to take value from request logs. 6 | 7 | ### Table of Contents 8 | 9 | 1. [Requirements](requirements) 10 | 1. [Installation](installation) 11 | 1. [HTTPS](https) 12 | 1. [Architecture](architecture) 13 | 1. [Load Balancing](load-balancing) 14 | 1. [Rate Limiting](rate-limiting) 15 | 1. [Services](services) 16 | 1. [Service groups](groups) 17 | 1. [Reachability](reachability) 18 | 1. [Healthcheck](healthcheck) 19 | 1. [Service Management](service-management) 20 | 1. [Database migrations](migrations) 21 | 1. [Plugins](plugins) 22 | 1. [Contributing](contributing) 23 | -------------------------------------------------------------------------------- /api/logs/models/requestlogging.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "encoding/json" 4 | 5 | type RequestLogging struct { 6 | Id string 7 | Method string 8 | Uri string 9 | RequestBody string 10 | Host string 11 | UserAgent string 12 | RemoteAddr string 13 | RemoteIp string 14 | Headers string 15 | QueryArgs string 16 | DateTime string 17 | Response string 18 | ElapsedTime int64 19 | StatusCode int 20 | ServiceName string 21 | IndexName string 22 | JWTContent string 23 | } 24 | 25 | func (r *RequestLogging) GetOtherInfo() string { 26 | var info = make(map[string]string) 27 | 28 | info["jwt_content"] = r.JWTContent 29 | i, err := json.Marshal(info) 30 | if err != nil { 31 | return "{}" 32 | } 33 | return string(i) 34 | } 35 | -------------------------------------------------------------------------------- /docs/reachability.md: -------------------------------------------------------------------------------- 1 | # Reachability 2 | 3 | gAPI enables services to be reachable or not reachable from external services. 4 | 5 | When a service is not reachable, only other services can communicate with it. 6 | 7 | ## Services Layers 8 | 9 | In order to facilitate the management of reachability, there is the option to create layers. 10 | 11 | With these layers, all services inside the layer will share the same state in terms of reachability. 12 | 13 | ## Configuration 14 | 15 | Each service contains a field called _IsReachable_ which indicates if the service is reachable from external services or not. 16 | 17 | In order to make the service reachable, this field must be TRUE. 18 | 19 | ## Flow 20 | 21 | ![Reachability flow](./imgs/reachability_flow.png "Reachability flow") 22 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849124807_create_request_logs_table.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 4:54:05 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_SERVICES_HOSTS 3 | -- Generated 5/14/2019 4:54:05 PM from GPLATFORM@HSDEV 4 | CREATE TABLE gapi_request_logs 5 | ( 6 | id varchar2(255) primary key, 7 | method VARCHAR2(30), 8 | uri VARCHAR2(255), 9 | request_body CLOB, 10 | host VARCHAR2(255), 11 | user_agent VARCHAR2(255), 12 | remote_addr VARCHAR2(255), 13 | remote_ip VARCHAR2(120), 14 | headers CLOB, 15 | query_args CLOB, 16 | date_time timestamp, 17 | response CLOB, 18 | elapsed_time number, 19 | status_code number, 20 | service_name VARCHAR2(255), 21 | index_name VARCHAR2(200), 22 | request_grouper_date timestamp 23 | ) -------------------------------------------------------------------------------- /api/swagger/service/AnalyticsService.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * Get API related analytics 6 | * 7 | * 8 | * authorization String Authorization token 9 | * endpoint String API matching uri/endpoint 10 | * no response value expected for this operation 11 | **/ 12 | exports.analyticsApiGET = function(authorization,endpoint) { 13 | return new Promise(function(resolve, reject) { 14 | resolve(); 15 | }); 16 | } 17 | 18 | 19 | /** 20 | * Get API related analytics 21 | * 22 | * 23 | * authorization String Authorization token 24 | * endpoint String API matching uri/endpoint 25 | * no response value expected for this operation 26 | **/ 27 | exports.analyticsLogsGET = function(authorization,endpoint) { 28 | return new Promise(function(resolve, reject) { 29 | resolve(); 30 | }); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /api/authentication/ldap.go: -------------------------------------------------------------------------------- 1 | package authentication 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | "github.com/Glintt/gAPI/api/utils" 6 | "github.com/go-ldap/ldap" 7 | ) 8 | 9 | var LDAP_PORT = "389" 10 | 11 | func AuthenticateWithLDAP(email string, password string) bool{ 12 | port := LDAP_PORT 13 | if config.GApiConfiguration.Authentication.LDAP.Port != "" { 14 | port = config.GApiConfiguration.Authentication.LDAP.Port 15 | } 16 | 17 | l, err := ldap.Dial("tcp", config.GApiConfiguration.Authentication.LDAP.Domain + ":" + port) 18 | if err != nil { 19 | utils.LogMessage("LDAP Error: " + err.Error(), utils.ErrorLogType) 20 | } 21 | err = l.Bind(email, password) 22 | if err != nil { 23 | utils.LogMessage("LDAP Credentials Error: " + err.Error(), utils.DebugLogType) 24 | return false 25 | } 26 | return true 27 | } -------------------------------------------------------------------------------- /api/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sh install.sh 3 | mkdir -p bin/ 4 | cd bin/ 5 | 6 | 7 | platforms=("windows/amd64" "windows/386" "darwin/amd64") 8 | 9 | for platform in "${platforms[@]}" 10 | do 11 | platform_split=(${platform//\// }) 12 | GOOS=${platform_split[0]} 13 | GOARCH=${platform_split[1]} 14 | output_name_server='api-'$GOOS'-'$GOARCH 15 | output_name_listener='api-listener-'$GOOS'-'$GOARCH 16 | if [ $GOOS = "windows" ]; then 17 | output_name+='.exe' 18 | fi 19 | 20 | env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name_server ../server.go 21 | env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name_listener ../rabbit-listener.go 22 | 23 | if [ $? -ne 0 ]; then 24 | echo 'An error has occurred! Aborting the script execution...' 25 | exit 1 26 | fi 27 | done 28 | cd .. 29 | 30 | -------------------------------------------------------------------------------- /api/servicediscovery/service/service-repository.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/database" 5 | userModels "github.com/Glintt/gAPI/api/users/models" 6 | ) 7 | 8 | type ServiceRepositoryInterface interface { 9 | Update(service Service, serviceExists Service) (int, error) 10 | CreateService(s Service) (Service, error) 11 | ListServices(page int, filterQuery string) []Service 12 | DeleteService(s Service) error 13 | Find(s Service) (Service, error) 14 | ListAllAvailableHosts() ([]string, error) 15 | NormalizeServices() error 16 | } 17 | 18 | func GetServicesRepository(user userModels.User) ServiceRepositoryInterface { 19 | if database.SD_TYPE == "mongo" { 20 | return &ServiceMongoRepository{ 21 | User: user, 22 | } 23 | } 24 | if database.SD_TYPE == "oracle" { 25 | return &ServiceOracleRepository{ 26 | User: user, 27 | } 28 | } 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /dashboard/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 34 | -------------------------------------------------------------------------------- /dashboard/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | API Management Dashboard 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /api/database/oracle.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "database/sql" 5 | "github.com/Glintt/gAPI/api/utils" 6 | 7 | _ "gopkg.in/goracle.v2" 8 | ) 9 | 10 | var dbConnection *sql.DB 11 | 12 | func ConnectToOracle(connectionString string) (*sql.DB, error) { 13 | var err error 14 | 15 | if dbConnection != nil { 16 | dbConnection.Ping() 17 | return dbConnection, err 18 | } 19 | dbConnection, err = sql.Open("goracle", connectionString) 20 | 21 | if err != nil { 22 | return nil, err 23 | } 24 | 25 | if err != nil { 26 | utils.LogMessage("error connecting to oracle on "+connectionString+". Err: "+err.Error(), utils.ErrorLogType) 27 | } else { 28 | utils.LogMessage("connected to oracle on "+connectionString, utils.InfoLogType) 29 | } 30 | 31 | return dbConnection, err 32 | } 33 | 34 | func CloseOracleConnection(dbConnection *sql.DB) error { 35 | //defer dbConnection.Close() 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /docs/groups.md: -------------------------------------------------------------------------------- 1 | ## Groups 2 | 3 | gAPI allows to associate APIs to an application group. 4 | 5 | These groups don't have any logic associated, they exists simply to better organize your APIs. 6 | 7 | #### Create a group 8 | 9 | 1. Open the dashboard 10 | 2. Navbar button "Apps" 11 | 3. Create Application 12 | 4. Fill in the form and save 13 | 14 | #### Associate API with Application Group 15 | 16 | 1. Open the dashboard 17 | 2. Open API information 18 | 3. API configuration section 19 | 4. From "Associated Application Group", select the group you want to associate the API to 20 | 5. Associate button 21 | 22 | #### Database table 23 | 24 | When using relational database, the table where groups are stored is: **_gapi_services_groups_**. This table contains a name, an identifier and a reachable status. 25 | 26 | Each service contains a column/attribute which is a foreign key to the group's identifier. 27 | -------------------------------------------------------------------------------- /api/swagger/controllers/Authentication.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('../utils/writer.js'); 4 | var Authentication = require('../service/AuthenticationService'); 5 | 6 | module.exports.oauthAuthorizeGET = function oauthAuthorizeGET (req, res, next) { 7 | var authorization = req.swagger.params['Authorization'].value; 8 | Authentication.oauthAuthorizeGET(authorization) 9 | .then(function (response) { 10 | utils.writeJson(res, response); 11 | }) 12 | .catch(function (response) { 13 | utils.writeJson(res, response); 14 | }); 15 | }; 16 | 17 | module.exports.oauthTokenPOST = function oauthTokenPOST (req, res, next) { 18 | var body = req.swagger.params['body'].value; 19 | Authentication.oauthTokenPOST(body) 20 | .then(function (response) { 21 | utils.writeJson(res, response); 22 | }) 23 | .catch(function (response) { 24 | utils.writeJson(res, response); 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /dashboard/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 34 | 35 | 50 | -------------------------------------------------------------------------------- /api/plugins/plugins.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "strings" 7 | ) 8 | 9 | func ListAll() (map[string][]string, error) { 10 | var filesMap map[string][]string 11 | filesMap = make(map[string][]string) 12 | 13 | configuration := Configurations() 14 | 15 | for _, pluginType := range PLUGINS_TYPES { 16 | var filesList []string 17 | typeLocation := configuration.Location + string(filepath.Separator) + pluginType 18 | 19 | filepath.Walk(typeLocation, func(path string, info os.FileInfo, err error) error { 20 | if err != nil { 21 | return err 22 | } 23 | if info.IsDir() { 24 | return nil 25 | } 26 | if filepath.Ext(info.Name()) != PLUGIN_EXTENSION { 27 | return nil 28 | } 29 | 30 | filesList = append(filesList, strings.Replace(info.Name(), ".so", "", -1)) 31 | return nil 32 | }) 33 | 34 | filesMap[pluginType] = filesList 35 | } 36 | 37 | return filesMap, nil 38 | } 39 | -------------------------------------------------------------------------------- /api/user_permission/providers/provider.go: -------------------------------------------------------------------------------- 1 | package providers 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/database" 5 | "github.com/Glintt/gAPI/api/user_permission/models" 6 | ) 7 | 8 | type PermissionsRepositoryInterface interface{ 9 | Get(userId string) ([]models.UserPermission, error) 10 | Add(userPermission models.UserPermission) error 11 | Update(userId string, userPermission []models.UserPermission) error 12 | Delete(userId string, serviceId string) error 13 | DeleteAll(userId string) error 14 | CreateTransaction() error 15 | CommitTransaction() error 16 | RollbackTransaction() error 17 | } 18 | 19 | func GetPermissionRepository() PermissionsRepositoryInterface { 20 | // if constants.SD_TYPE == "mongo" { 21 | // return &ServiceMongoRepository{ 22 | // User: user, 23 | // } 24 | // } 25 | if database.SD_TYPE == "oracle" { 26 | repos := &PermissionsOracleRepository{} 27 | repos.Init() 28 | return repos 29 | } 30 | return nil 31 | } -------------------------------------------------------------------------------- /api/routes/user_permission.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/controllers" 5 | "github.com/Glintt/gAPI/api/authentication" 6 | "github.com/Glintt/gAPI/api/config" 7 | "github.com/qiangxue/fasthttp-routing" 8 | ) 9 | 10 | 11 | 12 | func InitUserPermissionsService(router *routing.Router) { 13 | userPermissionsGroup := router.Group(config.USER_PERMISSIONS_GROUP) 14 | 15 | userPermissionsGroup.Get("/", authentication.AdminRequiredMiddleware, controllers.GetUserPermissionsHandler) 16 | userPermissionsGroup.Put("/", authentication.AdminRequiredMiddleware, controllers.UpdateUserPermissionHandler) 17 | userPermissionsGroup.Post("//", authentication.AdminRequiredMiddleware, controllers.AddPermissionToApplicationGroupHandler) 18 | userPermissionsGroup.Delete("//", authentication.AdminRequiredMiddleware, controllers.RemovePermissionFromApplicationGroupHandler) 19 | } -------------------------------------------------------------------------------- /api/rabbit/rabbit.go: -------------------------------------------------------------------------------- 1 | package rabbit 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/utils" 5 | "os" 6 | ) 7 | 8 | var WorkerPool chan []byte 9 | 10 | func User() string{ 11 | return os.Getenv("RABBITMQ_USER") 12 | } 13 | 14 | func Pwd() string{ 15 | return os.Getenv("RABBITMQ_PASSWORD") 16 | } 17 | 18 | func Host() string{ 19 | return os.Getenv("RABBITMQ_HOST") 20 | } 21 | 22 | func Port() string{ 23 | return os.Getenv("RABBITMQ_PORT") 24 | } 25 | 26 | func Queue() string{ 27 | return os.Getenv("RABBITMQ_QUEUE") 28 | } 29 | 30 | func FailOnError(err error, msg string) error { 31 | if err != nil { 32 | utils.LogMessage(msg + ": " + err.Error(), utils.ErrorLogType) 33 | } 34 | return err 35 | } 36 | 37 | func InitPublishers(workers int) { 38 | WorkerPool = make(chan []byte) 39 | for i:=0; i < workers; i++ { 40 | go StartPublisherWorker() 41 | } 42 | } 43 | 44 | func PublishToRabbitMQ(log []byte){ 45 | WorkerPool <- log 46 | } -------------------------------------------------------------------------------- /api/routes/apps-groups.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/controllers" 5 | routing "github.com/qiangxue/fasthttp-routing" 6 | ) 7 | 8 | func InitAppsGroupsApi(router *routing.Router) { 9 | router.Get("/apps-groups", controllers.GetAppGroups) 10 | router.Post("/apps-groups", controllers.CreateAppGroup) 11 | router.Get("/apps-groups/matches", controllers.AppGroupsMatches) 12 | router.Get("/apps-groups/ungrouped", controllers.UngroupedApps) 13 | router.Get("/apps-groups/search/", controllers.FindAppGroupForService) 14 | router.Put("/apps-groups/", controllers.UpdateAppGroup) 15 | router.Get("/apps-groups/", controllers.GetAppGroupByID) 16 | router.Delete("/apps-groups/", controllers.DeleteAppGroup) 17 | router.Post("/apps-groups//", controllers.AssociateServiceToAppGroup) 18 | router.Delete("/apps-groups//", controllers.DeassociateServiceFromApplicationGroup) 19 | } 20 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | I'm glad you're reading this as we need volunteer developers to help improve this project. 4 | 5 | #### Did you find a bug? 6 | 7 | - **Do not open up a GitHub issue if the bug is a security issue** 8 | - **Make sure the bug was not already reported** by searching on GitHub under issues. 9 | - **Be sure to include a title and description on the new issue**. The title and description must contain as much relevant information as possible , a code sample and a test case demonstrating the expected that is not happening. 10 | 11 | #### Did you implement new features or changed already existing one? 12 | 13 | - Send a [GitHub Pull Request to gAPI](https://github.com/Glintt/gAPI/compare) with a clear list of all features you've done. 14 | - Make sure all your commits are atomic (one feature per commit). 15 | - Always write a clear log message for your commits. One-line message is fine for small changes. For bigger changes, you should add a more detailed message. 16 | -------------------------------------------------------------------------------- /api/swagger/service/AdminService.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | /** 5 | * Clear cache 6 | * 7 | * 8 | * authorization String Authorization token 9 | * no response value expected for this operation 10 | **/ 11 | exports.invalidate_cacheGET = function(authorization) { 12 | return new Promise(function(resolve, reject) { 13 | resolve(); 14 | }); 15 | } 16 | 17 | 18 | /** 19 | * Reload gAPI configuration without restart process 20 | * 21 | * 22 | * authorization String Authorization token 23 | * no response value expected for this operation 24 | **/ 25 | exports.reloadGET = function(authorization) { 26 | return new Promise(function(resolve, reject) { 27 | resolve(); 28 | }); 29 | } 30 | 31 | 32 | /** 33 | * Normalize services 34 | * 35 | * 36 | * authorization String Authorization token 37 | * no response value expected for this operation 38 | **/ 39 | exports.service_discoveryAdminNormalizePOST = function(authorization) { 40 | return new Promise(function(resolve, reject) { 41 | resolve(); 42 | }); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | # How to Contribute 3 | 4 | I'm glad you're reading this as we need volunteer developers to help improve this project. 5 | 6 | #### Did you find a bug? 7 | 8 | * **Do not open up a GitHub issue if the bug is a security issue** 9 | * **Make sure the bug was not already reported** by searching on GitHub under issues. 10 | * **Be sure to include a title and description on the new issue**. The title and description must contain as much relevant information as possible , a code sample and a test case demonstrating the expected that is not happening. 11 | 12 | #### Did you implement new features or changed already existing one? 13 | 14 | Please send a [GitHub Pull Request to gAPIManagement](https://github.com/Glintt/gAPIManagement/compare) with a clear list of all features you've done. 15 | Make sure all your commits are atomic (one feature per commit). 16 | 17 | Always write a clear log message for your commits. One-line message is fine for small changes. For bigger changes, you should add a more detailed message. 18 | 19 | -------------------------------------------------------------------------------- /api/swagger/controllers/Analytics.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('../utils/writer.js'); 4 | var Analytics = require('../service/AnalyticsService'); 5 | 6 | module.exports.analyticsApiGET = function analyticsApiGET (req, res, next) { 7 | var authorization = req.swagger.params['Authorization'].value; 8 | var endpoint = req.swagger.params['endpoint'].value; 9 | Analytics.analyticsApiGET(authorization,endpoint) 10 | .then(function (response) { 11 | utils.writeJson(res, response); 12 | }) 13 | .catch(function (response) { 14 | utils.writeJson(res, response); 15 | }); 16 | }; 17 | 18 | module.exports.analyticsLogsGET = function analyticsLogsGET (req, res, next) { 19 | var authorization = req.swagger.params['Authorization'].value; 20 | var endpoint = req.swagger.params['endpoint'].value; 21 | Analytics.analyticsLogsGET(authorization,endpoint) 22 | .then(function (response) { 23 | utils.writeJson(res, response); 24 | }) 25 | .catch(function (response) { 26 | utils.writeJson(res, response); 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /api/sockets/requestscounter.go: -------------------------------------------------------------------------------- 1 | package sockets 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/utils" 5 | 6 | //"encoding/json" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | var RequestsCount = 0 12 | 13 | func IncrementRequestCounter() { 14 | RequestsCount = RequestsCount + 1 15 | } 16 | func ResetCounter() { 17 | RequestsCount = 0 18 | } 19 | 20 | func PropagateToSockets() { 21 | for _, element := range SocketsConnected { 22 | element.Emit("logs", string(strconv.Itoa(RequestsCount))) 23 | } 24 | 25 | ResetCounter() 26 | } 27 | 28 | func StartRequestsCounterSender() { 29 | PreventCrash() 30 | 31 | var ticker = time.NewTicker(1 * time.Second) 32 | quit := make(chan struct{}) 33 | go func() { 34 | for { 35 | select { 36 | case <-ticker.C: 37 | PropagateToSockets() 38 | case <-quit: 39 | ticker.Stop() 40 | return 41 | } 42 | } 43 | }() 44 | } 45 | 46 | func PreventCrash() { 47 | if r := recover(); r != nil { 48 | utils.LogMessage("recover request counter", utils.DebugLogType) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /dashboard/src/api/analytics.js: -------------------------------------------------------------------------------- 1 | const HTTP = require("@/api/http"); 2 | 3 | const APIConfig = require("@/configs/urls").config.API; 4 | const AnalyticsBaseURL = APIConfig.ANALYTICS_BASEPATH; 5 | 6 | export function byApi(api, cb) { 7 | return HTTP.GET(HTTP.PathToCall(AnalyticsBaseURL + "/api"), { 8 | params: api 9 | }).then( 10 | response => { 11 | cb(response); 12 | }, 13 | response => { 14 | HTTP.handleError(response, cb); 15 | } 16 | ); 17 | } 18 | 19 | export function byApplication(app_id, cb) { 20 | return HTTP.GET(HTTP.PathToCall(AnalyticsBaseURL + "/applications"), { 21 | params: app_id 22 | }).then( 23 | response => { 24 | cb(response); 25 | }, 26 | response => { 27 | HTTP.handleError(response, cb); 28 | } 29 | ); 30 | } 31 | 32 | export function logs(api, cb) { 33 | return HTTP.GET(HTTP.PathToCall(AnalyticsBaseURL + "/logs"), { 34 | params: api 35 | }).then( 36 | response => { 37 | cb(response); 38 | }, 39 | response => { 40 | HTTP.handleError(response, cb); 41 | } 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /api/swagger/utils/writer.js: -------------------------------------------------------------------------------- 1 | var ResponsePayload = function(code, payload) { 2 | this.code = code; 3 | this.payload = payload; 4 | } 5 | 6 | exports.respondWithCode = function(code, payload) { 7 | return new ResponsePayload(code, payload); 8 | } 9 | 10 | var writeJson = exports.writeJson = function(response, arg1, arg2) { 11 | var code; 12 | var payload; 13 | 14 | if(arg1 && arg1 instanceof ResponsePayload) { 15 | writeJson(response, arg1.payload, arg1.code); 16 | return; 17 | } 18 | 19 | if(arg2 && Number.isInteger(arg2)) { 20 | code = arg2; 21 | } 22 | else { 23 | if(arg1 && Number.isInteger(arg1)) { 24 | code = arg1; 25 | } 26 | } 27 | if(code && arg1) { 28 | payload = arg1; 29 | } 30 | else if(arg1) { 31 | payload = arg1; 32 | } 33 | 34 | if(!code) { 35 | // if no response code given, we default to 200 36 | code = 200; 37 | } 38 | if(typeof payload === 'object') { 39 | payload = JSON.stringify(payload, null, 2); 40 | } 41 | response.writeHead(code, {'Content-Type': 'application/json'}); 42 | response.end(payload); 43 | } 44 | -------------------------------------------------------------------------------- /api/database/database.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | "github.com/Glintt/gAPI/api/database/migrations" 6 | "os" 7 | ) 8 | 9 | var MONGO_HOST string 10 | var MONGO_DB string 11 | var MONGO_PORT string 12 | 13 | var SD_TYPE = "file" 14 | 15 | var ORACLE_CONNECTION_STRING string 16 | 17 | var IsConnectionDone = false 18 | 19 | func InitDatabaseConnection() error { 20 | MONGO_HOST = os.Getenv("MONGO_HOST") 21 | MONGO_DB = os.Getenv("MONGO_DB") 22 | MONGO_PORT = os.Getenv("MONGO_PORT") 23 | ORACLE_CONNECTION_STRING = os.Getenv("ORACLE_CONNECTION_STRING") 24 | 25 | if MONGO_PORT != "" { 26 | MONGO_HOST = MONGO_HOST + ":" + MONGO_PORT 27 | } 28 | 29 | IsConnectionDone = true 30 | 31 | if config.GApiConfiguration.ServiceDiscovery.Type == "mongo" { 32 | err := ConnectToMongo(MONGO_HOST) 33 | 34 | if err != nil { 35 | IsConnectionDone = false 36 | } 37 | return err 38 | } 39 | 40 | if config.GApiConfiguration.ServiceDiscovery.Type == "oracle" { 41 | migrations.MigrateOracle(ORACLE_CONNECTION_STRING) 42 | } 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /api/swagger/.swagger-codegen-ignore: -------------------------------------------------------------------------------- 1 | # Swagger Codegen Ignore 2 | # Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen 3 | 4 | # Use this file to prevent files from being overwritten by the generator. 5 | # The patterns follow closely to .gitignore or .dockerignore. 6 | 7 | # As an example, the C# client generator defines ApiClient.cs. 8 | # You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: 9 | #ApiClient.cs 10 | 11 | # You can match any string of characters against a directory, file or extension with a single asterisk (*): 12 | #foo/*/qux 13 | # The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux 14 | 15 | # You can recursively match patterns against a directory, file or extension with a double asterisk (**): 16 | #foo/**/qux 17 | # This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux 18 | 19 | # You can also negate patterns with an exclamation (!). 20 | # For example, you can ignore all files in a docs folder with the file extension .md: 21 | #docs/*.md 22 | # Then explicitly reverse the ignore rule for a single file: 23 | #!docs/README.md 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Glintt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /api/routes/users.go: -------------------------------------------------------------------------------- 1 | package routes 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/users" 5 | "github.com/Glintt/gAPI/api/controllers" 6 | "github.com/Glintt/gAPI/api/authentication" 7 | "github.com/Glintt/gAPI/api/config" 8 | "github.com/qiangxue/fasthttp-routing" 9 | ) 10 | 11 | 12 | 13 | func InitUsersService(router *routing.Router) { 14 | users.InitUsers() 15 | 16 | usersGroup := router.Group(config.USERS_GROUP) 17 | 18 | usersGroup.Get("", authentication.AdminRequiredMiddleware, controllers.FindUsersHandler) 19 | usersGroup.Get("/", authentication.AdminRequiredMiddleware, controllers.FindUsersHandler) 20 | usersGroup.Post("/", authentication.AdminRequiredMiddleware, controllers.CreateUserHandler) 21 | usersGroup.Post("", authentication.AdminRequiredMiddleware, controllers.CreateUserHandler) 22 | usersGroup.Get("/", authentication.AdminRequiredMiddleware, controllers.GetUserHandler) 23 | usersGroup.Put("/", authentication.AuthorizationMiddleware, controllers.UpdateUserHandler) 24 | usersGroup.Put("/admin/", authentication.AdminRequiredMiddleware, controllers.UpdateUserByAdminHandler) 25 | } -------------------------------------------------------------------------------- /dashboard/src/main.js: -------------------------------------------------------------------------------- 1 | import "es6-promise/auto"; 2 | import "@babel/polyfill"; 3 | import "url-polyfill"; 4 | import Vue from "vue"; 5 | import VueResource from "vue-resource"; 6 | import App from "./App.vue"; 7 | import router from "./router"; 8 | import store from "./store"; 9 | Vue.use(VueResource); 10 | 11 | require("bootstrap"); 12 | require("./libs/string_utils"); 13 | 14 | Vue.config.productionTip = false; 15 | 16 | Vue.prototype.$utils = require("@/utils"); 17 | Vue.prototype.$config = require("@/configs/urls").config; 18 | Vue.prototype.$chartColors = require("@/configs/chartColors"); 19 | Vue.prototype.$random = require("@/configs/random"); 20 | Vue.prototype.$oauthUtils = require("@/auth"); 21 | Vue.prototype.$api = require("@/api/api").api; 22 | Vue.prototype.$permissions = require("@/configs/permissions"); 23 | 24 | const UsersServices = require("@/api/users"); 25 | 26 | UsersServices.me(require("@/api/auth").getToken(), response => { 27 | if (response.status === 200) 28 | store.dispatch("loggedInUserUpdate", response.body); 29 | 30 | new Vue({ 31 | router, 32 | store, 33 | render: h => h(App) 34 | }).$mount("#app"); 35 | }); 36 | -------------------------------------------------------------------------------- /api/controllers/plugins.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/Glintt/gAPI/api/config" 7 | "github.com/Glintt/gAPI/api/http" 8 | "github.com/Glintt/gAPI/api/plugins" 9 | 10 | "github.com/fatih/structs" 11 | 12 | routing "github.com/qiangxue/fasthttp-routing" 13 | ) 14 | 15 | func PluginsServiceName() string { 16 | return plugins.SERVICE_NAME 17 | } 18 | 19 | func ListPluginsAvailable(c *routing.Context) error { 20 | plugins, err := plugins.ListAll() 21 | 22 | if err != nil { 23 | http.Response(c, fmt.Sprintf(`{"error_msg": "%v"}`, err.Error()), 404, ServiceDiscoveryServiceName(), config.APPLICATION_JSON) 24 | return nil 25 | } 26 | pluginsList, _ := json.Marshal(plugins) 27 | 28 | http.Response(c, string(pluginsList), 200, PluginsServiceName(), config.APPLICATION_JSON) 29 | return nil 30 | } 31 | 32 | func ActivePlugins(c *routing.Context) error { 33 | m := structs.Map(config.GApiConfiguration.Plugins) 34 | 35 | delete(m, "Location") 36 | activePlugins, _ := json.Marshal(m) 37 | 38 | http.Response(c, string(activePlugins), 200, PluginsServiceName(), config.APPLICATION_JSON) 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /api/logs/workerqueue.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | apianalytics "github.com/Glintt/gAPI/api/api-analytics" 5 | "github.com/Glintt/gAPI/api/config" 6 | "github.com/Glintt/gAPI/api/rabbit" 7 | "github.com/Glintt/gAPI/api/utils" 8 | "strconv" 9 | ) 10 | 11 | var WorkQueue = make(chan LogWorkRequest, 1000) 12 | var LogWorkQueue chan chan LogWorkRequest 13 | 14 | func StartDispatcher(nworkers int) { 15 | // First, initialize the channel we are going to but the workers' work channels into. 16 | LogWorkQueue = make(chan chan LogWorkRequest, nworkers) 17 | 18 | // Now, create all of our workers. 19 | for i := 0; i < nworkers; i++ { 20 | utils.LogMessage("Starting worker - "+strconv.Itoa(i+1), utils.InfoLogType) 21 | worker := NewWorker(i+1, LogWorkQueue) 22 | worker.Start() 23 | } 24 | 25 | go func() { 26 | for { 27 | select { 28 | case work := <-WorkQueue: 29 | go func() { 30 | worker := <-LogWorkQueue 31 | 32 | // utils.LogMessage("Dispatching work request") 33 | worker <- work 34 | }() 35 | } 36 | } 37 | }() 38 | 39 | if config.GApiConfiguration.Logs.Queue == apianalytics.LogRabbitQueueType { 40 | rabbit.InitPublishers(2) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /docs/plugins.md: -------------------------------------------------------------------------------- 1 | # Plugin 2 | 3 | Plugins are supported on gAPI. 4 | 5 | These plugins must be writen in Golang and are only supportend on Unix. 6 | 7 | Currently, it is supported these types of plugins: 8 | 9 | 1. BeforeRequestPlugin 10 | 11 | ## Build a plugin 12 | 13 | 1. A plugin must use _package main_. 14 | 15 | 2. To build the plugin for usage, run this command: 16 | 17 | ``` 18 | go build -buildmode=plugin -o .so .go 19 | ``` 20 | 21 | ## Types 22 | 23 | #### BeforeRequestPlugin 24 | 25 | 1. These plugins are run before each request to a microservice on gAPI. 26 | 27 | 1. When a plugin returns an error, the request will fail and stop. 28 | 29 | 1. The following methods must be implemented: 30 | 31 | ``` 32 | func (g beforeRequestEntryPlugin) Call(c *routing.Context) error 33 | ``` 34 | 35 | ## Activate a plugin on gAPI 36 | 37 | Currently, to activate a plugin on gAPI you must add the following configuration to _gAPI.json_ config: 38 | 39 | ``` 40 | "Plugins": { 41 | "Location": "./custom_plugins", 42 | "BeforeRequest": ["BeforeRequestPlugin"] 43 | } 44 | ``` 45 | 46 | Params: 47 | 48 | 1. Location - where plugins are stored 49 | 2. BeforeRequest - List of BeforeRequestPlugin type plugins 50 | -------------------------------------------------------------------------------- /dashboard/src/api/auth.js: -------------------------------------------------------------------------------- 1 | const HTTP = require("@/api/http"); 2 | const ACCESS_TOKEN_KEY = "access_token_key"; 3 | const ACCESS_TOKEN_EXPIRATION_TIME = "access_token_expiration_time"; 4 | 5 | export function authenticate(user, password, cb) { 6 | return HTTP.POST( 7 | HTTP.PathToCall("/oauth/token"), 8 | { username: user, password: password }, 9 | {} 10 | ).then( 11 | response => { 12 | storeToken(response.body.token, response.body.expiration_time); 13 | 14 | cb(response); 15 | }, 16 | response => { 17 | HTTP.handleError(response, cb); 18 | } 19 | ); 20 | } 21 | 22 | export function storeToken(token, expirationTime) { 23 | localStorage.setItem(ACCESS_TOKEN_KEY, token); 24 | var whenExpires = new Date().getTime() + (expirationTime - 2) * 1000; 25 | localStorage.setItem(ACCESS_TOKEN_EXPIRATION_TIME, whenExpires); 26 | } 27 | 28 | export function getToken() { 29 | return localStorage.getItem(ACCESS_TOKEN_KEY); 30 | } 31 | 32 | export function getExpirationTime() { 33 | return localStorage.getItem(ACCESS_TOKEN_EXPIRATION_TIME); 34 | } 35 | 36 | export function clearAccessToken() { 37 | localStorage.removeItem(ACCESS_TOKEN_KEY); 38 | localStorage.removeItem(ACCESS_TOKEN_EXPIRATION_TIME); 39 | } 40 | -------------------------------------------------------------------------------- /api/users/providers/users-repository.go: -------------------------------------------------------------------------------- 1 | package providers 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/database" 5 | "github.com/Glintt/gAPI/api/users/models" 6 | 7 | ) 8 | 9 | const ( 10 | PAGE_LENGTH = 10 11 | ) 12 | 13 | type UserRepository interface { 14 | InitUsers() 15 | CreateUser(user models.User) error 16 | UpdateUser(user models.User) error 17 | FindUsersByUsernameOrEmail(q string, page int) []models.User 18 | GetUserByUsername(username string) []models.User 19 | 20 | OpenTransaction() error 21 | CommitTransaction() 22 | RollbackTransaction() 23 | Release() 24 | } 25 | 26 | // NewUserRepository create an user repository based on the database 27 | func NewUserRepository(user models.User) UserRepository { 28 | if database.SD_TYPE == "mongo" { 29 | session, db := database.GetSessionAndDB(database.MONGO_DB) 30 | collection := db.C(USERS_COLLECTION) 31 | 32 | return &UserMongoRepository{ 33 | Session: session, 34 | Db: db, 35 | Collection: collection, 36 | } 37 | } 38 | if database.SD_TYPE == "oracle" { 39 | db, err := database.ConnectToOracle(database.ORACLE_CONNECTION_STRING) 40 | if err != nil { 41 | return nil 42 | } 43 | return &UserOracleRepository{ 44 | Db: db, 45 | DbError: err, 46 | } 47 | } 48 | return nil 49 | } -------------------------------------------------------------------------------- /docs/https.md: -------------------------------------------------------------------------------- 1 | ## HTTPS 2 | 3 | 4 | ### API 5 | 6 | In order to activate HTTPS, you only need to add the configuration to gAPI configuration file (located at *configs/gAPI.json*) and an environment variable. 7 | 8 | The configuration for the HTTPS is as follows: 9 | 10 | ``` 11 | "Protocol": { 12 | "CertificateFile": "certificates/certificate.crt", 13 | "CertificateKey": "certificates/privatekey.key" 14 | } 15 | ``` 16 | 17 | * CertificateFile - certificate file location (*required*) 18 | * CertificateKey - certificate key file location (*required*) 19 | 20 | The environment variable is called *API_PROTOCOL* and can assume these two values: *http* or *https* 21 | 22 | ### Dashboard 23 | 24 | 25 | You also need to define the protocol for the dashboard. If you enable HTTPS on the server side, you need to configure the dashboard to comunicate over https with the API. 26 | 27 | In order to enable HTTPS on the frontend, you need to specify the following env vars: 28 | 29 | 1. *FRONTEND_PROTOCOL* - the protocol of the dashboard (*https* or *http*) 30 | 1. *FRONTEND_CERT_PRIVATE_KEY* - https certificate key file location 31 | 1. *FRONTEND_CERT_FILE* - https certificate file location 32 | 1. *API_PROTOCOL* - the same as the API environment variable. it is used to communicate with the API 33 | 34 | 35 | -------------------------------------------------------------------------------- /dashboard/src/auth.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | const OAUTH_API = require("@/api/auth"); 3 | var store = require("./store"); 4 | 5 | export const vmA = new Vue({ 6 | data: { 7 | loggedIn: false, 8 | user: null 9 | }, 10 | methods: { 11 | logout() { 12 | OAUTH_API.clearAccessToken(); 13 | this.loggedIn = false; 14 | }, 15 | isLoggedIn() { 16 | this.loggedIn = 17 | OAUTH_API.getToken() && 18 | new Date().getTime() < OAUTH_API.getExpirationTime(); 19 | return this.loggedIn; 20 | }, 21 | authenticate(user, cb) { 22 | OAUTH_API.authenticate(user.username, user.password, response => { 23 | cb(response); 24 | }); 25 | }, 26 | currentUser() { 27 | return this.user; 28 | } 29 | } 30 | }); 31 | 32 | export function requireAdminAuth(to, from, next) { 33 | if (!vmA.isLoggedIn()) { 34 | next({ 35 | path: "/login" 36 | }); 37 | } else { 38 | if (!store.default.state.loggedInUser.IsAdmin) return next({ path: "/" }); 39 | else next(); 40 | } 41 | } 42 | 43 | export function requireAuth(to, from, next) { 44 | if (!vmA.isLoggedIn()) { 45 | next({ 46 | path: "/login" 47 | }); 48 | } else { 49 | next(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /api/logs/providers/elastic.go: -------------------------------------------------------------------------------- 1 | package providers 2 | 3 | import ( 4 | "encoding/json" 5 | 6 | "github.com/Glintt/gAPI/api/config" 7 | "github.com/Glintt/gAPI/api/logs/models" 8 | "github.com/Glintt/gAPI/api/utils" 9 | 10 | "github.com/valyala/fasthttp" 11 | ) 12 | 13 | func PublishElastic(reqLogging *models.RequestLogging) { 14 | utils.LogMessage("ELASTIC PUBLISH", utils.DebugLogType) 15 | currentDate := utils.CurrentDate() 16 | 17 | indexName := config.ELASTICSEARCH_LOGS_INDEX 18 | if reqLogging.IndexName != "" { 19 | indexName = reqLogging.IndexName 20 | } 21 | 22 | logsURL := config.ELASTICSEARCH_URL + "/" + indexName + "/request-logs-" + currentDate 23 | 24 | reqLoggingJson, _ := json.Marshal(reqLogging) 25 | 26 | request := fasthttp.AcquireRequest() 27 | 28 | request.SetRequestURI(logsURL) 29 | request.Header.SetMethod("POST") 30 | 31 | request.Header.SetContentType("application/json") 32 | request.SetBody(reqLoggingJson) 33 | client := fasthttp.Client{} 34 | 35 | resp := fasthttp.AcquireResponse() 36 | err := client.Do(request, resp) 37 | 38 | if err != nil { 39 | utils.LogMessage("ELASTIC PUBLISH - error:"+err.Error(), utils.DebugLogType) 40 | 41 | resp.SetStatusCode(400) 42 | } 43 | } 44 | 45 | func RemoveOldLogsElastic() { 46 | // TODO: Remove logs older than x on elasticsearch 47 | } 48 | -------------------------------------------------------------------------------- /api/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/Glintt/gAPI/api 2 | 3 | replace github.com/Glintt/gAPI/api => ./ 4 | 5 | require ( 6 | github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect 7 | github.com/allegro/bigcache v1.2.0 8 | github.com/dgrijalva/jwt-go v3.2.0+incompatible 9 | github.com/fatih/structs v1.1.0 10 | github.com/go-ldap/ldap v3.0.3+incompatible 11 | github.com/go-ole/go-ole v1.2.4 // indirect 12 | github.com/googollee/go-socket.io v1.4.1 // indirect 13 | github.com/graarh/golang-socketio v0.0.0-20170510162725-2c44953b9b5f 14 | github.com/manucorporat/try v0.0.0-20170609134256-2a0c6b941d52 15 | github.com/patrickmn/go-cache v2.1.0+incompatible // indirect 16 | github.com/qiangxue/fasthttp-routing v0.0.0-20160225050629-6ccdc2a18d87 17 | github.com/robfig/cron v1.1.0 18 | github.com/rs/cors v1.6.0 19 | github.com/shirou/gopsutil v2.18.12+incompatible 20 | github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4 // indirect 21 | github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94 22 | github.com/ulule/limiter v2.2.2+incompatible // indirect 23 | github.com/valyala/fasthttp v1.3.0 24 | golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f 25 | gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect 26 | gopkg.in/goracle.v2 v2.16.2 27 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce 28 | ) 29 | -------------------------------------------------------------------------------- /docs/rate-limiting.md: -------------------------------------------------------------------------------- 1 | ## Rate Limiting 2 | 3 | gAPI allows to add rate limiting to micro services. 4 | 5 | It has two options: 6 | 7 | 1. Global rate limiting - affects all registered micro-services 8 | 2. Service specific rate limiting - only affects a specific micro-service 9 | 10 | 11 | ### Configuration 12 | 13 | In order to activate rate limiting add the following configuration to gAPI.json configuration: 14 | 15 | ```json 16 | "RateLimiting":{ 17 | "Active": true, 18 | "Limit": 20, 19 | "Period": 1, 20 | "Metrics": ["RemoteAddr", "MatchingUri"] 21 | } 22 | ``` 23 | 24 | > **Active** - enable or disable rate limiting;
25 | > **Limit** - max number of requests;
26 | > **Period** - time until number requests available are reset (in minutes);
27 | > **Metrics** - Metrics to use to limit requests rate (allowed values: *"RemoteAddr"*, *"MatchingUri"*) 28 | 29 | ### Service specific configuration 30 | 31 | Each service has the following fields: 32 | 33 | 1. RateLimit - max number of request 34 | 2. RateLimitExpirationTime - time until number requests is reset (in minutes) 35 | 36 | By default, these fields are stored with value 0. When value is 0, custom rate limiting is disabled. 37 | 38 | In order to add rate limiting to a specific service you need to override these values. 39 | -------------------------------------------------------------------------------- /api/oauth_clients/oauth_clients-oracle.go: -------------------------------------------------------------------------------- 1 | package oauth_clients 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/Glintt/gAPI/api/database" 7 | ) 8 | 9 | var FIND_CLIENT = `select client_id, client_secret from gapi_oauth_clients where client_id = :client_id and client_secret = :client_secret` 10 | 11 | func FindOAuthClientOracle(clientId string, clientSecret string) OAuthClient { 12 | db, err := database.ConnectToOracle(database.ORACLE_CONNECTION_STRING) 13 | if err != nil { 14 | return OAuthClient{} 15 | } 16 | 17 | rows, err := db.Query(FIND_CLIENT, clientId, clientSecret) 18 | 19 | if err != nil { 20 | database.CloseOracleConnection(db) 21 | return OAuthClient{} 22 | } 23 | 24 | clients := RowsToClients(rows, false) 25 | 26 | database.CloseOracleConnection(db) 27 | if len(clients) == 0 { 28 | return OAuthClient{} 29 | } 30 | return clients[0] 31 | } 32 | 33 | func RowsToClients(rows *sql.Rows, containsPagination bool) []OAuthClient { 34 | var clients []OAuthClient 35 | for rows.Next() { 36 | var client OAuthClient 37 | var r int 38 | if containsPagination { 39 | rows.Scan(&client.ClientId, &client.ClientSecret, &r) 40 | } else { 41 | rows.Scan(&client.ClientId, &client.ClientSecret) 42 | } 43 | 44 | clients = append(clients, client) 45 | } 46 | 47 | defer rows.Close() 48 | 49 | return clients 50 | } 51 | -------------------------------------------------------------------------------- /api/swagger/controllers/Admin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var utils = require('../utils/writer.js'); 4 | var Admin = require('../service/AdminService'); 5 | 6 | module.exports.invalidate_cacheGET = function invalidate_cacheGET (req, res, next) { 7 | var authorization = req.swagger.params['Authorization'].value; 8 | Admin.invalidate_cacheGET(authorization) 9 | .then(function (response) { 10 | utils.writeJson(res, response); 11 | }) 12 | .catch(function (response) { 13 | utils.writeJson(res, response); 14 | }); 15 | }; 16 | 17 | module.exports.reloadGET = function reloadGET (req, res, next) { 18 | var authorization = req.swagger.params['Authorization'].value; 19 | Admin.reloadGET(authorization) 20 | .then(function (response) { 21 | utils.writeJson(res, response); 22 | }) 23 | .catch(function (response) { 24 | utils.writeJson(res, response); 25 | }); 26 | }; 27 | 28 | module.exports.service_discoveryAdminNormalizePOST = function service_discoveryAdminNormalizePOST (req, res, next) { 29 | var authorization = req.swagger.params['Authorization'].value; 30 | Admin.service_discoveryAdminNormalizePOST(authorization) 31 | .then(function (response) { 32 | utils.writeJson(res, response); 33 | }) 34 | .catch(function (response) { 35 | utils.writeJson(res, response); 36 | }); 37 | }; 38 | -------------------------------------------------------------------------------- /api/ratelimiting/metric.go: -------------------------------------------------------------------------------- 1 | package ratelimiting 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | "github.com/Glintt/gAPI/api/servicediscovery/service" 6 | "github.com/Glintt/gAPI/api/servicediscovery" 7 | userModels "github.com/Glintt/gAPI/api/users/models" 8 | 9 | routing "github.com/qiangxue/fasthttp-routing" 10 | ) 11 | 12 | func GetRateLimitingMetricName(c *routing.Context, limiter config.GApiRateLimitingConfig) string { 13 | metricName := "" 14 | for _, val := range limiter.Metrics { 15 | if metricName != "" { 16 | metricName = metricName + "-" 17 | } 18 | switch val { 19 | case "RemoteAddr": 20 | metricName = metricName + remoteAddr(c) 21 | break 22 | case "MatchingUri": 23 | metricName = metricName + matchingUri(c) 24 | break 25 | 26 | default: 27 | metricName = metricName + val 28 | break 29 | } 30 | } 31 | return metricName 32 | } 33 | 34 | func remoteAddr(c *routing.Context) string { 35 | return c.RemoteAddr().String() 36 | } 37 | 38 | func matchingUri(c *routing.Context) string { 39 | return serviceForUri(c).MatchingURI 40 | } 41 | 42 | func serviceForUri(c *routing.Context) service.Service { 43 | sd := servicediscovery.GetServiceDiscoveryObject(userModels.GetInternalAPIUser()) 44 | s, _ := sd.GetEndpointForUri(string(c.Request.RequestURI())) 45 | return s 46 | } 47 | -------------------------------------------------------------------------------- /docs/healthcheck.md: -------------------------------------------------------------------------------- 1 | # Healthcheck 2 | 3 | Healthcheck is a module to check if a service is up and running. 4 | 5 | This module can be enabled on the configuration file. When a service status changes, a notifications can be sent to a channel. 6 | Currently, the only supported channel to send notifications is Slack. 7 | 8 | ### Enable/Disable 9 | 10 | On _gAPI.json_ configuration, there is the following section: 11 | 12 | ``` 13 | "Healthcheck": { 14 | "Active": true, 15 | "Frequency": 30, 16 | "Notification": false 17 | } 18 | ``` 19 | 20 | Info: 21 | 22 | 1. Active - boolean to activate/deactivate healthcheck 23 | 2. Frequency - healthcheck frequency in seconds 24 | 3. Notification - boolean to activate/deactivate status change notifications 25 | 26 | ### Notifications 27 | 28 | Notifications can also be enabled and disabled. In order to enable notifications, healthcheck must be enabled too. 29 | To enable notifications, there is a section on _gAPI.json_ configuration file: 30 | 31 | ``` 32 | "Notifications": { 33 | "Type": "Slack", 34 | "Slack": { 35 | "WebhookUrl": "https://hooks.slack.com/services/asld/lak/la" 36 | } 37 | } 38 | ``` 39 | 40 | Info: 41 | 42 | 1. Type - type of notifications to be sent (available: _Slack_) 43 | 2. Slack - for notification type _Slack_ 44 | 1. WebhookUrl - slack notifications are sent by calling an webhook. Here we can configure the webhook url. 45 | -------------------------------------------------------------------------------- /dashboard/src/components/plugins/PluginsList.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 41 | -------------------------------------------------------------------------------- /api/controllers/analytics.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | apianalytics "github.com/Glintt/gAPI/api/api-analytics" 5 | "github.com/Glintt/gAPI/api/config" 6 | "github.com/Glintt/gAPI/api/http" 7 | 8 | routing "github.com/qiangxue/fasthttp-routing" 9 | ) 10 | 11 | func Logs(c *routing.Context) error { 12 | apiEndpoint := string(c.QueryArgs().Peek("endpoint")) 13 | 14 | res, status := apianalytics.AnalyticsMethods[config.GApiConfiguration.Logs.Type]["logs"].(func(string) (string, int))(apiEndpoint) 15 | 16 | http.Response(c, res, status, apianalytics.SERVICE_NAME, config.APPLICATION_JSON) 17 | 18 | return nil 19 | } 20 | 21 | func APIAnalytics(c *routing.Context) error { 22 | apiEndpoint := string(c.QueryArgs().Peek("endpoint")) 23 | 24 | res, status := apianalytics.AnalyticsMethods[config.GApiConfiguration.Logs.Type]["analytics"].(func(string) (string, int))(apiEndpoint) 25 | 26 | http.Response(c, res, status, apianalytics.SERVICE_NAME, config.APPLICATION_JSON) 27 | 28 | return nil 29 | } 30 | 31 | func ApplicationGroupAnalytics(c *routing.Context) error { 32 | applicationGroup := string(c.QueryArgs().Peek("app_id")) 33 | 34 | res, status := apianalytics.AnalyticsMethods[config.GApiConfiguration.Logs.Type]["app_analytics"].(func(string) (string, int))(applicationGroup) 35 | 36 | http.Response(c, res, status, apianalytics.SERVICE_NAME, config.APPLICATION_JSON) 37 | 38 | return nil 39 | } 40 | -------------------------------------------------------------------------------- /docs/architecture.md: -------------------------------------------------------------------------------- 1 | # Architecture 2 | 3 | | System architecture as a global | gAPI functional architecture | 4 | | :--------------------------------------------------------------------------: | :---------------------------------------------------------------------------: | 5 | | ![System Architecture](./imgs/architecture_global.png "System Architecture") | ![Functional Architecture](./imgs/architecture.png "Functional Architecture") | 6 | 7 | gAPI is composed by several components: 8 | 9 | 1. Service Discovery (SD) - where all APIs and MicroServices are stored. The storage can be done to MongoDB or JSON file (to reduce dependencies) 10 | 2. Request Logging - this component is responsible for logging all requests information. It uses RabbitMQ to publish new logs to a queue. This component also contains a listener/consumer which is listening from RabbitMQ and stores logs to ElasticSearch 11 | 3. API - allows to access gAPI features: 12 | - Register, list, find or delete a MicroService 13 | - Get request analytics 14 | - Authenticate user on gAPI services 15 | 4. OAuth authenticator - responsible for authenticating users on MicroServices. This component uses an external oauth server to validate token. 16 | 5. Proxy - responsible for requesting the correct microservice when a new requests comes. 17 | 6. Authentication - gAPI Authentication service. 18 | -------------------------------------------------------------------------------- /dashboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve --open", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "@babel/polyfill": "^7.4.4", 12 | "bootstrap": "^4.1.1", 13 | "chart.js": "^2.7.2", 14 | "clipboard": "^2.0.1", 15 | "css-loader": "^0.28.11", 16 | "ejs": "^2.6.1", 17 | "es6-promise": "^4.2.8", 18 | "eslint": "^5.8.0", 19 | "express": "4.16.3", 20 | "express-http-proxy": "^1.5.1", 21 | "hchs-vue-charts": "^1.2.8", 22 | "jquery": "^3.3.1", 23 | "popper.js": "^1.14.1", 24 | "socket.io-client": "^2.1.0", 25 | "url-polyfill": "^1.1.5", 26 | "uws": "^9.14.0", 27 | "vue": "^2.5.13", 28 | "vue-chartjs": "^3.3.1", 29 | "vue-resource": "^1.5.0", 30 | "vue-router": "^3.0.1", 31 | "vuetable": "^1.5.12", 32 | "vuex": "^3.0.1" 33 | }, 34 | "devDependencies": { 35 | "@vue/cli-plugin-babel": "^3.0.0-rc.10", 36 | "@vue/cli-plugin-eslint": "^3.0.0-rc.10", 37 | "@vue/cli-service": "^3.0.0-rc.10", 38 | "@vue/eslint-config-prettier": "^3.0.0-rc.10", 39 | "node-sass": "^4.9.0", 40 | "sass-loader": "^7.0.1", 41 | "vue-template-compiler": "^2.5.16", 42 | "babel-plugin-transform-inline-environment-variables": "^0.3.0", 43 | "eslint-plugin-prettier": "^3.1.0", 44 | "eslint-plugin-vue": "^5.2.3" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dashboard/src/utils.js: -------------------------------------------------------------------------------- 1 | let $ = require("jquery"); 2 | 3 | export function timeRound(value) { 4 | return Math.round(value * 100) / 100; 5 | } 6 | 7 | export function currentTimeString() { 8 | var currentDate = new Date(); 9 | return ( 10 | currentDate.getHours() + 11 | ":" + 12 | currentDate.getMinutes() + 13 | ":" + 14 | currentDate.getSeconds() 15 | ); 16 | } 17 | 18 | export function getCookieByName(name) { 19 | var pair = document.cookie.match(new RegExp(name + "=([^;]+)")); 20 | return pair ? pair[1] : null; 21 | } 22 | export function convertMillisToTime(millis) { 23 | let delim = " "; 24 | let hours = Math.floor((millis / (1000 * 60 * 60)) % 60); 25 | let minutes = Math.floor((millis / (1000 * 60)) % 60); 26 | let seconds = Math.floor((millis / 1000) % 60); 27 | hours = hours < 10 ? "0" + hours : hours; 28 | minutes = minutes < 10 ? "0" + minutes : minutes; 29 | seconds = seconds < 10 ? "0" + seconds : seconds; 30 | return hours + "h" + delim + minutes + "m" + delim + seconds + "s"; 31 | } 32 | 33 | export function enableTooltip() { 34 | $(document).ready(function() { 35 | $("body").tooltip({ 36 | selector: "[data-toggle=tooltip]", 37 | trigger: "hover" 38 | }); 39 | }); 40 | } 41 | 42 | export function urlConcat(host, path) { 43 | try { 44 | return new URL(path, host).href; 45 | } catch (e) { 46 | return `${host}/${path}`.replace("//", ""); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /api/mongodb-update.js: -------------------------------------------------------------------------------- 1 | db.services.find({}).forEach(function (item){ 2 | // Update hosts array 3 | item.hosts = ['localhost:8070'] 4 | 5 | // Update default host and port 6 | item.host = 'localhost' 7 | item.port = '8070' 8 | 9 | // Update documentation location 10 | item.apidocumentation = "http://localhost:8070/api/experience/eresults/console" 11 | 12 | // Update healthcheck url - replace env=ci with the env 13 | item.healthcheckurl = "http://localhost:8001/amc/mule/applications/gplatform.experience.eresults-1.0.0/healthcheck?env=ci" 14 | 15 | // Update api management host and port 16 | item.servicemanagementhost = 'localhost' 17 | item.servicemanagementport = '8001' 18 | 19 | // Update all api management endpoints 20 | item.servicemanagementendpoints['redeploy'] = item.servicemanagementendpoints['redeploy'].replace('DEV', 'CI') 21 | item.servicemanagementendpoints['restart'] = item.servicemanagementendpoints['restart'].replace('DEV', 'CI') 22 | item.servicemanagementendpoints['undeploy'] = item.servicemanagementendpoints['undeploy'].replace('DEV', 'CI') 23 | item.servicemanagementendpoints['backup'] = item.servicemanagementendpoints['backup'].replace('DEV', 'CI') 24 | item.servicemanagementendpoints['logs'] = item.servicemanagementendpoints['logs'].replace('DEV', 'CI') 25 | item.servicemanagementendpoints['logs'] = item.servicemanagementendpoints['logs'].replace('logs', 'log') 26 | db.services.save(item) 27 | }) -------------------------------------------------------------------------------- /api/servicediscovery/servicegroup/service-group-repository.go: -------------------------------------------------------------------------------- 1 | package servicegroup 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/database" 5 | userModels "github.com/Glintt/gAPI/api/users/models" 6 | ) 7 | 8 | type ServiceGroupRepository interface { 9 | GetServiceGroups() ([]ServiceGroup, error) 10 | GetServiceGroupById(serviceGroup string) (ServiceGroup, error) 11 | AddServiceToGroup(serviceGroupId string, serviceId string) error 12 | RemoveServiceFromGroup(serviceGroupId string, serviceId string) error 13 | CreateServiceGroup(serviceGroup ServiceGroup) error 14 | UpdateServiceGroup(serviceGroupId string, serviceGroup ServiceGroup) error 15 | DeleteServiceGroup(serviceGroupId string) error 16 | 17 | OpenTransaction() error 18 | CommitTransaction() 19 | RollbackTransaction() 20 | Release() 21 | } 22 | 23 | // NewServiceGroupRepository create an application group repository based on the database 24 | func NewServiceGroupRepository(user userModels.User) ServiceGroupRepository { 25 | if database.SD_TYPE == "mongo" { 26 | session, db := database.GetSessionAndDB(database.MONGO_DB) 27 | collection := db.C(SERVICE_GROUP_COLLECTION) 28 | 29 | return &ServiceGroupMongoRepository{ 30 | Session: session, 31 | Db: db, 32 | Collection: collection, 33 | } 34 | } 35 | if database.SD_TYPE == "oracle" { 36 | db, err := database.ConnectToOracle(database.ORACLE_CONNECTION_STRING) 37 | if err != nil { 38 | return nil 39 | } 40 | return &ServiceGroupOracleRepository{ 41 | Db: db, 42 | DbError: err, 43 | } 44 | } 45 | return nil 46 | } -------------------------------------------------------------------------------- /dashboard/src/components/modals/ErrorMessage.vue: -------------------------------------------------------------------------------- 1 | 25 | 46 | -------------------------------------------------------------------------------- /dashboard/src/components/modals/SuccessModal.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 47 | -------------------------------------------------------------------------------- /api/logs/worker.go: -------------------------------------------------------------------------------- 1 | package logs 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/utils" 5 | "strconv" 6 | ) 7 | 8 | // NewWorker creates, and returns a new Worker object. Its only argument 9 | // is a channel that the worker can add itself to whenever it is done its 10 | // work. 11 | func NewWorker(id int, workerQueue chan chan LogWorkRequest) Worker { 12 | // Create, and return the worker. 13 | worker := Worker{ 14 | ID: id, 15 | Work: make(chan LogWorkRequest), 16 | WorkerQueue: workerQueue, 17 | QuitChan: make(chan bool)} 18 | 19 | return worker 20 | } 21 | 22 | type Worker struct { 23 | ID int 24 | Work chan LogWorkRequest 25 | WorkerQueue chan chan LogWorkRequest 26 | QuitChan chan bool 27 | } 28 | 29 | // This function "starts" the worker by starting a goroutine, that is 30 | // an infinite "for-select" loop. 31 | func (w *Worker) Start() { 32 | go func() { 33 | for { 34 | // Add ourselves into the worker queue. 35 | w.WorkerQueue <- w.Work 36 | 37 | select { 38 | case work := <-w.Work: 39 | PublishLog(&work.LogToSave) 40 | // Receive a work request. 41 | //work.LogToSave.Save() 42 | 43 | case <-w.QuitChan: 44 | // We have been asked to stop. 45 | utils.LogMessage("worker "+strconv.Itoa(w.ID)+" stopping\n", utils.DebugLogType) 46 | return 47 | } 48 | } 49 | }() 50 | } 51 | 52 | // Stop tells the worker to stop listening for work requests. 53 | // 54 | // Note that the worker will only stop *after* it has finished its work. 55 | func (w *Worker) Stop() { 56 | go func() { 57 | w.QuitChan <- true 58 | }() 59 | } 60 | -------------------------------------------------------------------------------- /dashboard/src/configs/urls.js: -------------------------------------------------------------------------------- 1 | export const config = { 2 | API: { 3 | PROTOCOL: process.env.API_PROTOCOL || "http", 4 | HOST: process.env.API_HOST || "localhost", 5 | PORT: process.env.API_PORT || "8084", 6 | SOCKET_HOST: process.env.SOCKET_HOST || "localhost", 7 | SOCKET_PORT: process.env.SOCKET_PORT || "5000", 8 | BASE_PATH: "", 9 | API_BASE_PATH: "", 10 | SERVICE_DISCOVERY_BASEPATH: "/service-discovery", 11 | ANALYTICS_BASEPATH: "/analytics", 12 | 13 | getHeader: function(name) { 14 | var req = new XMLHttpRequest(); 15 | req.open("GET", document.location, false); 16 | req.send(null); 17 | 18 | return req.getResponseHeader(name); 19 | }, 20 | 21 | getApiBaseUrl: function() { 22 | // let apiBaseUrl = this.getHeader("Api-Base"); 23 | 24 | // if (apiBaseUrl == undefined || apiBaseUrl == null) { 25 | // return this.API_BASE_PATH 26 | // } 27 | 28 | return this.API_BASE_PATH; 29 | 30 | // if (apiBaseUrl == undefined || apiBaseUrl == null) { 31 | // apiBaseUrl = `${this.PROTOCOL}://${this.HOST}:${this.PORT}/${ 32 | // this.BASE_PATH 33 | // }`; 34 | // } 35 | 36 | //return apiBaseUrl; 37 | }, 38 | 39 | getSocketBaseUrl: function() { 40 | var socketBaseUrl = this.getHeader("Socket-Base"); 41 | 42 | if (socketBaseUrl == undefined || socketBaseUrl == null) { 43 | socketBaseUrl = `ws://${this.SOCKET_HOST}:${this.SOCKET_PORT}/`; 44 | } 45 | 46 | return socketBaseUrl; 47 | } 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /dashboard/src/api/http.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | const OAuthAPI = require("@/api/auth"); 4 | const API_CONFIG = require("@/configs/urls").config.API; 5 | //const url = require("url"); 6 | 7 | export function PathToCall(path) { 8 | // return url.resolve(API_CONFIG.getApiBaseUrl(), path); 9 | return API_CONFIG.getApiBaseUrl() + path; 10 | } 11 | 12 | function AddAuthorizationToHeader(config) { 13 | var token = OAuthAPI.getToken(); 14 | 15 | if (config["headers"] === null || config["headers"] === undefined) 16 | config["headers"] = {}; 17 | 18 | if (token !== null && token !== undefined) 19 | config["headers"] = Object.assign(config["headers"], { 20 | Authorization: "Bearer " + token 21 | }); 22 | 23 | return config; 24 | } 25 | 26 | export function GET(url, params) { 27 | params = AddAuthorizationToHeader(params); 28 | 29 | return Vue.http.get(url, params); 30 | } 31 | 32 | export function DELETE(url, params) { 33 | params = AddAuthorizationToHeader(params); 34 | 35 | return Vue.http.delete(url, params); 36 | } 37 | 38 | export function PUT(url, body, params) { 39 | params = AddAuthorizationToHeader(params); 40 | 41 | return Vue.http.put(url, body, params); 42 | } 43 | 44 | export function POST(url, body, params) { 45 | params = AddAuthorizationToHeader(params); 46 | 47 | return Vue.http.post(url, body, params); 48 | } 49 | 50 | export function handleError(response, cb) { 51 | if (response.status === 401) { 52 | window.location.href = "/#/login"; 53 | OAuthAPI.clearAccessToken(); 54 | } 55 | 56 | cb(response); 57 | } 58 | -------------------------------------------------------------------------------- /dashboard/src/api/users.js: -------------------------------------------------------------------------------- 1 | const HTTP = require("@/api/http"); 2 | 3 | export function me(token, cb) { 4 | return HTTP.GET(HTTP.PathToCall("/oauth/me"), {}).then( 5 | response => { 6 | cb(response); 7 | }, 8 | response => { 9 | HTTP.handleError(response, cb); 10 | } 11 | ); 12 | } 13 | 14 | export function find(query, page, cb) { 15 | if (query === undefined) { 16 | query = ""; 17 | } 18 | if (page === undefined || page < 1) page = 1; 19 | return HTTP.GET( 20 | HTTP.PathToCall("/users?q=" + query + "&page=" + page), 21 | {} 22 | ).then( 23 | response => { 24 | cb(response); 25 | }, 26 | response => { 27 | HTTP.handleError(response, cb); 28 | } 29 | ); 30 | } 31 | 32 | export function update(user, cb) { 33 | return HTTP.PUT(HTTP.PathToCall(`/users/${user.Username}`), user, {}).then( 34 | response => { 35 | cb(response); 36 | }, 37 | response => { 38 | HTTP.handleError(response, cb); 39 | } 40 | ); 41 | } 42 | 43 | export function updateByAdmin(user, cb) { 44 | return HTTP.PUT( 45 | HTTP.PathToCall(`/users/admin/${user.Username}`), 46 | user, 47 | {} 48 | ).then( 49 | response => { 50 | cb(response); 51 | }, 52 | response => { 53 | HTTP.handleError(response, cb); 54 | } 55 | ); 56 | } 57 | 58 | export function create(user, cb) { 59 | return HTTP.POST(HTTP.PathToCall(`/users`), user, {}).then( 60 | response => { 61 | cb(response); 62 | }, 63 | response => { 64 | HTTP.handleError(response, cb); 65 | } 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /api/swagger/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | path = require('path'), 5 | http = require('http'); 6 | 7 | var app = require('connect')(); 8 | var swaggerTools = require('swagger-tools'); 9 | var jsyaml = require('js-yaml'); 10 | var serverPort = 8080; 11 | 12 | // swaggerRouter configuration 13 | var options = { 14 | swaggerUi: path.join(__dirname, '/swagger.json'), 15 | controllers: path.join(__dirname, './controllers'), 16 | useStubs: process.env.NODE_ENV === 'development' // Conditionally turn on stubs (mock mode) 17 | }; 18 | 19 | // The Swagger document (require it, build it programmatically, fetch it from a URL, ...) 20 | var spec = fs.readFileSync(path.join(__dirname,'api/swagger.yaml'), 'utf8'); 21 | var swaggerDoc = jsyaml.safeLoad(spec); 22 | 23 | // Initialize the Swagger middleware 24 | swaggerTools.initializeMiddleware(swaggerDoc, function (middleware) { 25 | 26 | // Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain 27 | app.use(middleware.swaggerMetadata()); 28 | 29 | // Validate Swagger requests 30 | app.use(middleware.swaggerValidator()); 31 | 32 | // Route validated requests to appropriate controller 33 | app.use(middleware.swaggerRouter(options)); 34 | 35 | // Serve the Swagger documents and Swagger UI 36 | app.use(middleware.swaggerUi()); 37 | 38 | // Start the server 39 | http.createServer(app).listen(serverPort, function () { 40 | console.log('Your server is listening on port %d (http://localhost:%d)', serverPort, serverPort); 41 | console.log('Swagger-ui is available on http://localhost:%d/docs', serverPort); 42 | }); 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /dashboard/src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | import users from "./store/modules/users/index"; 5 | import serviceGroups from "./store/modules/services-groups"; 6 | import appsGroups from "./store/modules/apps-groups"; 7 | import fullscreen from "./store/modules/full-screen"; 8 | import plugins from "./store/modules/plugins"; 9 | import user_permissions from "./store/modules/user_permissions"; 10 | // var auth = require('./auth') 11 | Vue.use(Vuex); 12 | 13 | export default new Vuex.Store({ 14 | modules: { 15 | users, 16 | serviceGroups, 17 | appsGroups, 18 | fullscreen, 19 | plugins, 20 | user_permissions 21 | }, 22 | state: { 23 | isLoggedIn: false, 24 | loggedInUser: null 25 | }, 26 | mutations: { 27 | loggedIn(state) { 28 | state.isLoggedIn = true; 29 | }, 30 | loggedOut(state) { 31 | state.isLoggedIn = false; 32 | }, 33 | loggedInUserUpdate(state, user) { 34 | state.loggedInUser = user; 35 | localStorage.setItem("user", user); 36 | } 37 | }, 38 | getters: { 39 | isLoggedIn: state => { 40 | return state.isLoggedIn; 41 | }, 42 | loggedInUser: state => { 43 | return state.loggedInUser; 44 | }, 45 | isAdmin: state => { 46 | if (!state.loggedInUser) return false; 47 | return state.loggedInUser.IsAdmin; 48 | } 49 | }, 50 | actions: { 51 | loggedInUserUpdate: ({ commit }, user) => { 52 | commit("loggedInUserUpdate", user); 53 | }, 54 | login: ({ commit }) => { 55 | commit("loggedIn"); 56 | }, 57 | logout: ({ commit }) => { 58 | commit("loggedOut"); 59 | } 60 | } 61 | }); 62 | -------------------------------------------------------------------------------- /dashboard/src/views/Analytics/ByApplication.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 56 | -------------------------------------------------------------------------------- /api/configs-example/gAPI.json: -------------------------------------------------------------------------------- 1 | { 2 | "Authentication": { 3 | "TokenExpirationTime": 86400000, 4 | "TokenSigningKey": "SIGNING_KEY", 5 | "LDAP": { 6 | "Active": true, 7 | "Domain": "ldap.example.com", 8 | "Port": "389" 9 | } 10 | }, 11 | "Logs": { 12 | "Active": true, 13 | "Type": "Elastic", 14 | "Queue": "Rabbit" 15 | }, 16 | "CORS": { 17 | "AllowedOrigins": ["http://localhost:8080"], 18 | "AllowCredentials": true 19 | }, 20 | "ServiceDiscovery": { 21 | "Type": "oracle" 22 | }, 23 | "Healthcheck": { 24 | "Active": true, 25 | "Frequency": 30, 26 | "Notification": true 27 | }, 28 | "Notifications": { 29 | "Type": "Slack", 30 | "Slack": { 31 | "WebhookUrl": "https://hooks.slack.com/services/asld/lak/la" 32 | } 33 | }, 34 | "RateLimiting": { 35 | "Active": true, 36 | "Limit": 20, 37 | "Period": 1, 38 | "Metrics": ["RemoteAddr", "MatchingUri"] 39 | }, 40 | "ManagementTypes": { 41 | "logs" : { 42 | "action": "logs", 43 | "method": "GET", 44 | "icon": "fas fa-file", 45 | "background": "", 46 | "description": "View service logs" 47 | } 48 | }, 49 | "Protocol": { 50 | "Https": false, 51 | "CertificateFile": "/certificates/certificate.crt", 52 | "CertificateKey": "/certificates/privatekey.key" 53 | }, 54 | "ThirdPartyOAuth": { 55 | "Host": "http://localhost", 56 | "Port": "8084", 57 | "AuthorizeEndpoint": "/oauth/authorize", 58 | "UserTokenInformation": { 59 | "Active": true, 60 | "Source": "header", 61 | "Name": "CallData" 62 | } 63 | }, 64 | "MatchingUriRegex": "newMatchingURIRegex" 65 | } 66 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | # nginx: 4 | # image: nginx:stable-alpine 5 | # restart: always 6 | # ports: 7 | # - ${API_MANAGEMENT_PORT_EXT}:80 8 | # - ${SOCKET_PORT_EXT}:${SOCKET_PORT} 9 | # volumes: 10 | # - ./nginx/sites-enabled:/etc/nginx/sites-enabled 11 | 12 | backend: 13 | restart: always 14 | build: 15 | context: ./api 16 | env_file: .env 17 | ports: 18 | - ${API_MANAGEMENT_PORT_EXT}:${API_MANAGEMENT_PORT} 19 | - ${SOCKET_PORT_EXT}:${SOCKET_PORT} 20 | volumes: 21 | - ./api/configs:/go/src/gAPI/api/configs/ 22 | 23 | frontend: 24 | build: 25 | context: ./dashboard 26 | env_file: .env 27 | restart: always 28 | ports: 29 | - ${FRONTEND_PORT}:80 30 | 31 | rabbitlistener: 32 | restart: always 33 | build: 34 | context: ./api 35 | dockerfile: Dockerfile-rabbitlistener 36 | env_file: .env 37 | volumes: 38 | - ./api/configs:/go/src/gAPI/api/configs/ 39 | 40 | rabbit: 41 | restart: always 42 | image: "rabbitmq:3-management" 43 | hostname: "rabbit" 44 | env_file: .env 45 | ports: 46 | - "${RABBITMQ_MANAGEMENT_PORT_EXT}:15672" 47 | - "${RABBITMQ_PORT_EXT}:5672" 48 | labels: 49 | NAME: "rabbitmq" 50 | 51 | elastic: 52 | restart: always 53 | image: elasticsearch:latest 54 | env_file: .env 55 | ports: 56 | - "${ELASTICSEARCH_PORT_EXT}:9200" 57 | - "${ELASTICSEARCH_ALT_PORT_EXT}:9300" 58 | volumes: 59 | - ./elasticsearch/storage/data:/usr/share/elasticsearch/data 60 | 61 | mongodb: 62 | image: mongo 63 | restart: always 64 | env_file: .env 65 | volumes: 66 | - ./data:/data/db 67 | ports: 68 | - "${MONGO_PORT_EXT}:27017" -------------------------------------------------------------------------------- /api/user_permission/user_permission.go: -------------------------------------------------------------------------------- 1 | package user_permission 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/user_permission/providers" 5 | "github.com/Glintt/gAPI/api/user_permission/models" 6 | ) 7 | 8 | const ( 9 | SERVICE_NAME = "USER_PERMISSION" 10 | ) 11 | 12 | func getRepository() providers.PermissionsRepositoryInterface { 13 | return providers.GetPermissionRepository() 14 | } 15 | 16 | func GetUserPermissions(user_id string) ([]models.UserPermission, error){ 17 | repository := getRepository() 18 | repository.CreateTransaction() 19 | 20 | permissions,err := repository.Get(user_id) 21 | if err != nil { 22 | repository.RollbackTransaction() 23 | return permissions,err 24 | } 25 | repository.CommitTransaction() 26 | return permissions, nil 27 | } 28 | 29 | func AddPermission(permission models.UserPermission) error { 30 | repository := getRepository() 31 | repository.CreateTransaction() 32 | 33 | err := repository.Add(permission) 34 | if err != nil { 35 | repository.RollbackTransaction() 36 | return err 37 | } 38 | repository.CommitTransaction() 39 | return nil 40 | } 41 | 42 | func UpdatePermission(userId string, permissions []models.UserPermission) error{ 43 | repository := getRepository() 44 | repository.CreateTransaction() 45 | 46 | err := repository.Update(userId, permissions) 47 | if err != nil { 48 | repository.RollbackTransaction() 49 | return err 50 | } 51 | err = repository.CommitTransaction() 52 | return nil 53 | } 54 | 55 | func DeletePermission(userId string, permissionId string) error{ 56 | repository := getRepository() 57 | repository.CreateTransaction() 58 | 59 | err := repository.Delete(userId, permissionId) 60 | if err != nil { 61 | repository.RollbackTransaction() 62 | return err 63 | } 64 | repository.CommitTransaction() 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /api/config/urls.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | var SERVICE_DISCOVERY_URL = "http://localhost:8080" 8 | var SERVICE_DISCOVERY_GROUP = "/service-discovery" 9 | var USERS_GROUP = "/users" 10 | var USER_PERMISSIONS_GROUP = "/user-permissions" 11 | var OAUTH_CLIENTS_GROUP = "/oauth_clients" 12 | var ANALYTICS_GROUP = "/analytics" 13 | var ELASTICSEARCH_URL = "http://localhost:9200" 14 | var ELASTICSEARCH_LOGS_INDEX = "gapi-logs" 15 | 16 | type UrlsConstants struct { 17 | SERVICE_DISCOVERY_GROUP string `json:SERVICE_DISCOVERY_GROUP` 18 | ANALYTICS_GROUP string `json:ANALYTICS_GROUP` 19 | } 20 | 21 | /* 22 | func LoadURLConstants() { 23 | urlsJSON, err := ioutil.ReadFile(CONFIGS_LOCATION + URLS_CONFIG_FILE) 24 | 25 | if err != nil { 26 | return 27 | } 28 | 29 | var sc UrlsConstants 30 | json.Unmarshal(urlsJSON, &sc) 31 | 32 | SERVICE_DISCOVERY_URL = "http://" + os.Getenv("SERVICEDISCOVERY_HOST") + ":" + os.Getenv("SERVICEDISCOVERY_PORT") 33 | SERVICE_DISCOVERY_GROUP = sc.SERVICE_DISCOVERY_GROUP 34 | ANALYTICS_GROUP = sc.ANALYTICS_GROUP 35 | ELASTICSEARCH_URL = "http://" + os.Getenv("ELASTICSEARCH_HOST") + ":" + os.Getenv("ELASTICSEARCH_PORT") 36 | 37 | return 38 | } 39 | */ 40 | 41 | func LoadURLConstants() { 42 | SERVICE_DISCOVERY_URL = os.Getenv("API_PROTOCOL") + "://" + os.Getenv("SERVICEDISCOVERY_HOST") + ":" + os.Getenv("SERVICEDISCOVERY_PORT") 43 | //SERVICE_DISCOVERY_GROUP = GApiConfiguration.Urls.SERVICE_DISCOVERY_GROUP 44 | //ANALYTICS_GROUP = GApiConfiguration.Urls.ANALYTICS_GROUP 45 | ELASTICSEARCH_URL = "http://" + os.Getenv("ELASTICSEARCH_HOST") + ":" + os.Getenv("ELASTICSEARCH_PORT") 46 | if os.Getenv("ELASTICSEARCH_LOGS_INDEX") != "" { 47 | ELASTICSEARCH_LOGS_INDEX = os.Getenv("ELASTICSEARCH_LOGS_INDEX") 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | API_PROTOCOL=#API_PROTOCOL# 2 | API_MANAGEMENT_PORT=#API_MANAGEMENT_PORT# 3 | API_MANAGEMENT_PORT_EXT=#API_MANAGEMENT_PORT_EXT# 4 | 5 | LOGS_TO_FILE=false 6 | DEBUG=#API_DEBUG_MODE# 7 | 8 | ELASTICSEARCH_LOGS_INDEX=#LOGS_INDEX_ON_ELASTICSEARCH - default: gapi-logs# 9 | 10 | ORACLE_CONNECTION_STRING=#ORACLE_CONNECTION_STRING# 11 | 12 | RABBIT_LISTENER_WORKERS=#RABBIT_LISTENER_NUM_WORKERS - default: 1# 13 | 14 | MONGO_HOST=#MONGO_HOST# 15 | MONGO_DB=#MONGO_DB# 16 | MONGO_PORT=#MONGO_PORT# 17 | MONGO_PORT_EXT=#MONGO_PORT_EXT# 18 | 19 | SOCKET_PORT=#SOCKET_PORT# 20 | SOCKET_PORT_EXT=#SOCKET_PORT_EXT# 21 | FRONTEND_PORT=#FRONTEND_PORT# 22 | FRONTEND_PROTOCOL=#FRONTEND_PROTOCOL# 23 | FRONTEND_CERT_PRIVATE_KEY=#FRONTEND_CERT_PRIVATE_KEY# 24 | FRONTEND_CERT_FILE=#FRONTEND_CERT_FILE# 25 | 26 | RABBITMQ_HOST=#RABBITMQ_HOST# 27 | RABBITMQ_PORT=#RABBITMQ_HOST# 28 | RABBITMQ_PORT_EXT=#RABBITMQ_HOST_EXT# 29 | RABBITMQ_MANAGEMENT_PORT=#RABBITMQ_MANAGEMENT_PORT# 30 | RABBITMQ_MANAGEMENT_PORT_EXT=#RABBITMQ_MANAGEMENT_PORT_EXT# 31 | RABBITMQ_USER=#RABBITMQ_USER# 32 | RABBITMQ_PASSWORD=#RABBITMQ_PASSWORD# 33 | RABBITMQ_QUEUE=#RABBITMQ_QUEUE# 34 | 35 | ELASTICSEARCH_HOST=#ELASTICSEARCH_HOST# 36 | ELASTICSEARCH_PORT=#ELASTICSEARCH_PORT# 37 | ELASTICSEARCH_PORT_EXT=#ELASTICSEARCH_PORT_EXT# 38 | ELASTICSEARCH_ALT_PORT=#ELASTICSEARCH_ALT_PORT# 39 | ELASTICSEARCH_ALT_PORT_EXT=#ELASTICSEARCH_ALT_PORT_EXT# 40 | 41 | RABBITMQ_ERLANG_COOKIE=#RABBITMQ_ERLANG_COOKIE# 42 | RABBITMQ_DEFAULT_USER=#RABBITMQ_DEFAULT_USER# 43 | RABBITMQ_DEFAULT_PASS=#RABBITMQ_DEFAULT_PASS# 44 | RABBITMQ_DEFAULT_VHOST=#RABBITMQ_DEFAULT_VHOST# 45 | 46 | # Dashboard related environment variables 47 | API_PROTOCOL=#API_PROTOCOL# 48 | API_HOST=#API_HOST# 49 | API_PORT=#API_PORT# 50 | SOCKET_HOST=#SOCKET_HOST# 51 | SOCKET_PORT=#SOCKET_PORT# -------------------------------------------------------------------------------- /dashboard/src/components/modals/ConfirmationModal.vue: -------------------------------------------------------------------------------- 1 | 26 | 51 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/apps-groups/actions.js: -------------------------------------------------------------------------------- 1 | const serviceDiscoveryAPI = require("@/api/service-discovery"); 2 | 3 | export const fetchGroups = ({ commit }) => { 4 | serviceDiscoveryAPI.listAppsGroups(response => { 5 | commit("updateGroups", response.body); 6 | }); 7 | }; 8 | 9 | export const updateGroup = ({ commit }, group) => { 10 | serviceDiscoveryAPI.updateAppsGroup(group, response => { 11 | commit("updateGroup", response.body); 12 | }); 13 | }; 14 | 15 | export const deleteGroup = ({ commit }, group) => { 16 | serviceDiscoveryAPI.deleteAppsGroup(group.Id, response => { 17 | if (response.status === 200) commit("groupDeleted", group); 18 | }); 19 | }; 20 | 21 | export const associateServiceToAppGroup = ({ commit }, payload) => { 22 | // TODO 23 | serviceDiscoveryAPI.addServiceToAppsGroup( 24 | payload.GroupId, 25 | payload.ServiceId, 26 | response => { 27 | // if (response.status === 200) commit('groupDeleted', group) 28 | } 29 | ); 30 | }; 31 | 32 | export const deassociateServiceFromAppGroup = ({ commit }, payload) => { 33 | // TODO 34 | serviceDiscoveryAPI.deassociateServiceFromAppsGroup( 35 | payload.GroupId, 36 | payload.ServiceId, 37 | response => { 38 | // if (response.status === 200) commit('groupDeleted', group) 39 | } 40 | ); 41 | }; 42 | 43 | export const listUngroupedApplications = ({ commit }) => { 44 | // TODO 45 | serviceDiscoveryAPI.listUngroupedApps(response => { 46 | if (response.status === 200) commit("ungroupedApplications", response.body); 47 | }); 48 | }; 49 | 50 | export const findPossibleMatches = ({ commit }, sg) => { 51 | // TODO 52 | serviceDiscoveryAPI.findPossibleMatches(sg.Name, response => { 53 | if (response.status === 200) commit("possibleMatches", response.body); 54 | }); 55 | }; 56 | -------------------------------------------------------------------------------- /dashboard/src/views/Service/ServiceLogs.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 32 | 33 | 65 | -------------------------------------------------------------------------------- /api/servicediscovery/appgroups/app-group-repository.go: -------------------------------------------------------------------------------- 1 | package appgroups 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/database" 5 | "github.com/Glintt/gAPI/api/servicediscovery/constants" 6 | "github.com/Glintt/gAPI/api/servicediscovery/service" 7 | userModels "github.com/Glintt/gAPI/api/users/models" 8 | ) 9 | 10 | type AppGroupRepository interface { 11 | UpdateApplicationGroup(appGroupID string, newGroup ApplicationGroup) error 12 | FindServiceApplicationGroup(serviceID string) ApplicationGroup 13 | CreateApplicationGroup(bodyMap ApplicationGroup) error 14 | GetApplicationGroups(page int, nameFilter string) []ApplicationGroup 15 | GetApplicationGroupByID(appGroupID string) (ApplicationGroup, error) 16 | GetServicesForApplicationGroup(appGroup ApplicationGroup) ([]service.Service, error) 17 | DeleteApplicationGroup(appGroupID string) error 18 | AddServiceToGroup(appGroupID string, serviceID string) error 19 | RemoveServiceFromGroup(appGroupID string, serviceID string) error 20 | UngroupedServices() []service.Service 21 | 22 | OpenTransaction() error 23 | CommitTransaction() 24 | RollbackTransaction() 25 | Release() 26 | } 27 | 28 | // NewAppGroupRepository create an application group repository based on the database 29 | func NewAppGroupRepository(user userModels.User) AppGroupRepository { 30 | if database.SD_TYPE == "mongo" { 31 | session, db := database.GetSessionAndDB(database.MONGO_DB) 32 | collection := db.C(constants.SERVICE_APPS_GROUP_COLLECTION) 33 | 34 | return &AppGroupMongoRepository{ 35 | Session: session, 36 | Db: db, 37 | Collection: collection, 38 | } 39 | } 40 | if database.SD_TYPE == "oracle" { 41 | db, err := database.ConnectToOracle(database.ORACLE_CONNECTION_STRING) 42 | if err != nil { 43 | return nil 44 | } 45 | return &AppGroupOracleRepository{ 46 | Db: db, 47 | DbError: err, 48 | } 49 | } 50 | return nil 51 | } 52 | -------------------------------------------------------------------------------- /api/sockets/listener.go: -------------------------------------------------------------------------------- 1 | package sockets 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "os" 7 | 8 | "github.com/Glintt/gAPI/api/config" 9 | "github.com/Glintt/gAPI/api/utils" 10 | 11 | "github.com/rs/cors" 12 | 13 | gosocketio "github.com/graarh/golang-socketio" 14 | "github.com/graarh/golang-socketio/transport" 15 | ) 16 | 17 | var SocketsConnected []*gosocketio.Channel 18 | 19 | func SocketListen() { 20 | port := os.Getenv("SOCKET_PORT") 21 | 22 | if port == "" { 23 | port = config.SOCKET_PORT_DEFAULT 24 | } 25 | 26 | server := gosocketio.NewServer(transport.GetDefaultWebsocketTransport()) 27 | 28 | server.On(gosocketio.OnConnection, func(c *gosocketio.Channel) { 29 | SocketsConnected = append(SocketsConnected, c) 30 | }) 31 | 32 | server.On(gosocketio.OnDisconnection, func(c *gosocketio.Channel) { 33 | var SocketsConnectedTemp []*gosocketio.Channel 34 | for _, element := range SocketsConnected { 35 | if element.Id() != c.Id() { 36 | SocketsConnectedTemp = append(SocketsConnectedTemp, element) 37 | } 38 | SocketsConnected = SocketsConnectedTemp 39 | } 40 | }) 41 | //error catching handler 42 | server.On(gosocketio.OnError, func(c *gosocketio.Channel) { 43 | var SocketsConnectedTemp []*gosocketio.Channel 44 | for _, element := range SocketsConnected { 45 | if element.Id() != c.Id() { 46 | SocketsConnectedTemp = append(SocketsConnectedTemp, element) 47 | } 48 | SocketsConnected = SocketsConnectedTemp 49 | } 50 | }) 51 | 52 | mux := http.NewServeMux() 53 | c := cors.New(cors.Options{ 54 | AllowedOrigins: config.GApiConfiguration.Cors.AllowedOrigins, 55 | AllowCredentials: config.GApiConfiguration.Cors.AllowCredentials, 56 | }) 57 | 58 | handler := c.Handler(mux) 59 | mux.Handle("/socket.io/", server) 60 | 61 | utils.LogMessage("WS PORT = "+port, utils.InfoLogType) 62 | log.Fatal(http.ListenAndServe(":"+port, handler)) 63 | } 64 | -------------------------------------------------------------------------------- /api/server/migrations/oracle/1557849123707_create_services_table.sql: -------------------------------------------------------------------------------- 1 | /* Formatted on 5/14/2019 4:52:35 PM (QP5 v5.206) */ 2 | -- Start of DDL Script for Table GPLATFORM.GAPI_SERVICES 3 | -- Generated 5/14/2019 4:52:32 PM from GPLATFORM@HSDEV 4 | 5 | CREATE TABLE gapi_services 6 | ( 7 | id VARCHAR2 (255), 8 | identifier VARCHAR2 (255), 9 | name VARCHAR2 (255), 10 | matchinguri VARCHAR2 (500), 11 | matchinguriregex VARCHAR2 (500), 12 | touri VARCHAR2 (500), 13 | protected NUMBER (1, 0) DEFAULT 0, 14 | apidocumentation VARCHAR2 (500), 15 | iscachingactive NUMBER (1, 0) DEFAULT 0, 16 | isactive NUMBER (1, 0) DEFAULT 1, 17 | healthcheckurl VARCHAR2 (500), 18 | lastactivetime NUMBER, 19 | servicemanagementhost VARCHAR2 (250), 20 | servicemanagementport VARCHAR2 (250), 21 | ratelimit NUMBER, 22 | ratelimitexpirationtime NUMBER, 23 | isreachable NUMBER (1, 0) DEFAULT 0, 24 | groupid VARCHAR2 (255), 25 | usegroupattributes NUMBER (1, 0) DEFAULT 0, 26 | protectedexclude CLOB, 27 | hosts CLOB, 28 | servicemanagementendpoints CLOB, 29 | applicationgroupid VARCHAR2 (255), 30 | 31 | CONSTRAINT gapiserv_id UNIQUE (id), 32 | CONSTRAINT gapiserv_identifier UNIQUE (identifier), 33 | CONSTRAINT gapiserv_uri UNIQUE (matchinguri), 34 | CONSTRAINT gapiserv_urireg UNIQUE (matchinguriregex), 35 | CONSTRAINT fk_gapi_service_groupid FOREIGN KEY (groupid) REFERENCES gapi_services_groups (id) ON DELETE SET NULL, 36 | CONSTRAINT fk_gapi_appgroupid FOREIGN KEY (applicationgroupid) REFERENCES gapi_services_apps_groups (id) ON DELETE SET NULL 37 | ) 38 | -------------------------------------------------------------------------------- /api/database/mongo.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "strconv" 5 | "os" 6 | "github.com/Glintt/gAPI/api/utils" 7 | "gopkg.in/mgo.v2" 8 | ) 9 | 10 | type MongoPool struct { 11 | BaseSession *mgo.Session 12 | Queue chan int 13 | URL string 14 | Open int 15 | } 16 | var MongoDBPool MongoPool 17 | 18 | 19 | func GetSessionAndDB(db string) (*mgo.Session, *mgo.Database) { 20 | session := GetSession() 21 | dbConn := GetDB(session, db) 22 | 23 | return session, dbConn 24 | } 25 | 26 | func (mp *MongoPool) New() error { 27 | var err error 28 | maxPool := 50 29 | if os.Getenv("MONGO_DB_CONN_POOL") != "" { 30 | maxPool, _ = strconv.Atoi(os.Getenv("MONGO_DB_CONN_POOL")) 31 | } 32 | mp.Queue = make(chan int, maxPool) 33 | for i := 0; i < maxPool; i = i + 1 { 34 | mp.Queue <- 1 35 | } 36 | mp.Open = 0 37 | mp.BaseSession, err = mgo.Dial(mp.URL) 38 | 39 | return err 40 | } 41 | 42 | func (mp *MongoPool) Session() *mgo.Session { 43 | defer utils.PreventCrash() 44 | 45 | <- mp.Queue 46 | if mp.BaseSession == nil { 47 | mp.BaseSession, _ = mgo.Dial(mp.URL) 48 | } 49 | mp.Open++ 50 | return mp.BaseSession.Clone() 51 | } 52 | func (mp *MongoPool) Close(session *mgo.Session) { 53 | session.Close() 54 | 55 | mp.Queue <- 1 56 | mp.Open-- 57 | } 58 | 59 | 60 | func ConnectToMongo(host string) error{ 61 | var err error 62 | MongoDBPool.URL = host 63 | err = MongoDBPool.New() 64 | 65 | if err != nil { 66 | utils.LogMessage("error connecting to mongo on " + host + ". Err: " + err.Error(), utils.ErrorLogType) 67 | } else { 68 | utils.LogMessage("connected to mongo on " + host, utils.InfoLogType) 69 | } 70 | 71 | return err 72 | } 73 | 74 | func GetSession() *mgo.Session { 75 | return MongoDBPool.Session() 76 | } 77 | 78 | func GetDB(session *mgo.Session, db string) *mgo.Database { 79 | return session.DB(db) 80 | } 81 | 82 | func Query(q interface{}) error { 83 | 84 | return nil 85 | } 86 | -------------------------------------------------------------------------------- /api/thirdpartyauthentication/oauth.go: -------------------------------------------------------------------------------- 1 | package thirdpartyauthentication 2 | 3 | import ( 4 | "errors" 5 | "github.com/Glintt/gAPI/api/utils" 6 | 7 | // "github.com/Glintt/gAPI/api/config" 8 | // "github.com/Glintt/gAPI/api/config" 9 | "github.com/Glintt/gAPI/api/http" 10 | 11 | "github.com/valyala/fasthttp" 12 | ) 13 | 14 | type OAuthServer struct { 15 | Host string 16 | Port string 17 | AuthorizeEndpoint string 18 | UserTokenInformation UserTokenInformation 19 | } 20 | 21 | func GetAuthorizeEndpointUrl(oas OAuthServer) string { 22 | return oas.Host + ":" + oas.Port + oas.AuthorizeEndpoint 23 | } 24 | 25 | /* 26 | func LoadFromConfig() OAuthServer { 27 | authenticationJSON, err := utils.LoadJsonFile(config.CONFIGS_LOCATION + config.AUTHENTICATION_CONFIG_FILE) 28 | 29 | if err != nil { 30 | return OAuthServer{} 31 | } 32 | 33 | var oas OAuthServer 34 | json.Unmarshal(authenticationJSON, &oas) 35 | 36 | oas.AuthorizeEndpoint = oas.Host + ":" + oas.Port + oas.AuthorizeEndpoint 37 | return oas 38 | } */ 39 | 40 | func (oauthServer *OAuthServer) Authorize(request fasthttp.Request) (string, string, error) { 41 | 42 | token := request.Header.Peek("Authorization") 43 | 44 | if token == nil { 45 | return "", "", errors.New("Not Authorized.") 46 | } 47 | 48 | // TODO: send on header 49 | var headers map[string]string 50 | headers = make(map[string]string) 51 | headers["Authorization"] = string(token) 52 | 53 | utils.LogMessage("ThirdPartyOAuth (AuthorizationEndpoint) : "+oauthServer.AuthorizeEndpoint, utils.DebugLogType) 54 | 55 | response := http.MakeRequest("GET", oauthServer.AuthorizeEndpoint, "", headers) 56 | 57 | if response.StatusCode() != 200 { 58 | return "", "", errors.New("Not Authorized.") 59 | } 60 | 61 | if oauthServer.UserTokenInformation.Active { 62 | return oauthServer.UserTokenInformation.Name, string(response.Header.Peek(oauthServer.UserTokenInformation.Name)), nil 63 | } 64 | 65 | return "token", "valid", nil 66 | } 67 | -------------------------------------------------------------------------------- /dashboard/src/views/Analytics/ByApi.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 65 | -------------------------------------------------------------------------------- /dashboard/src/store/modules/users/actions.js: -------------------------------------------------------------------------------- 1 | const usersAPI = require("@/api/users"); 2 | 3 | export const updateList = ({ commit }, payload) => { 4 | if (payload === undefined) { 5 | payload = { 6 | query: "", 7 | page: 1 8 | }; 9 | } 10 | usersAPI.find(payload.query, payload.page, response => { 11 | commit("usersListUpdated", response.body); 12 | }); 13 | }; 14 | 15 | export const changeUser = ({ commit }, user) => { 16 | commit("changeUser", user); 17 | }; 18 | 19 | export const emptyUser = ({ commit }) => { 20 | commit("changeUser", { 21 | Username: "", 22 | Password: "", 23 | Email: "", 24 | IsAdmin: false 25 | }); 26 | }; 27 | 28 | export const createUser = ({ commit }, user) => { 29 | usersAPI.create(user, response => { 30 | if (response.status !== 201) { 31 | commit("newAlert", { msg: "Error creating user", classType: "danger" }); 32 | } else { 33 | commit("newAlert", { 34 | msg: "User created successfuly", 35 | classType: "success" 36 | }); 37 | } 38 | }); 39 | }; 40 | 41 | export const updateUserWithAdmin = ({ commit, state }) => { 42 | usersAPI.updateByAdmin(state.user, response => { 43 | if (response.status !== 200) { 44 | commit("newAlert", { msg: "Error updating user", classType: "danger" }); 45 | } else { 46 | commit("newAlert", { 47 | msg: "User updated successfuly", 48 | classType: "success" 49 | }); 50 | } 51 | }); 52 | }; 53 | 54 | export const updateUser = ({ commit, state }) => { 55 | usersAPI.update(state.user, response => { 56 | if (response.status !== 200) { 57 | commit("newAlert", { msg: "Error updating user", classType: "danger" }); 58 | } else { 59 | commit("newAlert", { 60 | msg: "User updated successfuly", 61 | classType: "success" 62 | }); 63 | } 64 | }); 65 | }; 66 | 67 | export const closeAlert = ({ commit }) => { 68 | commit("closeAlert"); 69 | }; 70 | -------------------------------------------------------------------------------- /docs/service-management.md: -------------------------------------------------------------------------------- 1 | ## Service Management Module 2 | 3 | gAPI has a module that allows to integrate external service management services. 4 | This module is highly scalable and flexible allowing to easily add new management feature in an easy way. 5 | 6 | Currently, gAPI configuration example contains the following features to manage each service: 7 | 8 | 1. Stop a service 9 | 2. Restart a service 10 | 3. Redeploy a service 11 | 4. Backup a service version 12 | 5. View service internal logs 13 | 14 | ### How it works 15 | 16 | Currently, in order to manage each service, gAPI needs to interact with another services which are responsible for implementing each of the features. These services must be implemented by service manager. 17 | 18 | Each feature is linked to an endpoint which will be called when the feature is used: 19 | 20 | 1. Stop a service - UndeployEndpoint 21 | 2. Restart a service - RestartEndpoint 22 | 3. Redeploy a service - RedeployEndpoint 23 | 4. Backup a service version - BackupEndpoint 24 | 5. View service internal logs - LogsEndpoint 25 | 26 | All the features share the same host and port and, as consequence, for a single service, these endpoints must be exposed on the same host and port: 27 | 28 | 1. Host - ServiceManagementHost 29 | 2. Port - ServiceManagementPort 30 | 31 | ### Implementation 32 | 33 | #### Adding more managing features 34 | 35 | In order to add new features, you just need to add a new entry to management types map (_ManagementTypes_). This map is located inside the configuration file (_/api/configs/gAPI.json_) 36 | 37 | Example: 38 | 39 | ``` 40 | "feature_name" : { 41 | "action": "feature_name", 42 | "method": "POST", 43 | "icon": "fas fa-sync", 44 | "background": "info", 45 | "description": "feature_name service" 46 | } 47 | ``` 48 | 49 | If you need to handle the new feature in a custom way inside the dashboard, you need to add an to _CustomManagementActions_ list with the new feature name. This list is located at: _/dashboard/src/api/service-discovery.js_ 50 | -------------------------------------------------------------------------------- /api/database/migrations/oracle.go: -------------------------------------------------------------------------------- 1 | package migrations 2 | 3 | import ( 4 | "database/sql" 5 | "io/ioutil" 6 | "log" 7 | "os" 8 | 9 | "github.com/Glintt/gAPI/api/utils" 10 | ) 11 | 12 | const oracleMigrationFolder = "./migrations/oracle" 13 | 14 | const ( 15 | MIGRATION_EXISTS = `select * from gapi_migrations where rownum = 1` 16 | MIGRATION_ALREADY_RUN = `select COUNT(*) from gapi_migrations where id = :id` 17 | CREATE_MIGRATIONS_TABLE = `create table gapi_migrations ( 18 | id VARCHAR2(255), 19 | created_at DATE DEFAULT (sysdate) 20 | )` 21 | ADD_RUN_MIGRATION = `insert into gapi_migrations(id, created_at) values (:id, DEFAULT)` 22 | ) 23 | 24 | const RUN_MIGRATION_ENV_VAR = "RUN_MIGRATIONS" 25 | 26 | func MigrateOracle(connectionString string) { 27 | if os.Getenv(RUN_MIGRATION_ENV_VAR) != "true" { 28 | return 29 | } 30 | 31 | db, err := sql.Open("goracle", connectionString) 32 | 33 | files, err := ioutil.ReadDir(oracleMigrationFolder) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | 38 | utils.LogMessage("==== RUNNING MIGRATIONS ====", utils.InfoLogType) 39 | 40 | _, err = db.Exec(CREATE_MIGRATIONS_TABLE) 41 | if err != nil { 42 | _, err = db.Exec(MIGRATION_EXISTS) 43 | if err != nil { 44 | utils.LogMessage("error creating migration table: "+err.Error(), utils.InfoLogType) 45 | return 46 | } 47 | } 48 | 49 | for _, f := range files { 50 | migrationID := f.Name() 51 | rows, err := db.Query(MIGRATION_ALREADY_RUN, migrationID) 52 | 53 | count := checkCount(rows) 54 | if count > 0 { 55 | continue 56 | } 57 | 58 | dat, _ := ioutil.ReadFile(oracleMigrationFolder + "/" + f.Name()) 59 | 60 | utils.LogMessage(" -----> "+migrationID, utils.InfoLogType) 61 | _, err = db.Exec(string(dat)) 62 | if err != nil { 63 | log.Fatal(err.Error()) 64 | } 65 | _, err = db.Exec(ADD_RUN_MIGRATION, migrationID) 66 | } 67 | 68 | utils.LogMessage("==== MIGRATIONS FINISHED RUNNING ====", utils.InfoLogType) 69 | 70 | defer db.Close() 71 | } 72 | 73 | func checkCount(rows *sql.Rows) (count int) { 74 | c := 0 75 | for rows.Next() { 76 | rows.Scan(&c) 77 | } 78 | return c 79 | } 80 | -------------------------------------------------------------------------------- /api/servicediscovery/validator.go: -------------------------------------------------------------------------------- 1 | package servicediscovery 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "github.com/Glintt/gAPI/api/servicediscovery/service" 7 | "github.com/Glintt/gAPI/api/servicediscovery/servicegroup" 8 | 9 | "gopkg.in/mgo.v2/bson" 10 | routing "github.com/qiangxue/fasthttp-routing" 11 | ) 12 | 13 | func ValidateServiceGroupBody(c *routing.Context) (servicegroup.ServiceGroup, error) { 14 | var s servicegroup.ServiceGroup 15 | err := json.Unmarshal(c.Request.Body(), &s) 16 | 17 | if s.Name == "" { 18 | return servicegroup.ServiceGroup{}, errors.New(`{"error" : true, "msg": "Missing body parameters."}`) 19 | } 20 | if err != nil { 21 | return servicegroup.ServiceGroup{}, errors.New(`{"error" : true, "msg": "Error parsing body."}`) 22 | } 23 | 24 | return s, nil 25 | } 26 | // ValidateServiceBody validate service request body 27 | func ValidateServiceBody(c *routing.Context) (service.Service, error) { 28 | var s service.Service 29 | err := json.Unmarshal(c.Request.Body(), &s) 30 | 31 | if s.Name == "" || len(s.Hosts) == 0 || s.MatchingURI == "" || s.ToURI == "" || s.APIDocumentation == "" { 32 | return service.Service{}, errors.New("Missing body parameters") 33 | } 34 | if err != nil { 35 | return service.Service{}, errors.New(`Error parsing body`) 36 | } 37 | 38 | s.NormalizeService() 39 | 40 | return s, nil 41 | } 42 | 43 | // ValidateServiceExists validate if service already exists 44 | func ValidateServiceExists(s service.Service) (service.Service, error) { 45 | sd := GetInternalServiceDiscoveryObject() 46 | ser, err := sd.FindService(s) 47 | 48 | if err != nil { 49 | return service.Service{}, errors.New(`Service not found`) 50 | } 51 | 52 | return ser, nil 53 | } 54 | 55 | 56 | // ValidateServiceBodyAndServiceExists validates both request body and if service already exists 57 | func ValidateServiceBodyAndServiceExists(c *routing.Context, serviceID string) (service.Service, int, error) { 58 | s, err := ValidateServiceBody(c) 59 | if err != nil { 60 | return service.Service{}, 400, err 61 | } 62 | 63 | if serviceID != "" { 64 | s.Id = bson.ObjectIdHex(serviceID) 65 | } 66 | 67 | _, err = ValidateServiceExists(s) 68 | if err != nil { 69 | return service.Service{}, 404, err 70 | } 71 | return s, 200, nil 72 | } -------------------------------------------------------------------------------- /dashboard/src/views/Users/ListUsers.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 78 | 79 | 81 | -------------------------------------------------------------------------------- /api/http/httpresponse.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/utils" 5 | 6 | routing "github.com/qiangxue/fasthttp-routing" 7 | ) 8 | 9 | type ResponseInfo struct { 10 | StatusCode int 11 | ContentType []byte 12 | Body []byte 13 | } 14 | 15 | // Response creates the API response structure 16 | func Response(c *routing.Context, response string, statuscode int, service string, contentType string) { 17 | utils.LogMessage("RESPONSE ==> "+response, utils.DebugLogType) 18 | 19 | c.Response.SetBody([]byte(response)) 20 | c.Response.Header.SetContentType(contentType) 21 | c.Response.Header.Set("service", service) 22 | c.Response.Header.SetStatusCode(statuscode) 23 | } 24 | 25 | // Error creates and sends error response 26 | func Error(c *routing.Context, err string, statusCode int, service string) error { 27 | Response(c, `{"error": true, "msg": "` + err + `"}`, statusCode, service, "application/json") 28 | return nil 29 | } 30 | 31 | // Created Creates and sends created response 32 | func Created(c *routing.Context, msg string, service string) error { 33 | Response(c, `{"error": false, "msg": "`+msg+`"}`, 201, service, "application/json") 34 | return nil 35 | } 36 | 37 | // OkFormated creates and send created response 38 | func OkFormated(c *routing.Context, msg string, service string) error { 39 | Response(c, `{"error": false, "msg": "`+msg+`"}`, 200, service, "application/json") 40 | return nil 41 | } 42 | 43 | // Ok creates and send created response 44 | func Ok(c *routing.Context, msg string, service string) error { 45 | Response(c, msg, 200, service, "application/json") 46 | return nil 47 | } 48 | 49 | // Deleted creates and send deleted response 50 | func Deleted(c *routing.Context, msg string, service string) error { 51 | Response(c, `{"error": false, "msg": "`+msg+`"}`, 200, service, "application/json") 52 | return nil 53 | } 54 | 55 | // NotFound creates and send not found response 56 | func NotFound(c *routing.Context, msg string, service string) error { 57 | Response(c, `{"error": true, "msg": "`+msg+`"}`, 404, service, "application/json") 58 | return nil 59 | } 60 | 61 | func NotAuthorized(c *routing.Context, service string) error{ 62 | Response(c, `{"error":true, "msg":"Not Authorized."}`, 401, service, "application/json") 63 | return nil 64 | 65 | } 66 | -------------------------------------------------------------------------------- /api/controllers/gapi.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "runtime" 6 | "strconv" 7 | 8 | "github.com/Glintt/gAPI/api/cache" 9 | "github.com/Glintt/gAPI/api/config" 10 | "github.com/Glintt/gAPI/api/http" 11 | routing "github.com/qiangxue/fasthttp-routing" 12 | "github.com/shirou/gopsutil/cpu" 13 | "github.com/shirou/gopsutil/host" 14 | ) 15 | 16 | func InvalidateCache(c *routing.Context) error { 17 | cache.InvalidateCache() 18 | c.Response.SetBody([]byte(`{"error":false, "msg": "Invalidation finished."}`)) 19 | c.Response.Header.SetContentType("application/json") 20 | return nil 21 | } 22 | 23 | func ReloadServices(c *routing.Context) error { 24 | // InitServices() 25 | 26 | cache.InvalidateCache() 27 | 28 | c.Response.SetBody([]byte(`{"error":false, "msg": "Reloaded successfully."}`)) 29 | c.Response.Header.SetContentType("application/json") 30 | return nil 31 | } 32 | 33 | func ProfileGApiUsage(c *routing.Context) error { 34 | 35 | var profileStats map[string]interface{} 36 | profileStats = make(map[string]interface{}) 37 | 38 | profileStats["OS"] = runtime.GOOS 39 | 40 | // Go Routines 41 | profileStats["GoRoutines"] = runtime.NumGoroutine() 42 | 43 | // Memory Stats 44 | var m runtime.MemStats 45 | runtime.ReadMemStats(&m) 46 | 47 | var memStats map[string]interface{} 48 | memStats = make(map[string]interface{}) 49 | 50 | memStats["Alloc"] = strconv.Itoa(int(bToMb(m.Alloc))) + " Mb" 51 | memStats["TotalAlloc"] = strconv.Itoa(int(bToMb(m.TotalAlloc))) + " Mb" 52 | memStats["Sys"] = strconv.Itoa(int(bToMb(m.Sys))) + " Mb" 53 | memStats["NumGC"] = m.NumGC 54 | profileStats["Memory"] = memStats 55 | 56 | // CPU Stats 57 | cpuStat, _ := cpu.Info() 58 | profileStats["CPU"] = cpuStat 59 | 60 | percentage, _ := cpu.Percent(0, true) 61 | 62 | var cpuUsageMap []string 63 | for _, cpupercent := range percentage { 64 | cpuUsageMap = append(cpuUsageMap, strconv.FormatFloat(cpupercent, 'f', 2, 64)) 65 | } 66 | profileStats["CPU_Usage"] = cpuUsageMap 67 | 68 | // Host Stats 69 | hostStat, _ := host.Info() 70 | profileStats["HostInfo"] = hostStat 71 | 72 | jsonBytes, _ := json.Marshal(profileStats) 73 | 74 | http.Response(c, string(jsonBytes), 200, config.GAPI_SERVICE_NAME, "application/json") 75 | return nil 76 | } 77 | 78 | func bToMb(b uint64) uint64 { 79 | return b / 1024 / 1024 80 | } 81 | -------------------------------------------------------------------------------- /api/plugins/before_request_plugin.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | import ( 4 | "errors" 5 | "github.com/Glintt/gAPI/api/config" 6 | "github.com/Glintt/gAPI/api/http" 7 | "github.com/Glintt/gAPI/api/utils" 8 | "path/filepath" 9 | 10 | "github.com/manucorporat/try" 11 | routing "github.com/qiangxue/fasthttp-routing" 12 | ) 13 | 14 | type BeforeRequestPlugin struct { 15 | Location string 16 | Filename string 17 | } 18 | 19 | func (p *BeforeRequestPlugin) Call(c *routing.Context) error { 20 | generalPlugin := GeneralPlugin{Location: p.Location, Filename: p.Filename} 21 | symReqEntryPlugin, err := generalPlugin.Load(BeforeRequestEntryPluginLookup) 22 | 23 | if err != nil { 24 | utils.LogMessage("BeforeRequestPlugin Call() : "+err.Error(), utils.DebugLogType) 25 | return err 26 | } 27 | 28 | // check if loaded symbol is of desired type 29 | var pluginBefore BeforeRequestEntryPlugin 30 | pluginBefore, ok := symReqEntryPlugin.(BeforeRequestEntryPlugin) 31 | if !ok { 32 | utils.LogMessage("BeforeRequestPlugin Call() : "+err.Error(), utils.DebugLogType) 33 | return err 34 | } 35 | 36 | // call the plugin 37 | err = pluginBefore.Call(c) 38 | 39 | if err != nil { 40 | utils.LogMessage("BeforeRequestPlugin Call() : "+err.Error(), utils.DebugLogType) 41 | return err 42 | } 43 | 44 | return nil 45 | } 46 | 47 | func CallBeforeRequestPlugins(c *routing.Context) error { 48 | allPlugins := Configurations().BeforeRequest 49 | 50 | pluginsLocation := filepath.Join(PLUGINS_LOCATION, BEFORE_REQUEST_PLUGINS_NAME) 51 | 52 | utils.LogMessage("CallBeforeRequestPlugins() - pluginsLocation: "+pluginsLocation, utils.DebugLogType) 53 | 54 | for _, pluginToLoad := range allPlugins { 55 | pluginToCall := BeforeRequestPlugin{Location: pluginsLocation, Filename: pluginToLoad} 56 | 57 | utils.LogMessage("CallBeforeRequestPlugins() - pluginToLoad: "+pluginToLoad, utils.DebugLogType) 58 | var hasStoppingError error 59 | try.This(func() { 60 | hasStoppingError = pluginToCall.Call(c) 61 | }).Catch(func(e try.E) { 62 | hasStoppingError = errors.New("Plugin " + pluginToLoad + " failed.") 63 | utils.LogMessage("CallBeforeRequestPlugins() - pluginCall: error on plugin", utils.DebugLogType) 64 | http.Response(c, `{"error": true, "msg": "`+hasStoppingError.Error()+`"}`, 500, SERVICE_NAME, config.APPLICATION_JSON) 65 | }) 66 | 67 | if hasStoppingError != nil { 68 | return hasStoppingError 69 | } 70 | } 71 | 72 | return nil 73 | } 74 | -------------------------------------------------------------------------------- /dashboard/index.js: -------------------------------------------------------------------------------- 1 | // Server.js, don't forget to add express & ejs to packages 2 | const express = require("express"); 3 | 4 | const fs = require("fs"); 5 | const app = express(); 6 | const port = process.env.PORT || 3003; 7 | const protocol = process.env.FRONTEND_PROTOCOL || "http"; 8 | const router = express.Router(); 9 | 10 | const ApiProtocol = process.env.API_PROTOCOL || "http"; 11 | const ApiHost = process.env.API_HOST || "localhost"; 12 | const ApiPort = process.env.API_PORT || "8080"; 13 | const SocketHost = process.env.SOCKET_HOST || "localhost"; 14 | const SocketPort = process.env.SOCKET_PORT || "5000"; 15 | 16 | const https = require("https"); 17 | const http = require("http"); 18 | 19 | app.use( 20 | express.static(`${__dirname}/dist`, { 21 | setHeaders: res => { 22 | res.setHeader("Api-Base", `${ApiProtocol}://${ApiHost}:${ApiPort}`); 23 | 24 | res.setHeader( 25 | "Socket-Base", 26 | `${ApiProtocol}://${SocketHost}:${SocketPort}` 27 | ); 28 | } 29 | }) 30 | ); 31 | 32 | app.engine(".html", require("ejs").renderFile); 33 | 34 | app.set("views", `${__dirname}/dist`); 35 | 36 | router.get("/assets/:file", (req, res) => { 37 | res.sendFile(`${__dirname}/dist/assets/` + req.params.file); 38 | }); 39 | 40 | var proxy = require("express-http-proxy"); 41 | 42 | router.get("/dashboard/*", (req, res) => { 43 | res.set({ 44 | "Api-Base": `${ApiProtocol}://${ApiHost}:${ApiPort}`, 45 | "Socket-Base": `${ApiProtocol}://${SocketHost}:${SocketPort}` 46 | }); 47 | res.sendFile(`${__dirname}/dist/index.html`); 48 | }); 49 | 50 | app.use("/", router); 51 | 52 | app.use("/", proxy(`${ApiProtocol}://${ApiHost}:${ApiPort}`)); 53 | 54 | switch (protocol) { 55 | case "https": 56 | HttpsListen(); 57 | break; 58 | case "http": 59 | HttpListen(); 60 | break; 61 | default: 62 | HttpListen(); 63 | } 64 | 65 | function HttpsListen() { 66 | var privateKey = fs.readFileSync( 67 | process.env.FRONTEND_CERT_PRIVATE_KEY, 68 | "utf8" 69 | ); 70 | var certificate = fs.readFileSync(process.env.FRONTEND_CERT_FILE, "utf8"); 71 | var credentials = { 72 | key: privateKey, 73 | cert: certificate 74 | }; 75 | 76 | var httpsServer = https.createServer(credentials, app); 77 | httpsServer.listen(port); 78 | 79 | console.log(`App running on port ${port} using HTTPS protocol`); 80 | } 81 | 82 | function HttpListen() { 83 | var httpServer = http.createServer(app); 84 | httpServer.listen(port); 85 | 86 | console.log(`App running on port ${port} using HTTP protocol`); 87 | } -------------------------------------------------------------------------------- /dashboard/src/views/Analytics/Live/LiveRequests.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 86 | 87 | 89 | -------------------------------------------------------------------------------- /docs/services.md: -------------------------------------------------------------------------------- 1 | ## Services 2 | 3 | A service contains the following information: 4 | 5 | - _Identifier_ - unique identifier 6 | - _Name_ - Service name 7 | - _Hosts_ - List of hosts in which the service is hosted. Multiple hosts are allowed for load balancing 8 | - _Domain_ - Default domain 9 | - _Port_ - Default port 10 | - _MatchingURI_ - Unique uri to represent the service 11 | - _MatchingURIRegex_ - Regex to search by MatchingURI 12 | - _ToURI_ - Service base uri 13 | - _Protected_ - If service is protected with OAuth (Boolean) 14 | - _IsCachingActive_ - If caching is enabled (Boolean) 15 | - _IsActive_ - Is service running (Boolean) 16 | - _APIDocumentation_ - API Documentation location 17 | - _HealthcheckUrl_ - URL to call to check if service is running 18 | - _LastActiveTime_ - Last time the service was running (in milliseconds) 19 | - _ServiceManagementHost_ - Service management service host 20 | - _ServiceManagementPort_ - Service management service port 21 | - _ServiceManagementEndpoints_ - Service management service available endpoints 22 | - _RateLimit_ - Global rate limit (rps) 23 | - _RateLimitExpirationTime_ - Global rate limit expiration time (in minutes) 24 | - _IsReachable_ - If micro service is reachable from external requests 25 | - _GroupId_ - Group Id to which the micro service belongs. null if no group 26 | - _GroupVisibility_ - Group Visibility to external requests 27 | - _UseGroupAttributes_ - If the service must use group attributes (currently: visibility) 28 | - _ProtectedExclude_ - remove authentication from some endpoints 29 | 30 | In order to get more information on ServiceManagement part, check [here](./service-management.md) 31 | 32 | In order to get more information on Rate Limiting part, check [here](./rate-limiting.md) 33 | 34 | In order to get more information on Reachability, check [here](./reachability.md) 35 | 36 | #### Matching URI 37 | 38 | The matching uri is used to call the correct service. Currently, it is supported complex URIs with more than one subroute. 39 | 40 | **Example:** 41 | 42 | _/gapi/modules/service-discovery_ calls gapi service discovery component located at _/service-discovery_. Everything that goes after _/service-discovery_ is considered a service endpoint. 43 | 44 | With this configuration, when you call _/gapi/modules/service-discovery/services_ it is called _/service-discovery/services_ on the service host. 45 | 46 | #### Hosts 47 | 48 | Currently, gAPI has a simple load balancing. 49 | 50 | In order to register multiple hosts for a service, you must add an entry with a new host to **Hosts** array. 51 | -------------------------------------------------------------------------------- /api/Dockerfile-rabbitlistener: -------------------------------------------------------------------------------- 1 | FROM golang:1.9 as base 2 | 3 | # Install oracle related software 4 | RUN apt-get update && apt-get install -y unzip vim pkg-config libaio1 wget 5 | 6 | RUN mkdir -p /usr/lib/oracle/18.3/client64/lib && mkdir -p /usr/include/oracle/18.3/client64/ 7 | 8 | RUN wget https://github.com/bumpx/oracle-instantclient/raw/master/instantclient-basic-linux.x64-18.3.0.0.0dbru.zip 9 | RUN wget https://github.com/bumpx/oracle-instantclient/raw/master/instantclient-sdk-linux.x64-18.3.0.0.0dbru.zip 10 | 11 | RUN mv instantclient-basic-linux.x64-18.3.0.0.0dbru.zip /tmp/ 12 | RUN mv instantclient-sdk-linux.x64-18.3.0.0.0dbru.zip /tmp/ 13 | 14 | 15 | RUN cd /tmp && unzip instantclient-basic-linux.x64-18.3.0.0.0dbru.zip 16 | RUN cp -r /tmp/instantclient_18_3/* /usr/lib/oracle/18.3/client64/lib/ 17 | 18 | RUN cd /tmp && unzip instantclient-sdk-linux.x64-18.3.0.0.0dbru.zip 19 | RUN cp -r /tmp/instantclient_18_3/sdk/include/* /usr/include/oracle/18.3/client64/ 20 | 21 | 22 | FROM golang:1.12 as builder 23 | 24 | #COPY --from=dependencies /go/src /go/src 25 | ADD . /go/src/gAPI/api 26 | 27 | WORKDIR /go/src/gAPI/api/rabbit-listener 28 | 29 | ENV GO111MODULE on 30 | 31 | RUN go mod download 32 | 33 | RUN go build -o rabbit-listener 34 | 35 | FROM golang:1.9 36 | 37 | ENV RABBITMQ_HOST localhost 38 | ENV RABBITMQ_PORT 5672 39 | ENV RABBITMQ_USER guest 40 | ENV RABBITMQ_PASSWORD guest 41 | ENV RABBITMQ_QUEUE gAPI-logqueue 42 | 43 | ENV LD_LIBRARY_PATH /usr/lib:/usr/local/lib:/usr/lib/oracle/18.3/client64/lib 44 | 45 | RUN apt-get update && apt-get install -y pkg-config libaio1 46 | 47 | RUN mkdir -p /usr/lib/oracle/18.3/client64/lib && mkdir -p /usr/include/oracle/18.3/client64/ 48 | 49 | COPY --from=base /usr/lib/oracle/ /usr/lib/oracle/ 50 | COPY --from=base /usr/include/oracle/ /usr/include/oracle/ 51 | 52 | #RUN ln -s /usr/lib/oracle/18.3/client64/lib/libclntsh.so.18.1 /usr/lib/oracle/18.3/client64/lib/libclntsh.so 53 | #RUN ln -s /usr/lib/oracle/18.3/client64/lib/libocci.so.18.1 /usr/lib/oracle/18.3/client64/lib/libocci.so 54 | 55 | COPY oci8.pc /usr/lib/pkgconfig/ 56 | 57 | 58 | 59 | COPY --from=builder /go/src/gAPI/api/rabbit-listener/rabbit-listener /go/src/gAPI/api/rabbit-listener 60 | COPY --from=builder /go/src/gAPI/api/generate_config.sh /go/src/gAPI/api/generate_config.sh 61 | 62 | WORKDIR /go/src/gAPI/api 63 | 64 | ARG db=mongo 65 | ARG logs_type=Elastic 66 | ARG queue_type=Internal 67 | 68 | RUN sh generate_config.sh db=$db logs_type=$logs_type queue_type=$queue_type 69 | RUN cat configs/gAPI.json 70 | 71 | CMD ["/go/src/gAPI/api/rabbit-listener"] -------------------------------------------------------------------------------- /api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.9 as base 2 | 3 | # Install oracle related software 4 | RUN apt-get update && apt-get install -y unzip vim pkg-config libaio1 wget 5 | 6 | RUN mkdir -p /usr/lib/oracle/18.3/client64/lib && mkdir -p /usr/include/oracle/18.3/client64/ 7 | 8 | RUN wget https://github.com/bumpx/oracle-instantclient/raw/master/instantclient-basic-linux.x64-18.3.0.0.0dbru.zip 9 | RUN wget https://github.com/bumpx/oracle-instantclient/raw/master/instantclient-sdk-linux.x64-18.3.0.0.0dbru.zip 10 | 11 | RUN mv instantclient-basic-linux.x64-18.3.0.0.0dbru.zip /tmp/ 12 | RUN mv instantclient-sdk-linux.x64-18.3.0.0.0dbru.zip /tmp/ 13 | 14 | RUN cd /tmp && unzip instantclient-basic-linux.x64-18.3.0.0.0dbru.zip 15 | RUN cp -r /tmp/instantclient_18_3/* /usr/lib/oracle/18.3/client64/lib/ 16 | 17 | RUN cd /tmp && unzip instantclient-sdk-linux.x64-18.3.0.0.0dbru.zip 18 | RUN cp -r /tmp/instantclient_18_3/sdk/include/* /usr/include/oracle/18.3/client64/ 19 | 20 | ### Build API 21 | FROM golang:1.12 as builder 22 | 23 | #COPY --from=dependencies /go/src /go/src 24 | ADD . /go/src/gAPI/api 25 | 26 | WORKDIR /go/src/gAPI/api/server 27 | 28 | ENV GO111MODULE on 29 | 30 | RUN go mod download 31 | 32 | RUN go build -o server 33 | 34 | ### Create final image 35 | FROM golang:1.12 36 | 37 | ENV RABBITMQ_HOST rabbit 38 | ENV RABBITMQ_PORT 5672 39 | ENV RABBITMQ_USER gapi 40 | ENV RABBITMQ_PASSWORD gapi 41 | ENV RABBITMQ_QUEUE gAPI-logqueue 42 | 43 | ENV LD_LIBRARY_PATH /usr/lib:/usr/local/lib:/usr/lib/oracle/18.3/client64/lib 44 | 45 | # 1. Install oracle 46 | RUN apt-get update && apt-get install -y pkg-config libaio1 47 | 48 | RUN mkdir -p /usr/lib/oracle/18.3/client64/lib && mkdir -p /usr/include/oracle/18.3/client64/ 49 | 50 | COPY --from=base /usr/lib/oracle/ /usr/lib/oracle/ 51 | COPY --from=base /usr/include/oracle/ /usr/include/oracle/ 52 | 53 | #RUN ln -s /usr/lib/oracle/18.3/client64/lib/libclntsh.so.18.1 /usr/lib/oracle/18.3/client64/lib/libclntsh.so 54 | #RUN ln -s /usr/lib/oracle/18.3/client64/lib/libocci.so.18.1 /usr/lib/oracle/18.3/client64/lib/libocci.so 55 | 56 | COPY oci8.pc /usr/lib/pkgconfig/ 57 | 58 | # 2. Copy api runtime and configs 59 | COPY --from=builder /go/src/gAPI/api/server/server /go/src/gAPI/api/server 60 | COPY --from=builder /go/src/gAPI/api/server/migrations /go/src/gAPI/api/migrations 61 | COPY --from=builder /go/src/gAPI/api/generate_config.sh /go/src/gAPI/api/generate_config.sh 62 | 63 | WORKDIR /go/src/gAPI/api 64 | 65 | ARG db=mongo 66 | ARG logs_type=Elastic 67 | ARG queue_type=Internal 68 | 69 | RUN sh generate_config.sh db=$db logs_type=$logs_type queue_type=$queue_type 70 | RUN cat configs/gAPI.json 71 | 72 | CMD ["/go/src/gAPI/api/server"] -------------------------------------------------------------------------------- /api/controllers/authentication.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/config" 5 | "github.com/Glintt/gAPI/api/http" 6 | "github.com/Glintt/gAPI/api/authentication" 7 | auth "github.com/Glintt/gAPI/api/authentication" 8 | routing "github.com/qiangxue/fasthttp-routing" 9 | "strconv" 10 | "encoding/json" 11 | ) 12 | 13 | func GetTokenHandler(c *routing.Context) error { 14 | c.Response.Header.SetContentType("application/json") 15 | tokenRequestBody := c.Request.Body() 16 | var tokenRequestObj auth.TokenRequestObj 17 | json.Unmarshal(tokenRequestBody, &tokenRequestObj) 18 | 19 | token, err := auth.GenerateToken(tokenRequestObj.Username, tokenRequestObj.Password) 20 | 21 | if err != nil { 22 | http.Response(c,`{"error":true, "msg":"` + err.Error() + `"}`, 401, authentication.SERVICE_NAME, config.APPLICATION_JSON) 23 | return nil 24 | } 25 | http.Response(c,`{"token":"` + token + `", "expiration_time": ` + strconv.Itoa(auth.EXPIRATION_TIME) +`}`, 200, authentication.SERVICE_NAME, config.APPLICATION_JSON) 26 | return nil 27 | } 28 | 29 | func MeHandler(c *routing.Context) error { 30 | c.Response.Header.SetContentType("application/json") 31 | authorizationToken := c.Request.Header.Peek("Authorization") 32 | 33 | tokenClaims, err := auth.ValidateToken(string(authorizationToken)) 34 | 35 | if err != nil{ 36 | http.Response(c, `{"error":true, "msg":"`+ err.Error() + `"}`, 400, authentication.SERVICE_NAME, config.APPLICATION_JSON) 37 | return nil 38 | } 39 | 40 | username := tokenClaims["Username"].(string) 41 | 42 | userService := getUserService(c) 43 | usersList := userService.GetUserByUsername(username) 44 | 45 | if len(usersList) == 0 || len(usersList) > 1 { 46 | http.Response(c, `{"error":true, "msg":"User not found."}`, 404, authentication.SERVICE_NAME, config.APPLICATION_JSON) 47 | return nil 48 | } 49 | 50 | usersList[0].Password = "" 51 | userJSON,_ := json.Marshal(usersList[0]) 52 | http.Response(c, string(userJSON), 200, authentication.SERVICE_NAME, config.APPLICATION_JSON) 53 | return nil 54 | } 55 | 56 | func AuthorizeTokenHandler(c *routing.Context) error { 57 | c.Response.Header.SetContentType("application/json") 58 | authorizationToken := c.Request.Header.Peek("Authorization") 59 | 60 | _, err := auth.ValidateToken(string(authorizationToken)) 61 | 62 | if err != nil{ 63 | http.Response(c, `{"error":true, "msg":"`+ err.Error() + `"}`, 401, authentication.SERVICE_NAME, config.APPLICATION_JSON) 64 | return nil 65 | } 66 | http.Response(c, `{"error":false, "msg":"Token is valid."}`, 200, authentication.SERVICE_NAME, config.APPLICATION_JSON) 67 | 68 | return nil 69 | } -------------------------------------------------------------------------------- /dashboard/src/views/ServiceDiscovery/ListServicesGroup.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 69 | 70 | 72 | -------------------------------------------------------------------------------- /api/users/userservice.go: -------------------------------------------------------------------------------- 1 | package users 2 | 3 | import ( 4 | "github.com/Glintt/gAPI/api/users/models" 5 | "github.com/Glintt/gAPI/api/users/providers" 6 | "github.com/Glintt/gAPI/api/utils" 7 | "gopkg.in/mgo.v2/bson" 8 | "errors" 9 | ) 10 | const ( 11 | SERVICE_NAME = "gapi_users" 12 | ) 13 | 14 | type UserService struct { 15 | User models.User 16 | UserRepos providers.UserRepository 17 | } 18 | 19 | // InitUsers init users service 20 | func InitUsers() { 21 | userService := UserService{User: models.GetInternalAPIUser()} 22 | userService.createRepository() 23 | userService.UserRepos.OpenTransaction() 24 | 25 | userService.UserRepos.InitUsers() 26 | 27 | err := userService.CreateUser(models.User{Username: "admin", Email: "admin@gapi.com", Password: "admin", IsAdmin: true}) 28 | if err != nil { 29 | utils.LogMessage(err.Error(), utils.ErrorLogType) 30 | } 31 | releaseConnection(&userService) 32 | } 33 | 34 | // NewUserServiceWithUser create user service 35 | func NewUserServiceWithUser(user models.User) (UserService, error) { 36 | userServ := UserService{User: user} 37 | err := userServ.createRepository() 38 | return userServ, err 39 | } 40 | 41 | func releaseConnection(us *UserService) { 42 | us.UserRepos.CommitTransaction() 43 | us.UserRepos.Release() 44 | } 45 | 46 | func (us *UserService) createRepository() error { 47 | us.UserRepos = providers.NewUserRepository(us.User) 48 | if us.UserRepos == nil { 49 | return errors.New("Could not get application group repository") 50 | } 51 | us.UserRepos.OpenTransaction() 52 | return nil 53 | } 54 | 55 | // CreateUser creates a new user 56 | func (us *UserService) CreateUser(user models.User) error { 57 | us.UserRepos.OpenTransaction() 58 | hashedPwd, _ := models.GeneratePassword(user.Password) 59 | user.Password = string(hashedPwd) 60 | user.Id = bson.NewObjectId() 61 | 62 | err := us.UserRepos.CreateUser(user) 63 | releaseConnection(us) 64 | return err 65 | } 66 | 67 | // UpdateUser update an existing user 68 | func (us *UserService) UpdateUser(user models.User) error { 69 | us.UserRepos.OpenTransaction() 70 | err := us.UserRepos.UpdateUser(user) 71 | releaseConnection(us) 72 | return err 73 | } 74 | // FindUsersByUsernameOrEmail search user by email or username 75 | func (us *UserService) FindUsersByUsernameOrEmail(q string, page int) []models.User { 76 | us.UserRepos.OpenTransaction() 77 | users := us.UserRepos.FindUsersByUsernameOrEmail(q, page) 78 | releaseConnection(us) 79 | return users 80 | } 81 | // GetUserByUsername search user by username 82 | func (us *UserService) GetUserByUsername(username string) []models.User { 83 | us.UserRepos.OpenTransaction() 84 | users := us.UserRepos.GetUserByUsername(username) 85 | releaseConnection(us) 86 | return users 87 | } 88 | -------------------------------------------------------------------------------- /api/controllers/api_documentation.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "io/ioutil" 5 | "net/http" 6 | "crypto/tls" 7 | netUrl "net/url" 8 | "path" 9 | "strings" 10 | 11 | gapiHttp "github.com/Glintt/gAPI/api/http" 12 | "github.com/Glintt/gAPI/api/servicediscovery" 13 | "github.com/Glintt/gAPI/api/servicediscovery/service" 14 | "github.com/Glintt/gAPI/api/utils" 15 | 16 | routing "github.com/qiangxue/fasthttp-routing" 17 | ) 18 | 19 | func HandleServiceDocumentationRequest(c *routing.Context) error { 20 | url, err := GetServiceDocumentationUrl(c.Param("service_name")) 21 | if err != nil { 22 | gapiHttp.Response(c, "Not found", 404, "", "text/html") 23 | return nil 24 | } 25 | 26 | response, responseString, err := GetHtml(url) 27 | if err != nil { 28 | gapiHttp.Response(c, responseString, 500, "", "text/html") 29 | return nil 30 | } 31 | gapiHttp.Response(c, responseString, 200, "", response.Header.Get("Content-Type")) 32 | 33 | return nil 34 | } 35 | 36 | func HandleServiceDocumentationJSRequest(c *routing.Context) error { 37 | serviceIdentifier := c.Param("service_name") 38 | url, err := GetServiceDocumentationUrl(serviceIdentifier) 39 | 40 | if err != nil { 41 | gapiHttp.Response(c, "Not found", 404, "", "text/html") 42 | return nil 43 | } 44 | 45 | uri := strings.Replace(string(c.Request.RequestURI()), "/api_docs/"+serviceIdentifier+"/", "", -1) 46 | u, _ := netUrl.Parse(url) 47 | 48 | uri = path.Join(u.Path, uri) 49 | url = u.Scheme + "://" + u.Host + uri 50 | 51 | response, responseString, err := GetHtml(url) 52 | if err != nil { 53 | gapiHttp.Response(c, responseString, 500, "", "text/html") 54 | return nil 55 | } 56 | 57 | gapiHttp.Response(c, responseString, 200, "", response.Header.Get("Content-Type")) 58 | 59 | return nil 60 | } 61 | 62 | func GetServiceDocumentationUrl(serviceIdentifier string) (string, error) { 63 | service, err := servicediscovery.GetInternalServiceDiscoveryObject().FindService(service.Service{Identifier: serviceIdentifier}) 64 | if err != nil { 65 | return "", err 66 | } 67 | 68 | return service.APIDocumentation, nil 69 | } 70 | 71 | func GetHtml(url string) (*http.Response, string, error) { 72 | tr := &http.Transport{ 73 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 74 | } 75 | client := &http.Client{Transport: tr} 76 | 77 | response, err := client.Get(url) 78 | if err != nil { 79 | utils.LogMessage(err.Error(), utils.ErrorLogType) 80 | return response, err.Error(), err 81 | } 82 | defer response.Body.Close() 83 | 84 | responseData, err := ioutil.ReadAll(response.Body) 85 | if err != nil { 86 | utils.LogMessage(err.Error(), utils.ErrorLogType) 87 | return response, err.Error(), err 88 | } 89 | 90 | return response, string(responseData), nil 91 | } 92 | -------------------------------------------------------------------------------- /dashboard/src/views/Users/NewUser.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 66 | 67 | 69 | -------------------------------------------------------------------------------- /dashboard/src/views/ServiceDiscovery/NewApplicationGroup.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 76 | 77 | 79 | -------------------------------------------------------------------------------- /api/utils/printer.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io/ioutil" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | "time" 9 | 10 | "github.com/robfig/cron" 11 | ) 12 | 13 | const ( 14 | FILE_LOGS_ENV_VAR = "LOGS_TO_FILE" 15 | DebugLogType = "DEBUG" 16 | InfoLogType = "INFO" 17 | ErrorLogType = "ERROR" 18 | logDateFilenameFormat = "2006-01-02" 19 | serverLogsFolder = "gapi_log_files" 20 | logFileExtension = "log" 21 | ) 22 | 23 | var initialized = false 24 | 25 | // Logs duration (15 days) 26 | var logsPersistenceTime = 7 * 24 * time.Hour 27 | 28 | // Remove files older than 29 | func deletefiles(path string, f os.FileInfo, err error) (e error) { 30 | logsPath := "." + string(filepath.Separator) + serverLogsFolder 31 | now := time.Now() 32 | fileInfo, err := ioutil.ReadDir("." + string(filepath.Separator) + serverLogsFolder) 33 | for _, info := range fileInfo { 34 | if diff := now.Sub(info.ModTime()); diff > logsPersistenceTime { 35 | pathToDelete := logsPath + string(filepath.Separator) + info.Name() 36 | LogMessage("Deleting "+pathToDelete, DebugLogType) 37 | err = os.Remove(pathToDelete) 38 | if err != nil { 39 | LogMessage("Error deleting "+pathToDelete+" with error: "+err.Error(), DebugLogType) 40 | } 41 | } 42 | } 43 | return 44 | } 45 | 46 | // Configure everything required when using files to log 47 | func configureLoggingFiles() { 48 | if initialized { 49 | return 50 | } 51 | 52 | path := "." + string(filepath.Separator) + serverLogsFolder 53 | if _, err := os.Stat(path); os.IsNotExist(err) { 54 | os.Mkdir(path, 0755) 55 | } 56 | 57 | c := cron.New() 58 | c.AddFunc("* * * * *", func() { 59 | filepath.Walk("."+string(filepath.Separator)+serverLogsFolder, deletefiles) 60 | }) 61 | c.Start() 62 | initialized = true 63 | } 64 | 65 | func LogMessage(message string, logtype string) { 66 | if logtype == DebugLogType && os.Getenv("DEBUG") != "true" { 67 | return 68 | } 69 | 70 | currentTime := time.Now() 71 | currDate := currentTime.UTC().String() 72 | var logger = log.New(os.Stdout, currDate+" - ", log.LstdFlags) 73 | 74 | // If log to file enabled, then change output to file inside gapi_log_files folder 75 | if os.Getenv(FILE_LOGS_ENV_VAR) != "" && os.Getenv(FILE_LOGS_ENV_VAR) == "true" { 76 | configureLoggingFiles() 77 | logFileName := "." + string(filepath.Separator) + serverLogsFolder + string(filepath.Separator) + currentTime.Format(logDateFilenameFormat) + "." + logFileExtension 78 | f, err := os.OpenFile(logFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) 79 | if err == nil { 80 | logger.SetOutput(f) 81 | } else { 82 | logger.Println(err.Error()) 83 | } 84 | defer f.Close() 85 | } 86 | 87 | logger.Println(message) 88 | } 89 | -------------------------------------------------------------------------------- /dashboard/src/views/Service/ViewService.vue: -------------------------------------------------------------------------------- 1 | 35 | 46 | 47 | 91 | --------------------------------------------------------------------------------