Skip to content
This repository has been archived by the owner on May 6, 2021. It is now read-only.

Commit

Permalink
Single user Idler v for test/debug purpose
Browse files Browse the repository at this point in the history
Input: Namespace Basename, OSIO User UUID, CLuster URL and OS User Token

Watches builds and deployments in a single namespace relying only on a User token
(require admin/edit of -jenkins ns to perform Idle/Unidle)

See cmd/fabric8-jenkins-idler-test/main.go for "var"s required.

Run on cli

    go install -ldflags="-X github.com/fabric8-services/fabric8-jenkins-idler/internal/version.version=c931081" ./cmd/fabric8-jenkins-idler-test && fabric8-jenkins-idler-test

Or run/debug the test TestSingleIdler in cmd/fabric8-jenkins-idler-test/main_test.go
  • Loading branch information
aslakknutsen committed Oct 12, 2018
1 parent 8840ca9 commit b128cb7
Show file tree
Hide file tree
Showing 4 changed files with 411 additions and 72 deletions.
177 changes: 177 additions & 0 deletions cmd/fabric8-jenkins-idler-test/idler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package main

import (
"github.com/fabric8-services/fabric8-jenkins-idler/internal/configuration"

"github.com/fabric8-services/fabric8-jenkins-idler/internal/openshift"
"github.com/fabric8-services/fabric8-jenkins-idler/internal/toggles"

"context"
"os"
"os/signal"
"sync"
"syscall"

"github.com/fabric8-services/fabric8-jenkins-idler/internal/api"
"github.com/fabric8-services/fabric8-jenkins-idler/internal/cluster"
"github.com/fabric8-services/fabric8-jenkins-idler/internal/openshift/client"
"github.com/fabric8-services/fabric8-jenkins-idler/internal/router"
"github.com/fabric8-services/fabric8-jenkins-idler/internal/tenant"
"github.com/julienschmidt/httprouter"
log "github.com/sirupsen/logrus"
)

const (
profilerPort = 6060
)

var idlerLogger = log.WithFields(log.Fields{"component": "idler"})

// Idler is responsible to create and control the various concurrent processes needed to implement the Jenkins idling
// feature. An Idler instance creates two goroutines for watching all builds respectively deployment config changes of
// the whole cluster. To do this it needs an access openShift access token which allows the Idler to do so (see Data.GetOpenShiftToken).
// A third go routine is used to serve a HTTP REST API.
type Idler struct {
featureService toggles.Features
tenantService tenant.Service
clusterView cluster.View
config configuration.Configuration
baseNamespace string
}

// NewIdler creates a new instance of Idler. The configuration as well as feature toggle handler needs to be passed.
func NewIdler(features toggles.Features, tenantService tenant.Service, clusterView cluster.View, config configuration.Configuration, baseNamespace string) *Idler {
return &Idler{
featureService: features,
tenantService: tenantService,
clusterView: clusterView,
config: config,
baseNamespace: baseNamespace,
}
}

// Run starts the various goroutines of the Idler. To cleanly shutdown the SIGTERM signal should be send to the process.
func (idler *Idler) Run() {
var wg sync.WaitGroup
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

idler.startWorkers(ctx, &wg, cancel, idler.config.GetDebugMode())

setupSignalChannel(cancel)
wg.Wait()
idlerLogger.Info("Idler successfully shut down.")
}

func (idler *Idler) startWorkers(ctx context.Context, wg *sync.WaitGroup, cancel context.CancelFunc, addProfiler bool) {
idlerLogger.Info("Starting all Idler workers")

// Create synchronized map for UserIdler instances
userIdlers := openshift.NewUserIdlerMap()

// Start the controllers to monitor the OpenShift clusters
idler.startOpenShiftControllers(ctx, wg, cancel, userIdlers)

// Start API router
go func() {
// Create and start a Router instance to serve the REST API
idlerAPI := api.NewIdlerAPI(userIdlers, idler.clusterView, idler.tenantService)
apirouter := router.CreateAPIRouter(idlerAPI)
router := router.NewRouter(apirouter)
router.AddMetrics(apirouter)
router.Start(ctx, wg, cancel)
}()

if addProfiler {
go func() {
idlerLogger.Infof("Starting profiler on port %d", profilerPort)
router := router.NewRouterWithPort(httprouter.New(), profilerPort)
router.Start(ctx, wg, cancel)
}()
}
}

func (idler *Idler) startOpenShiftControllers(ctx context.Context, wg *sync.WaitGroup, cancel context.CancelFunc, userIdlers *openshift.UserIdlerMap) {
openShiftClient := client.NewOpenShift()

for _, openShiftCluster := range idler.clusterView.GetClusters() {
// Create Controller
controller := openshift.NewController(
ctx,
openShiftCluster.APIURL,
openShiftCluster.Token,
userIdlers,
idler.tenantService,
idler.featureService,
idler.config,
wg,
cancel,
)

wg.Add(1)
go func(cluster cluster.Cluster) {
defer wg.Done()
go func() {
idlerLogger.Info("Starting to watch openShift deployment configuration changes.")
var err error
if len(idler.baseNamespace) > 0 {
err = openShiftClient.WatchNamespaceDeploymentConfigs(cluster.APIURL, cluster.Token, idler.baseNamespace+"-jenkins", "-jenkins", controller.HandleDeploymentConfig)
} else {
err = openShiftClient.WatchDeploymentConfigs(cluster.APIURL, cluster.Token, "-jenkins", controller.HandleDeploymentConfig)
}
if err != nil {
cancel()
return
}
}()

for {
select {
case <-ctx.Done():
idlerLogger.Infof("Stopping to watch openShift deployment configuration changes.")
cancel()
return
}
}
}(openShiftCluster)

wg.Add(1)
go func(cluster cluster.Cluster) {
defer wg.Done()
go func() {
idlerLogger.Info("Starting to watch openShift build configuration changes.")
var err error
if len(idler.baseNamespace) > 0 {
err = openShiftClient.WatchNamespaceBuilds(cluster.APIURL, cluster.Token, "JenkinsPipeline", idler.baseNamespace, controller.HandleBuild)
} else {
err = openShiftClient.WatchBuilds(cluster.APIURL, cluster.Token, "JenkinsPipeline", controller.HandleBuild)
}
if err != nil {
cancel()
return
}
}()

for {
select {
case <-ctx.Done():
idlerLogger.Infof("Stopping to watch openShift build configuration changes.")
cancel()
return
}
}
}(openShiftCluster)
}
}

// setupSignalChannel registers a listener for Unix signals for a ordered shutdown
func setupSignalChannel(cancel context.CancelFunc) {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGTERM)

go func() {
<-sigChan
idlerLogger.Info("Received SIGTERM signal. Initiating shutdown.")
cancel()
}()
}
95 changes: 95 additions & 0 deletions cmd/fabric8-jenkins-idler-test/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package main

import (
"os"

"github.com/fabric8-services/fabric8-jenkins-idler/internal/cluster"
"github.com/fabric8-services/fabric8-jenkins-idler/internal/configuration"
"github.com/fabric8-services/fabric8-jenkins-idler/internal/tenant"
)

type testTenantService struct {
IdentityID string
BaseName string
}

func (t testTenantService) GetTenantInfoByNamespace(apiURL string, ns string) (tenant.InfoList, error) {
if ns == t.BaseName || ns == t.BaseName+"-jenkins" {
return tenant.InfoList{
Data: []tenant.InfoData{{
ID: t.IdentityID,
Attributes: tenant.Attributes{
Namespaces: []tenant.Namespace{
{
ClusterURL: apiURL,
Name: ns,
Type: "user",
ClusterCapacityExhausted: false,
},
{
ClusterURL: apiURL,
Name: ns + "-jenkins",
Type: "jenkins",
ClusterCapacityExhausted: false,
},
},
},
}},
}, nil
}
return tenant.InfoList{}, nil
}

func (t testTenantService) HasReachedMaxCapacity(apiURL, ns string) (bool, error) {
return false, nil
}

type testFeaturesService struct {
IdentityID string
}

func (t testFeaturesService) IsIdlerEnabled(uid string) (bool, error) {
if uid == t.IdentityID {
return true, nil
}
return false, nil
}

func NewTestIdler(baseName, identityID, clusterURL, token string) *Idler {
featuresService := testFeaturesService{
IdentityID: identityID,
}
tenantService := testTenantService{
IdentityID: identityID,
BaseName: baseName,
}
clusterView := cluster.NewView([]cluster.Cluster{
cluster.Cluster{
APIURL: clusterURL,
AppDNS: "4e1e.starter-us-east-2a.openshiftapps.com",
Token: token,
},
})
config, _ := configuration.NewConfiguration()

return NewIdler(featuresService, tenantService, clusterView, config, baseName)
}

var (
baseName = "aslak-preview"
identityID = "81d3c8d8-1aa2-49b4-a4c3-ffb41ed1f439"
clusterURL = "https://api.starter-us-east-2a.openshift.com/"
token = "xxxxxxxx"
)

func main() {

os.Setenv("JC_DEBUG_MODE", "true")
os.Setenv("JC_IDLE_AFTER", "5")
os.Setenv("JC_CHECK_INTERVAL", "5")
os.Setenv("JC_MAX_RETRIES", "5")
os.Setenv("JC_MAX_RETRIES_QUIET_INTERVAL", "5")

idler := NewTestIdler(baseName, identityID, clusterURL, token)
idler.Run()
}
18 changes: 18 additions & 0 deletions cmd/fabric8-jenkins-idler-test/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"os"
"testing"
)

func XTestSingleIdler(t *testing.T) {

os.Setenv("JC_DEBUG_MODE", "true")
os.Setenv("JC_IDLE_AFTER", "5")
os.Setenv("JC_CHECK_INTERVAL", "5")
os.Setenv("JC_MAX_RETRIES", "5")
os.Setenv("JC_MAX_RETRIES_QUIET_INTERVAL", "5")

idler := NewTestIdler(baseName, identityID, clusterURL, token)
idler.Run()
}
Loading

0 comments on commit b128cb7

Please sign in to comment.