mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-04-15 07:16:34 +00:00
No more controllers
This commit is contained in:
@@ -39,6 +39,7 @@ func Test_textAnalyze(t *testing.T) {
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "text-collector-1",
|
||||
Message: "pass",
|
||||
},
|
||||
files: map[string][]byte{
|
||||
@@ -68,6 +69,7 @@ func Test_textAnalyze(t *testing.T) {
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-2",
|
||||
Message: "fail",
|
||||
},
|
||||
files: map[string][]byte{
|
||||
@@ -94,10 +96,11 @@ func Test_textAnalyze(t *testing.T) {
|
||||
RegexPattern: "",
|
||||
},
|
||||
expectResult: AnalyzeResult{
|
||||
IsPass: true,
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Message: "success",
|
||||
IsFail: true,
|
||||
Title: "",
|
||||
Message: "Invalid analyzer",
|
||||
},
|
||||
files: map[string][]byte{
|
||||
"text-collector-3/cfile-3.txt": []byte("Connection to service succeeded"),
|
||||
@@ -126,6 +129,7 @@ func Test_textAnalyze(t *testing.T) {
|
||||
IsPass: true,
|
||||
IsWarn: false,
|
||||
IsFail: false,
|
||||
Title: "text-collector-5",
|
||||
Message: "success",
|
||||
},
|
||||
files: map[string][]byte{
|
||||
@@ -155,6 +159,7 @@ func Test_textAnalyze(t *testing.T) {
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-4",
|
||||
Message: "fail",
|
||||
},
|
||||
files: map[string][]byte{
|
||||
@@ -184,6 +189,7 @@ func Test_textAnalyze(t *testing.T) {
|
||||
IsPass: false,
|
||||
IsWarn: false,
|
||||
IsFail: true,
|
||||
Title: "text-collector-6",
|
||||
Message: "fail",
|
||||
},
|
||||
files: map[string][]byte{
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/controller/analyzer"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, analyzer.Add)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/controller/analyzerjob"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, analyzerjob.Add)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/controller/collector"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, collector.Add)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/controller/collectorjob"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, collectorjob.Add)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/controller/preflight"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, preflight.Add)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"github.com/replicatedhq/troubleshoot/pkg/controller/preflightjob"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
|
||||
AddToManagerFuncs = append(AddToManagerFuncs, preflightjob.Add)
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
/**
|
||||
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
|
||||
* business logic. Delete these comments after modifying this file.*
|
||||
*/
|
||||
|
||||
// Add creates a new Analyzer Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcileAnalyzer{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("analyzer-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to Analyzer
|
||||
err = c.Watch(&source.Kind{Type: &troubleshootv1beta1.Analyzer{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(user): Modify this to be the types you create
|
||||
// Uncomment watch a Deployment created by Analyzer - change this for objects you create
|
||||
err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &troubleshootv1beta1.Analyzer{},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcileAnalyzer{}
|
||||
|
||||
// ReconcileAnalyzer reconciles a Analyzer object
|
||||
type ReconcileAnalyzer struct {
|
||||
client.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a Analyzer object and makes changes based on the state read
|
||||
// and what is in the Analyzer.Spec
|
||||
// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes
|
||||
// a Deployment as an example
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=analyzers,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=analyzers/status,verbs=get;update;patch
|
||||
func (r *ReconcileAnalyzer) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the Analyzer instance
|
||||
instance := &troubleshootv1beta1.Analyzer{}
|
||||
err := r.Get(context.TODO(), request.NamespacedName, instance)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// TODO(user): Change this to be the object type created by your controller
|
||||
// Define the desired Deployment object
|
||||
deploy := &appsv1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: instance.Name + "-deployment",
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// TODO(user): Change this for the object type created by your controller
|
||||
// Check if the Deployment already exists
|
||||
found := &appsv1.Deployment{}
|
||||
err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found)
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
log.Info("Creating Deployment", "namespace", deploy.Namespace, "name", deploy.Name)
|
||||
err = r.Create(context.TODO(), deploy)
|
||||
return reconcile.Result{}, err
|
||||
} else if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// TODO(user): Change this for the object type created by your controller
|
||||
// Update the found object and write the result back if there are any changes
|
||||
if !reflect.DeepEqual(deploy.Spec, found.Spec) {
|
||||
found.Spec = deploy.Spec
|
||||
log.Info("Updating Deployment", "namespace", deploy.Namespace, "name", deploy.Name)
|
||||
err = r.Update(context.TODO(), found)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/apis"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package analyzer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package analyzerjob
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
/**
|
||||
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
|
||||
* business logic. Delete these comments after modifying this file.*
|
||||
*/
|
||||
|
||||
// Add creates a new AnalyzerJob Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcileAnalyzerJob{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("analyzerjob-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to AnalyzerJob
|
||||
err = c.Watch(&source.Kind{Type: &troubleshootv1beta1.AnalyzerJob{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(user): Modify this to be the types you create
|
||||
// Uncomment watch a Deployment created by AnalyzerJob - change this for objects you create
|
||||
err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &troubleshootv1beta1.AnalyzerJob{},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcileAnalyzerJob{}
|
||||
|
||||
// ReconcileAnalyzerJob reconciles a AnalyzerJob object
|
||||
type ReconcileAnalyzerJob struct {
|
||||
client.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a AnalyzerJob object and makes changes based on the state read
|
||||
// and what is in the AnalyzerJob.Spec
|
||||
// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes
|
||||
// a Deployment as an example
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=analyzerjobs,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=analyzerjobs/status,verbs=get;update;patch
|
||||
func (r *ReconcileAnalyzerJob) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the AnalyzerJob instance
|
||||
instance := &troubleshootv1beta1.AnalyzerJob{}
|
||||
err := r.Get(context.TODO(), request.NamespacedName, instance)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// TODO(user): Change this to be the object type created by your controller
|
||||
// Define the desired Deployment object
|
||||
deploy := &appsv1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: instance.Name + "-deployment",
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"},
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "nginx",
|
||||
Image: "nginx",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// TODO(user): Change this for the object type created by your controller
|
||||
// Check if the Deployment already exists
|
||||
found := &appsv1.Deployment{}
|
||||
err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found)
|
||||
if err != nil && errors.IsNotFound(err) {
|
||||
log.Info("Creating Deployment", "namespace", deploy.Namespace, "name", deploy.Name)
|
||||
err = r.Create(context.TODO(), deploy)
|
||||
return reconcile.Result{}, err
|
||||
} else if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// TODO(user): Change this for the object type created by your controller
|
||||
// Update the found object and write the result back if there are any changes
|
||||
if !reflect.DeepEqual(deploy.Spec, found.Spec) {
|
||||
found.Spec = deploy.Spec
|
||||
log.Info("Updating Deployment", "namespace", deploy.Namespace, "name", deploy.Name)
|
||||
err = r.Update(context.TODO(), found)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package analyzerjob
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/apis"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package analyzerjob
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
// Add creates a new Collector Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcileCollector{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("collector-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to Collector
|
||||
err = c.Watch(&source.Kind{Type: &troubleshootv1beta1.Collector{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcileCollector{}
|
||||
|
||||
// ReconcileCollector reconciles a Collector object
|
||||
type ReconcileCollector struct {
|
||||
client.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a Collector object and makes changes based on the state read
|
||||
// and what is in the Collector.Spec
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=collectors,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=collectors/status,verbs=get;update;patch
|
||||
func (r *ReconcileCollector) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the Collector instance
|
||||
instance := &troubleshootv1beta1.Collector{}
|
||||
err := r.Get(context.TODO(), request.NamespacedName, instance)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// The troubleshoot spec doesn't really do anything. the work
|
||||
// is performed in the troubleshootjob crd. this one is really
|
||||
// primarily used as a packaging format2
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileCollector) getCollectorConfigMapSpec(instance *troubleshootv1beta1.Collector) (*v1.ConfigMap, error) {
|
||||
configMap := v1.ConfigMap{}
|
||||
|
||||
return &configMap, nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/apis"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package collector
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package collectorjob
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
)
|
||||
|
||||
func (r *ReconcileCollectorJob) createCollectorServer(instance *troubleshootv1beta1.CollectorJob) error {
|
||||
name := fmt.Sprintf("%s-%s", instance.Name, "collector")
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
}
|
||||
|
||||
found := &corev1.Pod{}
|
||||
err := r.Get(context.Background(), namespacedName, found)
|
||||
if err == nil || !kuberneteserrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
imageName := "replicated/troubleshoot:latest"
|
||||
imagePullPolicy := corev1.PullAlways
|
||||
|
||||
if instance.Spec.Image != "" {
|
||||
imageName = instance.Spec.Image
|
||||
}
|
||||
if instance.Spec.ImagePullPolicy != "" {
|
||||
imagePullPolicy = corev1.PullPolicy(instance.Spec.ImagePullPolicy)
|
||||
}
|
||||
|
||||
podLabels := make(map[string]string)
|
||||
podLabels["collector"] = instance.Name
|
||||
podLabels["troubleshoot-role"] = "collector"
|
||||
|
||||
pod := corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
Labels: podLabels,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
RestartPolicy: corev1.RestartPolicyNever,
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Image: imageName,
|
||||
ImagePullPolicy: imagePullPolicy,
|
||||
Name: "collector",
|
||||
Command: []string{"collector"},
|
||||
Args: []string{"server"},
|
||||
Ports: []corev1.ContainerPort{
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: 8000,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := controllerutil.SetControllerReference(instance, &pod, r.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.Create(context.Background(), &pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
service := corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Service",
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
Selector: podLabels,
|
||||
Type: corev1.ServiceTypeClusterIP,
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
Name: "http",
|
||||
Port: 8000,
|
||||
TargetPort: intstr.FromInt(8000),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := controllerutil.SetControllerReference(instance, &service, r.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.Create(context.Background(), &service); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
instance.Status.ServerPodName = name
|
||||
instance.Status.ServerPodNamespace = instance.Namespace
|
||||
instance.Status.ServerPodPort = 8000
|
||||
instance.Status.IsServerReady = true
|
||||
|
||||
// wait for the server to be ready
|
||||
// TODO
|
||||
time.Sleep(time.Second * 5)
|
||||
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,439 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package collectorjob
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootclientv1beta1 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta1"
|
||||
collectrunner "github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/k8sutil"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/logger"
|
||||
"gopkg.in/yaml.v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
// Add creates a new CollectorJob Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcileCollectorJob{
|
||||
Client: mgr.GetClient(),
|
||||
config: mgr.GetConfig(),
|
||||
scheme: mgr.GetScheme(),
|
||||
}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("collectorjob-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to CollectorJob
|
||||
err = c.Watch(&source.Kind{Type: &troubleshootv1beta1.CollectorJob{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.EnqueueRequestForOwner{
|
||||
IsController: true,
|
||||
OwnerType: &troubleshootv1beta1.CollectorJob{},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcileCollectorJob{}
|
||||
|
||||
// ReconcileCollectorJob reconciles a CollectorJob object
|
||||
type ReconcileCollectorJob struct {
|
||||
client.Client
|
||||
config *rest.Config
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a CollectorJob object and makes changes based on the state read
|
||||
// and what is in the CollectorJob.Spec
|
||||
// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes
|
||||
// a Deployment as an example
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=collectorjobs,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=collectorjobs/status,verbs=get;update;patch
|
||||
func (r *ReconcileCollectorJob) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the CollectorJob instance
|
||||
instance := &troubleshootv1beta1.CollectorJob{}
|
||||
err := r.Get(context.Background(), request.NamespacedName, instance)
|
||||
if err != nil {
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// for a new object, create the http server
|
||||
if !instance.Status.IsServerReady {
|
||||
if err := r.createCollectorServer(instance); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
namespace := instance.Namespace
|
||||
if instance.Spec.Collector.Namespace != "" {
|
||||
namespace = instance.Spec.Collector.Namespace
|
||||
}
|
||||
|
||||
collectorSpec, err := r.getCollectorSpec(namespace, instance.Spec.Collector.Name)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
for _, collector := range collectorSpec.Spec.Collectors {
|
||||
if err := r.reconileOneCollectorJob(instance, collector); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileCollectorJob) getCollectorSpec(namespace string, name string) (*troubleshootv1beta1.Collector, error) {
|
||||
troubleshootClient, err := troubleshootclientv1beta1.NewForConfig(r.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
collector, err := troubleshootClient.Collectors(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return collector, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileCollectorJob) reconileOneCollectorJob(instance *troubleshootv1beta1.CollectorJob, collect *troubleshootv1beta1.Collect) error {
|
||||
if contains(instance.Status.Running, collectrunner.DeterministicIDForCollector(collect)) {
|
||||
collectorPod, err := r.getCollectorPod(instance, collect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if collectorPod.Status.Phase == corev1.PodFailed {
|
||||
instance.Status.Failed = append(instance.Status.Failed, collectrunner.DeterministicIDForCollector(collect))
|
||||
instance.Status.Running = remove(instance.Status.Running, collectrunner.DeterministicIDForCollector(collect))
|
||||
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
if collectorPod.Status.Phase == corev1.PodSucceeded {
|
||||
// Get the logs
|
||||
podLogOpts := corev1.PodLogOptions{}
|
||||
|
||||
k8sClient, err := kubernetes.NewForConfig(r.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req := k8sClient.CoreV1().Pods(collectorPod.Namespace).GetLogs(collectorPod.Name, &podLogOpts)
|
||||
podLogs, err := req.Stream()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer podLogs.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
_, err = io.Copy(buf, podLogs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
|
||||
serviceURI := ""
|
||||
|
||||
// For local dev, it's useful to run the manager out of the cluster
|
||||
// but this is difficult to connect to the collector service running in-cluster
|
||||
// so, we can create a local port-foward to get back into the cluster.
|
||||
stopCh := make(chan struct{}, 1)
|
||||
if os.Getenv("TROUBLESHOOT_EXTERNAL_MANAGER") != "" {
|
||||
logger.Printf("setting up port forwarding because the manager is not running in the cluster\n")
|
||||
|
||||
// this isn't likely to be very solid
|
||||
localPort := 3000 + rand.New(rand.NewSource(time.Now().UnixNano())).Intn(999)
|
||||
|
||||
ch, err := k8sutil.PortForward(r.config, localPort, 8000, instance.Namespace, instance.Name+"-collector")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stopCh = ch
|
||||
serviceURI = fmt.Sprintf("http://localhost:%d", localPort)
|
||||
} else {
|
||||
serviceURI = fmt.Sprintf("http://%s-collector.%s.svc.cluster.local:8000", instance.Name, instance.Namespace)
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("PUT", serviceURI, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.ContentLength = int64(len(buf.String()))
|
||||
request.Header.Add("collector-id", collectrunner.DeterministicIDForCollector(collect))
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 201 {
|
||||
return errors.New("failed to send logs to collector")
|
||||
}
|
||||
|
||||
if os.Getenv("TROUBLESHOOT_EXTERNAL_MANAGER") != "" {
|
||||
logger.Printf("stopping port forwarding\n")
|
||||
close(stopCh)
|
||||
}
|
||||
|
||||
instance.Status.Successful = append(instance.Status.Successful, collectrunner.DeterministicIDForCollector(collect))
|
||||
instance.Status.Running = remove(instance.Status.Running, collectrunner.DeterministicIDForCollector(collect))
|
||||
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := r.createSpecInConfigMap(instance, collect); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.createCollectorPod(instance, collect); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcileCollectorJob) createSpecInConfigMap(instance *troubleshootv1beta1.CollectorJob, collector *troubleshootv1beta1.Collect) error {
|
||||
name := fmt.Sprintf("%s-%s", instance.Name, collectrunner.DeterministicIDForCollector(collector))
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
}
|
||||
|
||||
found := &corev1.ConfigMap{}
|
||||
err := r.Get(context.Background(), namespacedName, found)
|
||||
if err == nil || !kuberneteserrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
specContents, err := yaml.Marshal(collector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
specData := make(map[string]string)
|
||||
specData["collector.yaml"] = string(specContents)
|
||||
|
||||
configMap := corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
Data: specData,
|
||||
}
|
||||
|
||||
if err := controllerutil.SetControllerReference(instance, &configMap, r.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.Create(context.Background(), &configMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcileCollectorJob) getCollectorPod(instance *troubleshootv1beta1.CollectorJob, collector *troubleshootv1beta1.Collect) (*corev1.Pod, error) {
|
||||
name := fmt.Sprintf("%s-%s", instance.Name, collectrunner.DeterministicIDForCollector(collector))
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
}
|
||||
|
||||
pod := &corev1.Pod{}
|
||||
err := r.Get(context.Background(), namespacedName, pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pod, nil
|
||||
}
|
||||
|
||||
func (r *ReconcileCollectorJob) createCollectorPod(instance *troubleshootv1beta1.CollectorJob, collector *troubleshootv1beta1.Collect) error {
|
||||
name := fmt.Sprintf("%s-%s", instance.Name, collectrunner.DeterministicIDForCollector(collector))
|
||||
|
||||
namespacedName := types.NamespacedName{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
}
|
||||
|
||||
found := &corev1.Pod{}
|
||||
err := r.Get(context.Background(), namespacedName, found)
|
||||
if err == nil || !kuberneteserrors.IsNotFound(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
imageName := "replicated/troubleshoot:latest"
|
||||
imagePullPolicy := corev1.PullAlways
|
||||
|
||||
if instance.Spec.Image != "" {
|
||||
imageName = instance.Spec.Image
|
||||
}
|
||||
if instance.Spec.ImagePullPolicy != "" {
|
||||
imagePullPolicy = corev1.PullPolicy(instance.Spec.ImagePullPolicy)
|
||||
}
|
||||
|
||||
pod := corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: instance.Namespace,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Pod",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
RestartPolicy: corev1.RestartPolicyNever,
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Image: imageName,
|
||||
ImagePullPolicy: imagePullPolicy,
|
||||
Name: collectrunner.DeterministicIDForCollector(collector),
|
||||
Command: []string{"collector"},
|
||||
Args: []string{
|
||||
"run",
|
||||
fmt.Sprintf("--redact=%t", instance.Spec.Redact),
|
||||
"--collector",
|
||||
"/troubleshoot/specs/collector.yaml",
|
||||
},
|
||||
VolumeMounts: []corev1.VolumeMount{
|
||||
{
|
||||
Name: "collector",
|
||||
MountPath: "/troubleshoot/specs",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Volumes: []corev1.Volume{
|
||||
{
|
||||
Name: "collector",
|
||||
VolumeSource: corev1.VolumeSource{
|
||||
ConfigMap: &corev1.ConfigMapVolumeSource{
|
||||
LocalObjectReference: corev1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := controllerutil.SetControllerReference(instance, &pod, r.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.Create(context.Background(), &pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
instance.Status.Running = append(instance.Status.Running, collectrunner.DeterministicIDForCollector(collector))
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func remove(s []string, r string) []string {
|
||||
for i, v := range s {
|
||||
if v == r {
|
||||
return append(s[:i], s[i+1:]...)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package collectorjob
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/apis"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package collectorjob
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package controller
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
)
|
||||
|
||||
// AddToManagerFuncs is a list of functions to add all Controllers to the Manager
|
||||
var AddToManagerFuncs []func(manager.Manager) error
|
||||
|
||||
// AddToManager adds all Controllers to the Manager
|
||||
func AddToManager(m manager.Manager) error {
|
||||
for _, f := range AddToManagerFuncs {
|
||||
if err := f(m); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package preflight
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
// Add creates a new Preflight Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcilePreflight{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("preflight-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to Preflight
|
||||
err = c.Watch(&source.Kind{Type: &troubleshootv1beta1.Preflight{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcilePreflight{}
|
||||
|
||||
// ReconcilePreflight reconciles a Preflight object
|
||||
type ReconcilePreflight struct {
|
||||
client.Client
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a Preflight object and makes changes based on the state read
|
||||
// and what is in the Preflight.Spec
|
||||
// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes
|
||||
// a Deployment as an example
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=preflights,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=preflights/status,verbs=get;update;patch
|
||||
func (r *ReconcilePreflight) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the Preflight instance
|
||||
instance := &troubleshootv1beta1.Preflight{}
|
||||
err := r.Get(context.TODO(), request.NamespacedName, instance)
|
||||
if err != nil {
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package preflight
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/apis"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package preflight
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
"golang.org/x/net/context"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var c client.Client
|
||||
|
||||
var expectedRequest = reconcile.Request{NamespacedName: types.NamespacedName{Name: "foo", Namespace: "default"}}
|
||||
var depKey = types.NamespacedName{Name: "foo-deployment", Namespace: "default"}
|
||||
|
||||
const timeout = time.Second * 5
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
g := gomega.NewGomegaWithT(t)
|
||||
instance := &troubleshootv1beta1.Preflight{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}}
|
||||
|
||||
// Setup the Manager and Controller. Wrap the Controller Reconcile function so it writes each request to a
|
||||
// channel when it is finished.
|
||||
mgr, err := manager.New(cfg, manager.Options{})
|
||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
c = mgr.GetClient()
|
||||
|
||||
recFn, requests := SetupTestReconcile(newReconciler(mgr))
|
||||
g.Expect(add(mgr, recFn)).NotTo(gomega.HaveOccurred())
|
||||
|
||||
stopMgr, mgrStopped := StartTestManager(mgr, g)
|
||||
|
||||
defer func() {
|
||||
close(stopMgr)
|
||||
mgrStopped.Wait()
|
||||
}()
|
||||
|
||||
// Create the Preflight object and expect the Reconcile and Deployment to be created
|
||||
err = c.Create(context.TODO(), instance)
|
||||
// The instance object may not be a valid object because it might be missing some required fields.
|
||||
// Please modify the instance object by adding required fields and then remove the following if statement.
|
||||
if apierrors.IsInvalid(err) {
|
||||
t.Logf("failed to create object, got an invalid object error: %v", err)
|
||||
return
|
||||
}
|
||||
g.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
defer c.Delete(context.TODO(), instance)
|
||||
g.Eventually(requests, timeout).Should(gomega.Receive(gomega.Equal(expectedRequest)))
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package preflightjob
|
||||
|
||||
import (
|
||||
"context"
|
||||
// "fmt"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
)
|
||||
|
||||
type AnalysisResult struct {
|
||||
Success bool
|
||||
TextOutput string
|
||||
}
|
||||
|
||||
func (r *ReconcilePreflightJob) reconcilePreflightAnalyzers(instance *troubleshootv1beta1.PreflightJob, preflight *troubleshootv1beta1.Preflight) error {
|
||||
for _, analyzer := range preflight.Spec.Analyzers {
|
||||
if err := r.reconcileOnePreflightAnalyzer(instance, analyzer); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcilePreflightJob) reconcileOnePreflightAnalyzer(instance *troubleshootv1beta1.PreflightJob, analyze *troubleshootv1beta1.Analyze) error {
|
||||
if contains(instance.Status.AnalyzersRunning, idForAnalyzer(analyze)) {
|
||||
// these are the analyzers we want to attempt to run
|
||||
if analyze.ClusterVersion != nil {
|
||||
result, err := r.analyzeClusterVersion(instance, analyze.ClusterVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if result.Success == false {
|
||||
return nil // collectors are not yet ready
|
||||
}
|
||||
|
||||
instance.Status.AnalyzersSuccessful = append(instance.Status.AnalyzersSuccessful, idForAnalyzer(analyze))
|
||||
instance.Status.AnalyzersRunning = remove(instance.Status.AnalyzersRunning, idForAnalyzer(analyze))
|
||||
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func idForAnalyzer(analyzer *troubleshootv1beta1.Analyze) string {
|
||||
if analyzer.ClusterVersion != nil {
|
||||
return "cluster-version"
|
||||
}
|
||||
|
||||
if analyzer.StorageClass != nil {
|
||||
return "storage-classes"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package preflightjob
|
||||
|
||||
import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
)
|
||||
|
||||
func (r *ReconcilePreflightJob) analyzeClusterVersion(instance *troubleshootv1beta1.PreflightJob, clusterVersion *troubleshootv1beta1.ClusterVersion) (*AnalysisResult, error) {
|
||||
return &AnalysisResult{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package preflightjob
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
collectrunner "github.com/replicatedhq/troubleshoot/pkg/collect"
|
||||
)
|
||||
|
||||
func (r *ReconcilePreflightJob) reconcilePreflightCollectors(instance *troubleshootv1beta1.PreflightJob, preflight *troubleshootv1beta1.Preflight) error {
|
||||
requestedCollectorIDs := make([]string, 0, 0)
|
||||
for _, collector := range preflight.Spec.Collectors {
|
||||
requestedCollectorIDs = append(requestedCollectorIDs, collectrunner.DeterministicIDForCollector(collector))
|
||||
if err := r.reconcileOnePreflightCollector(instance, collector); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !contains(requestedCollectorIDs, "cluster-info") {
|
||||
clusterInfo := troubleshootv1beta1.Collect{
|
||||
ClusterInfo: &troubleshootv1beta1.ClusterInfo{},
|
||||
}
|
||||
if err := r.reconcileOnePreflightCollector(instance, &clusterInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !contains(requestedCollectorIDs, "cluster-resources") {
|
||||
clusterResources := troubleshootv1beta1.Collect{
|
||||
ClusterResources: &troubleshootv1beta1.ClusterResources{},
|
||||
}
|
||||
if err := r.reconcileOnePreflightCollector(instance, &clusterResources); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcilePreflightJob) reconcileOnePreflightCollector(instance *troubleshootv1beta1.PreflightJob, collect *troubleshootv1beta1.Collect) error {
|
||||
if contains(instance.Status.CollectorsRunning, collectrunner.DeterministicIDForCollector(collect)) {
|
||||
// preflight just leaves these stopped containers.
|
||||
// it's playing with fire a little, but the analyzers can just
|
||||
// read from the stdout of the stopped container
|
||||
//
|
||||
// in the very common use case (what we are building for today)
|
||||
// there's not too much risk in something destroying and reaping that stopped pod
|
||||
// immediately. this is a longer term problem to solve, maybe something,
|
||||
// the mananger? can broker these collector results. but, ya know...
|
||||
|
||||
instance.Status.CollectorsSuccessful = append(instance.Status.CollectorsSuccessful, collectrunner.DeterministicIDForCollector(collect))
|
||||
instance.Status.CollectorsRunning = remove(instance.Status.CollectorsRunning, collectrunner.DeterministicIDForCollector(collect))
|
||||
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
_, _, err := collectrunner.CreateCollector(r.Client, r.scheme, instance, instance.Name, instance.Namespace, "", "preflight", collect, instance.Spec.Image, instance.Spec.ImagePullPolicy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
instance.Status.CollectorsRunning = append(instance.Status.CollectorsRunning, collectrunner.DeterministicIDForCollector(collect))
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func remove(s []string, r string) []string {
|
||||
for i, v := range s {
|
||||
if v == r {
|
||||
return append(s[:i], s[i+1:]...)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package preflightjob
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
troubleshootclientv1beta1 "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/typed/troubleshoot/v1beta1"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/preflight"
|
||||
kuberneteserrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
|
||||
// Add creates a new PreflightJob Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
|
||||
// and Start it when the Manager is Started.
|
||||
func Add(mgr manager.Manager) error {
|
||||
return add(mgr, newReconciler(mgr))
|
||||
}
|
||||
|
||||
// newReconciler returns a new reconcile.Reconciler
|
||||
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
|
||||
return &ReconcilePreflightJob{
|
||||
Client: mgr.GetClient(),
|
||||
config: mgr.GetConfig(),
|
||||
scheme: mgr.GetScheme(),
|
||||
}
|
||||
}
|
||||
|
||||
// add adds a new Controller to mgr with r as the reconcile.Reconciler
|
||||
func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
||||
// Create a new controller
|
||||
c, err := controller.New("preflightjob-controller", mgr, controller.Options{Reconciler: r})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch for changes to PreflightJob
|
||||
err = c.Watch(&source.Kind{Type: &troubleshootv1beta1.PreflightJob{}}, &handler.EnqueueRequestForObject{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ reconcile.Reconciler = &ReconcilePreflightJob{}
|
||||
|
||||
// ReconcilePreflightJob reconciles a PreflightJob object
|
||||
type ReconcilePreflightJob struct {
|
||||
client.Client
|
||||
config *rest.Config
|
||||
scheme *runtime.Scheme
|
||||
}
|
||||
|
||||
// Reconcile reads that state of the cluster for a PreflightJob object and makes changes based on the state read
|
||||
// and what is in the PreflightJob.Spec
|
||||
// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes
|
||||
// a Deployment as an example
|
||||
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=apps,resources=deployments/status,verbs=get;update;patch
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=preflightjobs,verbs=get;list;watch;create;update;patch;delete
|
||||
// +kubebuilder:rbac:groups=troubleshoot.replicated.com,resources=preflightjobs/status,verbs=get;update;patch
|
||||
func (r *ReconcilePreflightJob) Reconcile(request reconcile.Request) (reconcile.Result, error) {
|
||||
// Fetch the PreflightJob instance
|
||||
instance := &troubleshootv1beta1.PreflightJob{}
|
||||
err := r.Get(context.TODO(), request.NamespacedName, instance)
|
||||
if err != nil {
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
// Object not found, return. Created objects are automatically garbage collected.
|
||||
// For additional cleanup logic use finalizers.
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
// Error reading the object - requeue the request.
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if !instance.Status.IsServerReady {
|
||||
preflightServerOptions := preflight.PreflightServerOptions{
|
||||
ImageName: instance.Spec.Image,
|
||||
PullPolicy: instance.Spec.ImagePullPolicy,
|
||||
Name: instance.Name,
|
||||
Namespace: instance.Namespace,
|
||||
OwnerReference: instance,
|
||||
}
|
||||
pod, _, err := preflight.CreatePreflightServer(r.Client, r.scheme, preflightServerOptions)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
instance.Status.ServerPodName = pod.Name
|
||||
instance.Status.ServerPodNamespace = pod.Namespace
|
||||
instance.Status.ServerPodPort = 8000
|
||||
instance.Status.IsServerReady = true
|
||||
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace := instance.Namespace
|
||||
if instance.Spec.Preflight.Namespace != "" {
|
||||
namespace = instance.Spec.Preflight.Namespace
|
||||
}
|
||||
|
||||
preflightSpec, err := r.getPreflightSpec(namespace, instance.Spec.Preflight.Name)
|
||||
if err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if len(instance.Status.AnalyzersRunning) == 0 && len(instance.Status.AnalyzersSuccessful) == 0 && len(instance.Status.AnalyzersFailed) == 0 {
|
||||
// Add them all!
|
||||
analyzersRunning := []string{}
|
||||
for _, analyzer := range preflightSpec.Spec.Analyzers {
|
||||
analyzersRunning = append(analyzersRunning, idForAnalyzer(analyzer))
|
||||
}
|
||||
|
||||
instance.Status.AnalyzersRunning = analyzersRunning
|
||||
if err := r.Update(context.Background(), instance); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.reconcilePreflightCollectors(instance, preflightSpec); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
if err := r.reconcilePreflightAnalyzers(instance, preflightSpec); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// just finished, nothing to do
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
func (r *ReconcilePreflightJob) getPreflightSpec(namespace string, name string) (*troubleshootv1beta1.Preflight, error) {
|
||||
troubleshootClient, err := troubleshootclientv1beta1.NewForConfig(r.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
preflight, err := troubleshootClient.Preflights(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if kuberneteserrors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return preflight, nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package preflightjob
|
||||
|
||||
import (
|
||||
stdlog "log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/onsi/gomega"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/apis"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
t := &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds")},
|
||||
}
|
||||
apis.AddToScheme(scheme.Scheme)
|
||||
|
||||
var err error
|
||||
if cfg, err = t.Start(); err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
t.Stop()
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// SetupTestReconcile returns a reconcile.Reconcile implementation that delegates to inner and
|
||||
// writes the request to requests after Reconcile is finished.
|
||||
func SetupTestReconcile(inner reconcile.Reconciler) (reconcile.Reconciler, chan reconcile.Request) {
|
||||
requests := make(chan reconcile.Request)
|
||||
fn := reconcile.Func(func(req reconcile.Request) (reconcile.Result, error) {
|
||||
result, err := inner.Reconcile(req)
|
||||
requests <- req
|
||||
return result, err
|
||||
})
|
||||
return fn, requests
|
||||
}
|
||||
|
||||
// StartTestManager adds recFn
|
||||
func StartTestManager(mgr manager.Manager, g *gomega.GomegaWithT) (chan struct{}, *sync.WaitGroup) {
|
||||
stop := make(chan struct{})
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
g.Expect(mgr.Start(stop)).NotTo(gomega.HaveOccurred())
|
||||
}()
|
||||
return stop, wg
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Replicated, Inc..
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package preflightjob
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReconcile(t *testing.T) {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user