service/jenkins/service.go (128 lines of code) (raw):
package jenkins
import (
"context"
"ddm-admin-console/service"
"ddm-admin-console/service/k8s"
"net/http"
"github.com/bndr/gojenkins"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
pkgScheme "sigs.k8s.io/controller-runtime/pkg/scheme"
)
const (
StatusSuccess = "SUCCESS"
StatusUnstable = "UNSTABLE"
StatusFailure = "FAILURE"
StatusNotBuild = "NOT_BUILT"
StatusAborted = "ABORTED"
)
type Service struct {
service.UserConfig
Config
k8sClient client.Client
scheme *runtime.Scheme
goJenkins *gojenkins.Jenkins
k8s k8s.ServiceInterface
}
type Config struct {
AdminSecretName string
APIUrl string
Namespace string
}
func Make(s *runtime.Scheme, k8sConfig *rest.Config, k8s k8s.ServiceInterface, cnf Config) (*Service, error) {
builder := pkgScheme.Builder{GroupVersion: schema.GroupVersion{Group: "v2.edp.epam.com", Version: "v1alpha1"}}
builder.Register(&JenkinsJobBuildRun{}, &JenkinsJobBuildRunList{})
if err := builder.AddToScheme(s); err != nil {
return nil, errors.Wrap(err, "error during builder add to scheme")
}
cl, err := client.New(k8sConfig, client.Options{
Scheme: s,
})
if err != nil {
return nil, errors.Wrap(err, "unable to init k8s jenkins client")
}
svc := Service{
Config: cnf,
k8sClient: cl,
scheme: s,
UserConfig: service.UserConfig{
RestConfig: k8sConfig,
},
k8s: k8s,
}
if err := svc.initJenkinsAPIClient(context.Background(), k8s); err != nil {
return nil, errors.Wrap(err, "unable to ini jenkins api client")
}
return &svc, nil
}
func (s *Service) initJenkinsAPIClient(ctx context.Context, k8s k8s.ServiceInterface) error {
rsp, err := k8s.GetSecretKeys(ctx, s.Namespace, s.AdminSecretName,
[]string{"username", "password"})
if err != nil {
return errors.Wrap(err, "unable to get jenkins admin secret")
}
jenkinsClient := gojenkins.CreateJenkins(http.DefaultClient, s.APIUrl, rsp["username"], rsp["password"])
j, err := jenkinsClient.Init(ctx)
if err != nil {
return errors.Wrap(err, "unable to init jenkins client")
}
s.goJenkins = j
return nil
}
func (s *Service) GetJobStatus(ctx context.Context, jobName string) (string, int64, error) {
j, err := s.goJenkins.GetJob(ctx, jobName)
if err != nil {
return "", 0, errors.Wrap(err, "unable to get job")
}
lastBuild, err := j.GetLastBuild(ctx)
if err != nil {
return "", 0, errors.Wrap(err, "unable to get last build")
}
if _, err := lastBuild.Poll(ctx); err != nil {
return "", 0, errors.Wrap(err, "unable to poll last build")
}
return lastBuild.GetResult(), lastBuild.GetBuildNumber(), nil
}
func (s *Service) CreateJobBuildRunRaw(ctx context.Context, jb *JenkinsJobBuildRun) error {
jb.Namespace = s.Namespace
if err := s.k8sClient.Create(ctx, jb, &client.CreateOptions{}); err != nil {
return errors.Wrap(err, "unable to create job build run")
}
return nil
}
func (s *Service) CreateJobBuildRun(ctx context.Context, name, jobPath string, jobParams map[string]string) error {
jbr := JenkinsJobBuildRun{
ObjectMeta: metav1.ObjectMeta{
Namespace: s.Namespace,
Name: name,
},
TypeMeta: metav1.TypeMeta{
APIVersion: "v2.edp.epam.com/v1alpha1",
Kind: "JenkinsJobBuildRun",
},
Spec: JenkinsJobBuildRunSpec{
Params: jobParams,
JobPath: jobPath,
Retry: 5,
},
}
if err := s.CreateJobBuildRunRaw(ctx, &jbr); err != nil {
return errors.Wrap(err, "unableto create jenkins job build run")
}
return nil
}
func (s *Service) ServiceForContext(ctx context.Context) (ServiceInterface, error) {
userConfig, changed := s.UserConfig.CreateConfig(ctx)
if !changed {
return s, nil
}
svc, err := Make(s.scheme, userConfig, s.k8s, s.Config)
if err != nil {
return nil, errors.Wrap(err, "unable to create service for context")
}
return svc, nil
}