mirror of
https://github.com/grafana/grafana.git
synced 2024-11-27 03:11:01 -06:00
Improve extensions build. (#12461)
* enable ee build on pr/master * step1: of including group sync * disable commit pinning for now * fixes broken build * enable team to ldap group sync * avoid returning error for missing external handler * services: allow routes to be added before http server start * services: allows services to add their own migrations * moves db migrations to ee code base * build using master branch in ee * disable enterprise build in .bra.toml [skip ci] * removes team sync extensions * removes commented line
This commit is contained in:
parent
1601f6d17c
commit
861af4cb97
@ -221,6 +221,8 @@ workflows:
|
||||
jobs:
|
||||
- build-all:
|
||||
filters: *filter-not-release
|
||||
- build-enterprise:
|
||||
filters: *filter-not-release
|
||||
- codespell:
|
||||
filters: *filter-not-release
|
||||
- gometalinter:
|
||||
|
@ -9,7 +9,14 @@ import (
|
||||
m "github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
// Register adds http routes
|
||||
func (hs *HTTPServer) applyRoutes() {
|
||||
hs.RouteRegister.Register(hs.macaron)
|
||||
|
||||
InitAppPluginRoutes(hs.macaron)
|
||||
|
||||
hs.macaron.NotFound(NotFoundHandler)
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) registerRoutes() {
|
||||
macaronR := hs.macaron
|
||||
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
|
||||
@ -393,10 +400,4 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
|
||||
// streams
|
||||
//r.Post("/api/streams/push", reqSignedIn, bind(dtos.StreamMessage{}), liveConn.PushToStream)
|
||||
|
||||
r.Register(macaronR)
|
||||
|
||||
InitAppPluginRoutes(macaronR)
|
||||
|
||||
macaronR.NotFound(NotFoundHandler)
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
|
||||
}
|
||||
|
||||
jsonObj := map[string]interface{}{
|
||||
"enterprise": setting.Enterprise,
|
||||
"defaultDatasource": defaultDatasource,
|
||||
"datasources": datasources,
|
||||
"panels": panels,
|
||||
|
@ -33,7 +33,11 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.RegisterService(&HTTPServer{})
|
||||
registry.Register(®istry.Descriptor{
|
||||
Name: "HTTPServer",
|
||||
Instance: &HTTPServer{},
|
||||
InitPriority: registry.High,
|
||||
})
|
||||
}
|
||||
|
||||
type HTTPServer struct {
|
||||
@ -54,6 +58,10 @@ func (hs *HTTPServer) Init() error {
|
||||
hs.log = log.New("http.server")
|
||||
hs.cache = gocache.New(5*time.Minute, 10*time.Minute)
|
||||
|
||||
hs.streamManager = live.NewStreamManager()
|
||||
hs.macaron = hs.newMacaron()
|
||||
hs.registerRoutes()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -61,10 +69,7 @@ func (hs *HTTPServer) Run(ctx context.Context) error {
|
||||
var err error
|
||||
|
||||
hs.context = ctx
|
||||
hs.streamManager = live.NewStreamManager()
|
||||
hs.macaron = hs.newMacaron()
|
||||
hs.registerRoutes()
|
||||
|
||||
hs.applyRoutes()
|
||||
hs.streamManager.Run(ctx)
|
||||
|
||||
listenAddr := fmt.Sprintf("%s:%s", setting.HttpAddr, setting.HttpPort)
|
||||
|
@ -66,7 +66,21 @@ func UpsertUser(cmd *m.UpsertUserCommand) error {
|
||||
}
|
||||
}
|
||||
|
||||
return syncOrgRoles(cmd.Result, extUser)
|
||||
err = syncOrgRoles(cmd.Result, extUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bus.Dispatch(&m.SyncTeamsCommand{
|
||||
User: cmd.Result,
|
||||
ExternalUser: extUser,
|
||||
})
|
||||
|
||||
if err == bus.ErrHandlerNotFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func createUser(extUser *m.ExternalUserInfo) (*m.User, error) {
|
||||
|
@ -163,6 +163,7 @@ func (a *ldapAuther) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo
|
||||
Name: fmt.Sprintf("%s %s", ldapUser.FirstName, ldapUser.LastName),
|
||||
Login: ldapUser.Username,
|
||||
Email: ldapUser.Email,
|
||||
Groups: ldapUser.MemberOf,
|
||||
OrgRoles: map[int64]m.RoleType{},
|
||||
}
|
||||
|
||||
@ -194,6 +195,7 @@ func (a *ldapAuther) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *LdapUserInfo
|
||||
ExternalUser: extUser,
|
||||
SignupAllowed: setting.LdapAllowSignup,
|
||||
}
|
||||
|
||||
err := bus.Dispatch(userQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1,6 +1,7 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"testing"
|
||||
|
||||
@ -14,6 +15,14 @@ func TestLdapAuther(t *testing.T) {
|
||||
|
||||
Convey("When translating ldap user to grafana user", t, func() {
|
||||
|
||||
var user1 = &m.User{}
|
||||
|
||||
bus.AddHandlerCtx("test", func(ctx context.Context, cmd *m.UpsertUserCommand) error {
|
||||
cmd.Result = user1
|
||||
cmd.Result.Login = "torkelo"
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Given no ldap group map match", func() {
|
||||
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
|
||||
LdapGroups: []*LdapGroupToOrgRole{{}},
|
||||
@ -23,8 +32,6 @@ func TestLdapAuther(t *testing.T) {
|
||||
So(err, ShouldEqual, ErrInvalidCredentials)
|
||||
})
|
||||
|
||||
var user1 = &m.User{}
|
||||
|
||||
ldapAutherScenario("Given wildcard group match", func(sc *scenarioContext) {
|
||||
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
|
||||
LdapGroups: []*LdapGroupToOrgRole{
|
||||
@ -96,7 +103,6 @@ func TestLdapAuther(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("When syncing ldap groups to grafana org roles", t, func() {
|
||||
|
||||
ldapAutherScenario("given no current user orgs", func(sc *scenarioContext) {
|
||||
ldapAuther := NewLdapAuthenticator(&LdapServerConf{
|
||||
LdapGroups: []*LdapGroupToOrgRole{
|
||||
@ -322,6 +328,10 @@ func ldapAutherScenario(desc string, fn scenarioFunc) {
|
||||
|
||||
bus.AddHandler("test", UpsertUser)
|
||||
|
||||
bus.AddHandlerCtx("test", func(ctx context.Context, cmd *m.SyncTeamsCommand) error {
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(cmd *m.GetUserByAuthInfoQuery) error {
|
||||
sc.getUserByAuthInfoQuery = cmd
|
||||
sc.getUserByAuthInfoQuery.Result = &m.User{Login: cmd.Login}
|
||||
|
@ -42,6 +42,7 @@ type RemoveTeamMemberCommand struct {
|
||||
type GetTeamMembersQuery struct {
|
||||
OrgId int64
|
||||
TeamId int64
|
||||
UserId int64
|
||||
Result []*TeamMemberDTO
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ type ExternalUserInfo struct {
|
||||
Email string
|
||||
Login string
|
||||
Name string
|
||||
Groups []string
|
||||
OrgRoles map[int64]RoleType
|
||||
}
|
||||
|
||||
@ -70,3 +71,8 @@ type GetAuthInfoQuery struct {
|
||||
|
||||
Result *UserAuth
|
||||
}
|
||||
|
||||
type SyncTeamsCommand struct {
|
||||
ExternalUser *ExternalUserInfo
|
||||
User *User
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
)
|
||||
|
||||
type Descriptor struct {
|
||||
@ -57,13 +59,21 @@ type CanBeDisabled interface {
|
||||
// BackgroundService should be implemented for services that have
|
||||
// long running tasks in the background.
|
||||
type BackgroundService interface {
|
||||
|
||||
// Run starts the background process of the service after `Init` have been called
|
||||
// on all services. The `context.Context` passed into the function should be used
|
||||
// to subscribe to ctx.Done() so the service can be notified when Grafana shuts down.
|
||||
Run(ctx context.Context) error
|
||||
}
|
||||
|
||||
// DatabaseMigrator allows the caller to add migrations to
|
||||
// the migrator passed as argument
|
||||
type DatabaseMigrator interface {
|
||||
|
||||
// AddMigrations allows the service to add migrations to
|
||||
// the database migrator.
|
||||
AddMigration(mg *migrator.Migrator)
|
||||
}
|
||||
|
||||
// IsDisabled takes an service and return true if its disabled
|
||||
func IsDisabled(srv Service) bool {
|
||||
canBeDisabled, ok := srv.(CanBeDisabled)
|
||||
|
@ -50,4 +50,5 @@ func addTeamMigrations(mg *Migrator) {
|
||||
mg.AddMigration("Add column email to team table", NewAddColumnMigration(teamV1, &Column{
|
||||
Name: "email", Type: DB_NVarchar, Nullable: true, Length: 190,
|
||||
}))
|
||||
|
||||
}
|
||||
|
@ -132,6 +132,13 @@ func (ss *SqlStore) Init() error {
|
||||
migrator := migrator.NewMigrator(x)
|
||||
migrations.AddMigrations(migrator)
|
||||
|
||||
for _, descriptor := range registry.GetServices() {
|
||||
sc, ok := descriptor.Instance.(registry.DatabaseMigrator)
|
||||
if ok {
|
||||
sc.AddMigration(migrator)
|
||||
}
|
||||
}
|
||||
|
||||
if err := migrator.Start(); err != nil {
|
||||
return fmt.Errorf("Migration failed err: %v", err)
|
||||
}
|
||||
|
@ -268,7 +268,15 @@ func GetTeamMembers(query *m.GetTeamMembersQuery) error {
|
||||
query.Result = make([]*m.TeamMemberDTO, 0)
|
||||
sess := x.Table("team_member")
|
||||
sess.Join("INNER", "user", fmt.Sprintf("team_member.user_id=%s.id", x.Dialect().Quote("user")))
|
||||
sess.Where("team_member.org_id=? and team_member.team_id=?", query.OrgId, query.TeamId)
|
||||
if query.OrgId != 0 {
|
||||
sess.Where("team_member.org_id=?", query.OrgId)
|
||||
}
|
||||
if query.TeamId != 0 {
|
||||
sess.Where("team_member.team_id=?", query.TeamId)
|
||||
}
|
||||
if query.UserId != 0 {
|
||||
sess.Where("team_member.user_id=?", query.UserId)
|
||||
}
|
||||
sess.Cols("user.org_id", "team_member.team_id", "team_member.user_id", "user.email", "user.login")
|
||||
sess.Asc("user.login", "user.email")
|
||||
|
||||
|
@ -22,6 +22,7 @@ class Settings {
|
||||
disableUserSignUp: boolean;
|
||||
loginHint: any;
|
||||
loginError: any;
|
||||
enterprise: boolean;
|
||||
|
||||
constructor(options) {
|
||||
var defaults = {
|
||||
|
@ -1,22 +1,22 @@
|
||||
<page-header model="ctrl.navModel"></page-header>
|
||||
|
||||
<div class="page-container page-body">
|
||||
<h3 class="page-sub-heading">Team Details</h3>
|
||||
<h3 class="page-sub-heading">Team Details</h3>
|
||||
|
||||
<form name="teamDetailsForm" class="gf-form-group">
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-10">Name</span>
|
||||
<input type="text" required ng-model="ctrl.team.name" class="gf-form-input max-width-22">
|
||||
</div>
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-10">
|
||||
Email
|
||||
<info-popover mode="right-normal">
|
||||
This is optional and is primarily used for allowing custom team avatars.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input class="gf-form-input max-width-22" type="email" ng-model="ctrl.team.email" placeholder="email@test.com">
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-10">
|
||||
Email
|
||||
<info-popover mode="right-normal">
|
||||
This is optional and is primarily used for allowing custom team avatars.
|
||||
</info-popover>
|
||||
</span>
|
||||
<input class="gf-form-input max-width-22" type="email" ng-model="ctrl.team.email" placeholder="email@test.com">
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="submit" class="btn btn-success" ng-click="ctrl.update()">Update</button>
|
||||
@ -26,42 +26,80 @@
|
||||
<div class="gf-form-group">
|
||||
|
||||
<h3 class="page-heading">Team Members</h3>
|
||||
<form name="ctrl.addMemberForm" class="gf-form-group">
|
||||
<form name="ctrl.addMemberForm" class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Add member</span>
|
||||
<!--
|
||||
Old picker
|
||||
<user-picker user-picked="ctrl.userPicked($user)"></user-picker>
|
||||
-->
|
||||
<select-user-picker class="width-7" handlePicked="ctrl.userPicked" backendSrv="ctrl.backendSrv"></select-user-picker>
|
||||
<!--
|
||||
Old picker
|
||||
<user-picker user-picked="ctrl.userPicked($user)"></user-picker>
|
||||
-->
|
||||
<select-user-picker class="width-7" handlePicked="ctrl.userPicked" backendSrv="ctrl.backendSrv"></select-user-picker>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table class="filter-table" ng-show="ctrl.teamMembers.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="member in ctrl.teamMembers">
|
||||
<td class="width-4 text-center link-td">
|
||||
<img class="filter-table__avatar" ng-src="{{member.avatarUrl}}"></img>
|
||||
</td>
|
||||
<td>{{member.login}}</td>
|
||||
<td>{{member.email}}</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="ctrl.removeTeamMember(member)" class="btn btn-danger btn-mini">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
<em class="muted" ng-hide="ctrl.teamMembers.length > 0">
|
||||
This team has no members yet.
|
||||
</em>
|
||||
</div>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="member in ctrl.teamMembers">
|
||||
<td class="width-4 text-center link-td">
|
||||
<img class="filter-table__avatar" ng-src="{{member.avatarUrl}}"></img>
|
||||
</td>
|
||||
<td>{{member.login}}</td>
|
||||
<td>{{member.email}}</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="ctrl.removeTeamMember(member)" class="btn btn-danger btn-mini">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
<em class="muted" ng-hide="ctrl.teamMembers.length > 0">
|
||||
This team has no members yet.
|
||||
</em>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group" ng-if="ctrl.enterprise">
|
||||
|
||||
<h3 class="page-heading">Team Group Mapping</h3>
|
||||
<form name="ctrl.addGroupForm" class="gf-form-group">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-10">Add group</span>
|
||||
<input class="gf-form-input max-width-22" type="text" ng-model="ctrl.newGroupId">
|
||||
</div>
|
||||
<div class="gf-form-button-row">
|
||||
<button type="submit" class="btn btn-success" ng-click="ctrl.addGroup()">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table class="filter-table" ng-show="ctrl.teamGroups.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Group</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr ng-repeat="group in ctrl.teamGroups">
|
||||
<td>{{group.groupId}}</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="ctrl.removeGroup(group)" class="btn btn-danger btn-mini">
|
||||
<i class="fa fa-remove"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div>
|
||||
<em class="muted" ng-hide="ctrl.teamGroups.length > 0">
|
||||
This team has no associated groups yet.
|
||||
</em>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -1,15 +1,21 @@
|
||||
import coreModule from 'app/core/core_module';
|
||||
import config from 'app/core/config';
|
||||
|
||||
export default class TeamDetailsCtrl {
|
||||
team: Team;
|
||||
teamMembers: User[] = [];
|
||||
navModel: any;
|
||||
teamGroups: TeamGroup[] = [];
|
||||
newGroupId: string;
|
||||
enterprise: boolean;
|
||||
|
||||
/** @ngInject **/
|
||||
constructor(private $scope, private backendSrv, private $routeParams, navModelSrv) {
|
||||
this.navModel = navModelSrv.getNav('cfg', 'teams', 0);
|
||||
this.userPicked = this.userPicked.bind(this);
|
||||
this.get = this.get.bind(this);
|
||||
this.newGroupId = '';
|
||||
this.enterprise = config.enterprise;
|
||||
this.get();
|
||||
}
|
||||
|
||||
@ -18,9 +24,16 @@ export default class TeamDetailsCtrl {
|
||||
this.backendSrv.get(`/api/teams/${this.$routeParams.id}`).then(result => {
|
||||
this.team = result;
|
||||
});
|
||||
|
||||
this.backendSrv.get(`/api/teams/${this.$routeParams.id}/members`).then(result => {
|
||||
this.teamMembers = result;
|
||||
});
|
||||
|
||||
if (config.enterprise) {
|
||||
this.backendSrv.get(`/api/teams/${this.$routeParams.id}/groups`).then(result => {
|
||||
this.teamGroups = result;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +70,20 @@ export default class TeamDetailsCtrl {
|
||||
this.get();
|
||||
});
|
||||
}
|
||||
|
||||
addGroup() {
|
||||
this.backendSrv.post(`/api/teams/${this.$routeParams.id}/groups`, { groupId: this.newGroupId }).then(() => {
|
||||
this.get();
|
||||
});
|
||||
}
|
||||
|
||||
removeGroup(group: TeamGroup) {
|
||||
this.backendSrv.delete(`/api/teams/${this.$routeParams.id}/groups/${group.groupId}`).then(this.get);
|
||||
}
|
||||
}
|
||||
|
||||
export interface TeamGroup {
|
||||
groupId: string;
|
||||
}
|
||||
|
||||
export interface Team {
|
||||
|
@ -14,9 +14,9 @@ cd /go/src/github.com/grafana/grafana
|
||||
echo "current dir: $(pwd)"
|
||||
|
||||
cd ..
|
||||
git clone -b ee_build --single-branch git@github.com:grafana/grafana-enterprise.git --depth 10
|
||||
git clone -b master --single-branch git@github.com:grafana/grafana-enterprise.git --depth 10
|
||||
cd grafana-enterprise
|
||||
git checkout 7fbae9c1be3467c4a39cf6ad85278a6896ceb49f
|
||||
#git checkout 7fbae9c1be3467c4a39cf6ad85278a6896ceb49f
|
||||
./build.sh
|
||||
|
||||
cd ../grafana
|
||||
|
Loading…
Reference in New Issue
Block a user