Skip to content

Commit

Permalink
Merge pull request #29 from alcounit/develop
Browse files Browse the repository at this point in the history
Fixed browser limit issue, added security features support
  • Loading branch information
alcounit authored Apr 1, 2021
2 parents 066ee61 + 63060d0 commit c989f8f
Show file tree
Hide file tree
Showing 11 changed files with 720 additions and 242 deletions.
82 changes: 82 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,88 @@ chrome:
image: selenoid/vnc:chrome_86.0
```
## Custom UID and GID for browser pod
Browser pod can be run with custom UID and GID. To do so set runAs property for specific browser globally or per each browser version.
``` json
{
"chrome": {
"defaultVersion": "85.0",
"path": "/",
"runAs": {
"uid": 1000,
"gid": 2000
},
"versions": {
"85.0": {
"image": "selenoid/vnc:chrome_85.0"
},
"runAs": {
"uid": 1001,
"gid": 2002
},
"86.0": {
"image": "selenoid/vnc:chrome_86.0"
}
}
}
}
```

``` yaml
---
chrome:
defaultVersion: '85.0'
path: "/"
runAs:
uid: 1000
gid: 2000
versions:
'85.0':
image: selenoid/vnc:chrome_85.0
runAs:
uid: 1001
gid: 2002
'86.0':
image: selenoid/vnc:chrome_86.0
```
## Custom Kernel Capabilities
In some cases you may need to run browser container with custom Linux capabilities. To do so set kernelCaps property for specific browser globally or per each browser version.
``` json
{
"chrome": {
"defaultVersion": "85.0",
"path": "/",
"kernelCaps": ["SYS_ADMIN"],
"versions": {
"85.0": {
"image": "selenoid/vnc:chrome_85.0"
},
"kernelCaps": ["SYS_ADMIN"],
"86.0": {
"image": "selenoid/vnc:chrome_86.0"
}
}
}
}
```

``` yaml
---
chrome:
defaultVersion: '85.0'
path: "/"
kernelCaps:
- SYS_ADMIN
versions:
'85.0':
image: selenoid/vnc:chrome_85.0
kernelCaps:
- SYS_ADMIN
'86.0':
image: selenoid/vnc:chrome_86.0
```
## Deployment
Files and steps required for selenosis deployment available in [selenosis-deploy](https://github.com/alcounit/selenosis-deploy) repository
Expand Down
2 changes: 1 addition & 1 deletion cmd/selenosis/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func command() *cobra.Command {
})

router := mux.NewRouter()
router.HandleFunc("/wd/hub/session", app.CheckLimit(app.HandleSession)).Methods(http.MethodPost)
router.HandleFunc("/wd/hub/session", app.HandleSession).Methods(http.MethodPost)
router.PathPrefix("/wd/hub/session/{sessionId}").HandlerFunc(app.HandleProxy)
router.HandleFunc("/wd/hub/status", app.HandleHubStatus).Methods(http.MethodGet)
router.PathPrefix("/vnc/{sessionId}").Handler(websocket.Handler(app.HandleVNC()))
Expand Down
7 changes: 7 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Layout struct {
DefaultVersion string `yaml:"defaultVersion" json:"defaultVersion"`
Versions map[string]*platform.BrowserSpec `yaml:"versions" json:"versions"`
Volumes []apiv1.Volume `yaml:"volumes,omitempty" json:"volumes,omitempty"`
Capabilities []apiv1.Capability `yaml:"kernelCaps,omitempty" json:"kernelCaps,omitempty"`
RunAs platform.RunAsOptions `yaml:"runAs,omitempty" json:"runAs,omitempty"`
}

//BrowsersConfig ...
Expand Down Expand Up @@ -134,10 +136,15 @@ func readConfig(configFile string) (map[string]*Layout, error) {
container.Meta.Annotations = merge(container.Meta.Annotations, layout.Meta.Annotations)
container.Meta.Labels = merge(container.Meta.Labels, layout.Meta.Labels)
container.Volumes = layout.Volumes
container.Capabilities = append(container.Capabilities, layout.Capabilities...)

if err := mergo.Merge(&container.Spec, spec); err != nil {
return nil, fmt.Errorf("merge error %v", err)
}

if err := mergo.Merge(&container.RunAs, layout.RunAs); err != nil {
return nil, fmt.Errorf("merge error %v", err)
}
}
}
return layouts, nil
Expand Down
28 changes: 4 additions & 24 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,6 @@ var (
}
)

//CheckLimit ...
func (app *App) CheckLimit(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
logger := app.logger.WithFields(logrus.Fields{
"request_id": uuid.New(),
"request": fmt.Sprintf("%s %s", r.Method, r.URL.Path),
})

total := app.stats.Len()

if total >= app.sessionLimit {
logger.Warnf("active session limit reached: total %d, limit %d", total, app.sessionLimit)
tools.JSONError(w, "session limit reached", http.StatusInternalServerError)
return
}

next.ServeHTTP(w, r)
}
}

//HandleSession ...
func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) {
start := time.Now()
Expand Down Expand Up @@ -122,7 +102,7 @@ func (app *App) HandleSession(w http.ResponseWriter, r *http.Request) {

logger.WithField("time_elapsed", tools.TimeElapsed(start)).Infof("starting browser from image: %s", template.Template.Image)

service, err := app.client.Create(template)
service, err := app.client.Service().Create(template)
if err != nil {
logger.WithField("time_elapsed", tools.TimeElapsed(start)).Errorf("failed to start browser: %v", err)
tools.JSONError(w, err.Error(), http.StatusBadRequest)
Expand Down Expand Up @@ -238,7 +218,7 @@ func (app *App) HandleHubStatus(w http.ResponseWriter, r *http.Request) {

w.Header().Set("Content-Type", "application/json")

active, pending := getSessionStats(app.stats.List())
active, pending := getSessionStats(app.stats.Sessions().List())
total := len(active) + len(pending)

json.NewEncoder(w).Encode(
Expand Down Expand Up @@ -341,7 +321,7 @@ func (app *App) HandleLogs() websocket.Handler {
})
logger.Infof("stream logs request: %s", fmt.Sprintf("%s.%s", sessionID, app.serviceName))

conn, err := app.client.Logs(wsconn.Request().Context(), sessionID)
conn, err := app.client.Service().Logs(wsconn.Request().Context(), sessionID)
if err != nil {
logger.Errorf("stream logs error: %v", err)
return
Expand Down Expand Up @@ -378,7 +358,7 @@ func (app *App) HandleStatus(w http.ResponseWriter, r *http.Request) {
Selenosis Status `json:"selenosis,omitempty"`
}

active, pending := getSessionStats(app.stats.List())
active, pending := getSessionStats(app.stats.Sessions().List())
json.NewEncoder(w).Encode(
Response{
Status: http.StatusOK,
Expand Down
60 changes: 52 additions & 8 deletions handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,30 +595,74 @@ func NewPlatformMock(f *PlatformMock) platform.Platform {
return f
}

func (p *PlatformMock) Create(*platform.ServiceSpec) (*platform.Service, error) {
func (p *PlatformMock) Service() platform.ServiceInterface {
return &serviceMock{
err: p.err,
service: p.service,
}
}

func (p *PlatformMock) Quota() platform.QuotaInterface {
return &quotaMock{
err: nil,
quota: &platform.Quota{
Name: "test",
CurrentMaxLimit: 10,
},
}
}

func (p *PlatformMock) State() (platform.PlatformState, error) {
return platform.PlatformState{}, nil
}

func (p *PlatformMock) Watch() <-chan platform.Event {
ch := make(chan platform.Event)
return ch
}

func (p *PlatformMock) List() ([]*platform.Service, error) {
return nil, nil
}

type serviceMock struct {
err error
service *platform.Service
}

func (p *serviceMock) Create(*platform.ServiceSpec) (*platform.Service, error) {
if p.err != nil {
return nil, p.err
}
return p.service, nil

}
func (p *PlatformMock) Delete(string) error {
func (p *serviceMock) Delete(string) error {
if p.err != nil {
return p.err
}
return nil
}
func (p *PlatformMock) List() ([]*platform.Service, error) {

func (p *serviceMock) Logs(ctx context.Context, name string) (io.ReadCloser, error) {
return nil, nil
}

func (p *PlatformMock) Watch() <-chan platform.Event {
ch := make(chan platform.Event)
return ch
type quotaMock struct {
err error
quota *platform.Quota
}

func (p *PlatformMock) Logs(ctx context.Context, name string) (io.ReadCloser, error) {
return nil, nil
func (s *quotaMock) Create(int64) (*platform.Quota, error) {
return s.quota, nil
}

func (s *quotaMock) Get() (*platform.Quota, error) {
return s.quota, nil
}

func (s *quotaMock) Update(int64) (*platform.Quota, error) {
return s.quota, nil
}

type errReader int
Expand Down
Loading

0 comments on commit c989f8f

Please sign in to comment.