mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-04-15 07:16:34 +00:00
Merge pull request #175 from replicatedhq/laverya/custom-redactors
last-mile and per-collector redactor specs
This commit is contained in:
@@ -43,6 +43,7 @@ from a server that can be used to assist when troubleshooting a server.`,
|
||||
cmd.Flags().String("collectors", "", "name of the collectors to use")
|
||||
cmd.Flags().String("image", "", "the full name of the collector image to use")
|
||||
cmd.Flags().String("pullpolicy", "", "the pull policy of the collector image")
|
||||
cmd.Flags().String("redactors", "", "name of the additional redactors to use")
|
||||
cmd.Flags().Bool("redact", true, "enable/disable default redactions")
|
||||
cmd.Flags().Bool("collect-without-permissions", false, "always run troubleshoot collectors even if some require permissions that troubleshoot does not have")
|
||||
|
||||
|
||||
@@ -56,6 +56,23 @@ func runTroubleshoot(v *viper.Viper, arg string) error {
|
||||
|
||||
collector := obj.(*troubleshootv1beta1.Collector)
|
||||
|
||||
var additionalRedactors *troubleshootv1beta1.Redactor
|
||||
if v.GetString("redactors") != "" {
|
||||
redactorContent, err := loadSpec(v, v.GetString("redactors"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to load redactor spec")
|
||||
}
|
||||
obj, _, err := decode([]byte(redactorContent), nil, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to parse redactors %s", v.GetString("redactors"))
|
||||
}
|
||||
var ok bool
|
||||
additionalRedactors, ok = obj.(*troubleshootv1beta1.Redactor)
|
||||
if !ok {
|
||||
return fmt.Errorf("%s is not a troubleshootv1beta1 redactor type", v.GetString("redactors"))
|
||||
}
|
||||
}
|
||||
|
||||
s := spin.New()
|
||||
finishedCh := make(chan bool, 1)
|
||||
progressChan := make(chan interface{}, 0) // non-zero buffer can result in missed messages
|
||||
@@ -87,7 +104,7 @@ func runTroubleshoot(v *viper.Viper, arg string) error {
|
||||
close(finishedCh)
|
||||
}()
|
||||
|
||||
archivePath, err := runCollectors(v, *collector, progressChan)
|
||||
archivePath, err := runCollectors(v, *collector, additionalRedactors, progressChan)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "run collectors")
|
||||
}
|
||||
@@ -193,7 +210,7 @@ func canTryInsecure(v *viper.Viper) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, progressChan chan interface{}) (string, error) {
|
||||
func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, additionalRedactors *troubleshootv1beta1.Redactor, progressChan chan interface{}) (string, error) {
|
||||
bundlePath, err := ioutil.TempDir("", "troubleshoot")
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "create temp dir")
|
||||
@@ -241,6 +258,11 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, prog
|
||||
return "", errors.New("insufficient permissions to run all collectors")
|
||||
}
|
||||
|
||||
globalRedactors := []*troubleshootv1beta1.Redact{}
|
||||
if additionalRedactors != nil {
|
||||
globalRedactors = additionalRedactors.Spec.Redactors
|
||||
}
|
||||
|
||||
// Run preflights collectors synchronously
|
||||
for _, collector := range collectors {
|
||||
if len(collector.RBACErrors) > 0 {
|
||||
@@ -253,7 +275,7 @@ func runCollectors(v *viper.Viper, collector troubleshootv1beta1.Collector, prog
|
||||
|
||||
progressChan <- collector.GetDisplayName()
|
||||
|
||||
result, err := collector.RunCollectorSync()
|
||||
result, err := collector.RunCollectorSync(globalRedactors)
|
||||
if err != nil {
|
||||
progressChan <- fmt.Errorf("failed to run collector %q: %v", collector.GetDisplayName(), err)
|
||||
continue
|
||||
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
)
|
||||
|
||||
type CollectorMeta struct {
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
CollectorName string `json:"collectorName,omitempty" yaml:"collectorName,omitempty"`
|
||||
Redactors []*Redact `json:"redactors,omitempty" yaml:"redactors,omitempty"`
|
||||
// +optional
|
||||
Exclude multitype.BoolOrString `json:"exclude,omitempty" yaml:"exclude,omitempty"`
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type AfterCollection struct {
|
||||
type CollectorSpec struct {
|
||||
Collectors []*Collect `json:"collectors,omitempty" yaml:"collectors,omitempty"`
|
||||
AfterCollection []*AfterCollection `json:"afterCollection,omitempty" yaml:"afterCollection,omitempty"`
|
||||
GlobalRedactors []*Redact `json:"globalRedactors,omitempty" yaml:"globalRedactors,omitempty"`
|
||||
}
|
||||
|
||||
// CollectorStatus defines the observed state of Collector
|
||||
|
||||
9
pkg/apis/troubleshoot/v1beta1/redact_shared.go
Normal file
9
pkg/apis/troubleshoot/v1beta1/redact_shared.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package v1beta1
|
||||
|
||||
type Redact struct {
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
File string `json:"file,omitempty" yaml:"file,omitempty"`
|
||||
Files []string `json:"files,omitempty" yaml:"files,omitempty"`
|
||||
Values []string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
Regex []string `json:"regex,omitempty" yaml:"regex,omitempty"`
|
||||
}
|
||||
56
pkg/apis/troubleshoot/v1beta1/redact_types.go
Normal file
56
pkg/apis/troubleshoot/v1beta1/redact_types.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// RedactorSpec defines the desired state of Redactor
|
||||
type RedactorSpec struct {
|
||||
Redactors []*Redact `json:"redacts,omitempty"`
|
||||
}
|
||||
|
||||
// RedactorStatus defines the observed state of Redactor
|
||||
type RedactorStatus struct {
|
||||
}
|
||||
|
||||
// +genclient
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Redactor is the Schema for the redaction API
|
||||
// +k8s:openapi-gen=true
|
||||
type Redactor struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
Spec RedactorSpec `json:"spec,omitempty"`
|
||||
Status RedactorStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// RedactorList contains a list of Redactor
|
||||
type RedactorList struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ListMeta `json:"metadata,omitempty"`
|
||||
Items []Redactor `json:"items"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&Redactor{}, &RedactorList{})
|
||||
}
|
||||
@@ -285,7 +285,7 @@ func (in *AnalyzerStatus) DeepCopy() *AnalyzerStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterInfo) DeepCopyInto(out *ClusterInfo) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterInfo.
|
||||
@@ -301,7 +301,7 @@ func (in *ClusterInfo) DeepCopy() *ClusterInfo {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ClusterResources) DeepCopyInto(out *ClusterResources) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterResources.
|
||||
@@ -347,17 +347,17 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
if in.ClusterInfo != nil {
|
||||
in, out := &in.ClusterInfo, &out.ClusterInfo
|
||||
*out = new(ClusterInfo)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.ClusterResources != nil {
|
||||
in, out := &in.ClusterResources, &out.ClusterResources
|
||||
*out = new(ClusterResources)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Secret != nil {
|
||||
in, out := &in.Secret, &out.Secret
|
||||
*out = new(Secret)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Logs != nil {
|
||||
in, out := &in.Logs, &out.Logs
|
||||
@@ -377,7 +377,7 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
if in.Data != nil {
|
||||
in, out := &in.Data, &out.Data
|
||||
*out = new(Data)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Copy != nil {
|
||||
in, out := &in.Copy, &out.Copy
|
||||
@@ -392,17 +392,17 @@ func (in *Collect) DeepCopyInto(out *Collect) {
|
||||
if in.Postgres != nil {
|
||||
in, out := &in.Postgres, &out.Postgres
|
||||
*out = new(Database)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Mysql != nil {
|
||||
in, out := &in.Mysql, &out.Mysql
|
||||
*out = new(Database)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.Redis != nil {
|
||||
in, out := &in.Redis, &out.Redis
|
||||
*out = new(Database)
|
||||
**out = **in
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,6 +478,17 @@ func (in *CollectorList) DeepCopyObject() runtime.Object {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CollectorMeta) DeepCopyInto(out *CollectorMeta) {
|
||||
*out = *in
|
||||
if in.Redactors != nil {
|
||||
in, out := &in.Redactors, &out.Redactors
|
||||
*out = make([]*Redact, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Redact)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
out.Exclude = in.Exclude
|
||||
}
|
||||
|
||||
@@ -516,6 +527,17 @@ func (in *CollectorSpec) DeepCopyInto(out *CollectorSpec) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.GlobalRedactors != nil {
|
||||
in, out := &in.GlobalRedactors, &out.GlobalRedactors
|
||||
*out = make([]*Redact, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Redact)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CollectorSpec.
|
||||
@@ -573,7 +595,7 @@ func (in *ContainerRuntime) DeepCopy() *ContainerRuntime {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Copy) DeepCopyInto(out *Copy) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make([]string, len(*in))
|
||||
@@ -621,7 +643,7 @@ func (in *CustomResourceDefinition) DeepCopy() *CustomResourceDefinition {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Data) DeepCopyInto(out *Data) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Data.
|
||||
@@ -637,7 +659,7 @@ func (in *Data) DeepCopy() *Data {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Database) DeepCopyInto(out *Database) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Database.
|
||||
@@ -734,7 +756,7 @@ func (in *Distribution) DeepCopy() *Distribution {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Exec) DeepCopyInto(out *Exec) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make([]string, len(*in))
|
||||
@@ -787,7 +809,7 @@ func (in *Get) DeepCopy() *Get {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HTTP) DeepCopyInto(out *HTTP) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Get != nil {
|
||||
in, out := &in.Get, &out.Get
|
||||
*out = new(Get)
|
||||
@@ -887,7 +909,7 @@ func (in *LogLimits) DeepCopy() *LogLimits {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Logs) DeepCopyInto(out *Logs) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Selector != nil {
|
||||
in, out := &in.Selector, &out.Selector
|
||||
*out = make([]string, len(*in))
|
||||
@@ -1147,6 +1169,136 @@ func (in *Put) DeepCopy() *Put {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Redact) DeepCopyInto(out *Redact) {
|
||||
*out = *in
|
||||
if in.Files != nil {
|
||||
in, out := &in.Files, &out.Files
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Regex != nil {
|
||||
in, out := &in.Regex, &out.Regex
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Redact.
|
||||
func (in *Redact) DeepCopy() *Redact {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Redact)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Redactor) DeepCopyInto(out *Redactor) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
out.Status = in.Status
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Redactor.
|
||||
func (in *Redactor) DeepCopy() *Redactor {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Redactor)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Redactor) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RedactorList) DeepCopyInto(out *RedactorList) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Redactor, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedactorList.
|
||||
func (in *RedactorList) DeepCopy() *RedactorList {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RedactorList)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *RedactorList) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RedactorSpec) DeepCopyInto(out *RedactorSpec) {
|
||||
*out = *in
|
||||
if in.Redactors != nil {
|
||||
in, out := &in.Redactors, &out.Redactors
|
||||
*out = make([]*Redact, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] != nil {
|
||||
in, out := &(*in)[i], &(*out)[i]
|
||||
*out = new(Redact)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedactorSpec.
|
||||
func (in *RedactorSpec) DeepCopy() *RedactorSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RedactorSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RedactorStatus) DeepCopyInto(out *RedactorStatus) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RedactorStatus.
|
||||
func (in *RedactorStatus) DeepCopy() *RedactorStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RedactorStatus)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResultRequest) DeepCopyInto(out *ResultRequest) {
|
||||
*out = *in
|
||||
@@ -1165,7 +1317,7 @@ func (in *ResultRequest) DeepCopy() *ResultRequest {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Run) DeepCopyInto(out *Run) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
if in.Command != nil {
|
||||
in, out := &in.Command, &out.Command
|
||||
*out = make([]string, len(*in))
|
||||
@@ -1191,7 +1343,7 @@ func (in *Run) DeepCopy() *Run {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Secret) DeepCopyInto(out *Secret) {
|
||||
*out = *in
|
||||
out.CollectorMeta = in.CollectorMeta
|
||||
in.CollectorMeta.DeepCopyInto(&out.CollectorMeta)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Secret.
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package fake
|
||||
|
||||
import (
|
||||
v1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
testing "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeRedactors implements RedactorInterface
|
||||
type FakeRedactors struct {
|
||||
Fake *FakeTroubleshootV1beta1
|
||||
ns string
|
||||
}
|
||||
|
||||
var redactorsResource = schema.GroupVersionResource{Group: "troubleshoot.replicated.com", Version: "v1beta1", Resource: "redactors"}
|
||||
|
||||
var redactorsKind = schema.GroupVersionKind{Group: "troubleshoot.replicated.com", Version: "v1beta1", Kind: "Redactor"}
|
||||
|
||||
// Get takes name of the redactor, and returns the corresponding redactor object, and an error if there is any.
|
||||
func (c *FakeRedactors) Get(name string, options v1.GetOptions) (result *v1beta1.Redactor, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(redactorsResource, c.ns, name), &v1beta1.Redactor{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.Redactor), err
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Redactors that match those selectors.
|
||||
func (c *FakeRedactors) List(opts v1.ListOptions) (result *v1beta1.RedactorList, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(redactorsResource, redactorsKind, c.ns, opts), &v1beta1.RedactorList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1beta1.RedactorList{ListMeta: obj.(*v1beta1.RedactorList).ListMeta}
|
||||
for _, item := range obj.(*v1beta1.RedactorList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested redactors.
|
||||
func (c *FakeRedactors) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(redactorsResource, c.ns, opts))
|
||||
|
||||
}
|
||||
|
||||
// Create takes the representation of a redactor and creates it. Returns the server's representation of the redactor, and an error, if there is any.
|
||||
func (c *FakeRedactors) Create(redactor *v1beta1.Redactor) (result *v1beta1.Redactor, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(redactorsResource, c.ns, redactor), &v1beta1.Redactor{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.Redactor), err
|
||||
}
|
||||
|
||||
// Update takes the representation of a redactor and updates it. Returns the server's representation of the redactor, and an error, if there is any.
|
||||
func (c *FakeRedactors) Update(redactor *v1beta1.Redactor) (result *v1beta1.Redactor, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(redactorsResource, c.ns, redactor), &v1beta1.Redactor{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.Redactor), err
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
func (c *FakeRedactors) UpdateStatus(redactor *v1beta1.Redactor) (*v1beta1.Redactor, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(redactorsResource, "status", c.ns, redactor), &v1beta1.Redactor{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.Redactor), err
|
||||
}
|
||||
|
||||
// Delete takes name of the redactor and deletes it. Returns an error if one occurs.
|
||||
func (c *FakeRedactors) Delete(name string, options *v1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(redactorsResource, c.ns, name), &v1beta1.Redactor{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeRedactors) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(redactorsResource, c.ns, listOptions)
|
||||
|
||||
_, err := c.Fake.Invokes(action, &v1beta1.RedactorList{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched redactor.
|
||||
func (c *FakeRedactors) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Redactor, err error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(redactorsResource, c.ns, name, pt, data, subresources...), &v1beta1.Redactor{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*v1beta1.Redactor), err
|
||||
}
|
||||
@@ -39,6 +39,10 @@ func (c *FakeTroubleshootV1beta1) Preflights(namespace string) v1beta1.Preflight
|
||||
return &FakePreflights{c, namespace}
|
||||
}
|
||||
|
||||
func (c *FakeTroubleshootV1beta1) Redactors(namespace string) v1beta1.RedactorInterface {
|
||||
return &FakeRedactors{c, namespace}
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *FakeTroubleshootV1beta1) RESTClient() rest.Interface {
|
||||
|
||||
@@ -22,3 +22,5 @@ type AnalyzerExpansion interface{}
|
||||
type CollectorExpansion interface{}
|
||||
|
||||
type PreflightExpansion interface{}
|
||||
|
||||
type RedactorExpansion interface{}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
v1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
scheme "github.com/replicatedhq/troubleshoot/pkg/client/troubleshootclientset/scheme"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// RedactorsGetter has a method to return a RedactorInterface.
|
||||
// A group's client should implement this interface.
|
||||
type RedactorsGetter interface {
|
||||
Redactors(namespace string) RedactorInterface
|
||||
}
|
||||
|
||||
// RedactorInterface has methods to work with Redactor resources.
|
||||
type RedactorInterface interface {
|
||||
Create(*v1beta1.Redactor) (*v1beta1.Redactor, error)
|
||||
Update(*v1beta1.Redactor) (*v1beta1.Redactor, error)
|
||||
UpdateStatus(*v1beta1.Redactor) (*v1beta1.Redactor, error)
|
||||
Delete(name string, options *v1.DeleteOptions) error
|
||||
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
|
||||
Get(name string, options v1.GetOptions) (*v1beta1.Redactor, error)
|
||||
List(opts v1.ListOptions) (*v1beta1.RedactorList, error)
|
||||
Watch(opts v1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Redactor, err error)
|
||||
RedactorExpansion
|
||||
}
|
||||
|
||||
// redactors implements RedactorInterface
|
||||
type redactors struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newRedactors returns a Redactors
|
||||
func newRedactors(c *TroubleshootV1beta1Client, namespace string) *redactors {
|
||||
return &redactors{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the redactor, and returns the corresponding redactor object, and an error if there is any.
|
||||
func (c *redactors) Get(name string, options v1.GetOptions) (result *v1beta1.Redactor, err error) {
|
||||
result = &v1beta1.Redactor{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of Redactors that match those selectors.
|
||||
func (c *redactors) List(opts v1.ListOptions) (result *v1beta1.RedactorList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1beta1.RedactorList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested redactors.
|
||||
func (c *redactors) Watch(opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch()
|
||||
}
|
||||
|
||||
// Create takes the representation of a redactor and creates it. Returns the server's representation of the redactor, and an error, if there is any.
|
||||
func (c *redactors) Create(redactor *v1beta1.Redactor) (result *v1beta1.Redactor, err error) {
|
||||
result = &v1beta1.Redactor{}
|
||||
err = c.client.Post().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
Body(redactor).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Update takes the representation of a redactor and updates it. Returns the server's representation of the redactor, and an error, if there is any.
|
||||
func (c *redactors) Update(redactor *v1beta1.Redactor) (result *v1beta1.Redactor, err error) {
|
||||
result = &v1beta1.Redactor{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
Name(redactor.Name).
|
||||
Body(redactor).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateStatus was generated because the type contains a Status member.
|
||||
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
|
||||
|
||||
func (c *redactors) UpdateStatus(redactor *v1beta1.Redactor) (result *v1beta1.Redactor, err error) {
|
||||
result = &v1beta1.Redactor{}
|
||||
err = c.client.Put().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
Name(redactor.Name).
|
||||
SubResource("status").
|
||||
Body(redactor).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete takes name of the redactor and deletes it. Returns an error if one occurs.
|
||||
func (c *redactors) Delete(name string, options *v1.DeleteOptions) error {
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
Name(name).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *redactors) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
|
||||
var timeout time.Duration
|
||||
if listOptions.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
|
||||
}
|
||||
return c.client.Delete().
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
VersionedParams(&listOptions, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Body(options).
|
||||
Do().
|
||||
Error()
|
||||
}
|
||||
|
||||
// Patch applies the patch and returns the patched redactor.
|
||||
func (c *redactors) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1beta1.Redactor, err error) {
|
||||
result = &v1beta1.Redactor{}
|
||||
err = c.client.Patch(pt).
|
||||
Namespace(c.ns).
|
||||
Resource("redactors").
|
||||
SubResource(subresources...).
|
||||
Name(name).
|
||||
Body(data).
|
||||
Do().
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
@@ -28,6 +28,7 @@ type TroubleshootV1beta1Interface interface {
|
||||
AnalyzersGetter
|
||||
CollectorsGetter
|
||||
PreflightsGetter
|
||||
RedactorsGetter
|
||||
}
|
||||
|
||||
// TroubleshootV1beta1Client is used to interact with features provided by the troubleshoot.replicated.com group.
|
||||
@@ -47,6 +48,10 @@ func (c *TroubleshootV1beta1Client) Preflights(namespace string) PreflightInterf
|
||||
return newPreflights(c, namespace)
|
||||
}
|
||||
|
||||
func (c *TroubleshootV1beta1Client) Redactors(namespace string) RedactorInterface {
|
||||
return newRedactors(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new TroubleshootV1beta1Client for the given config.
|
||||
func NewForConfig(c *rest.Config) (*TroubleshootV1beta1Client, error) {
|
||||
config := *c
|
||||
|
||||
@@ -13,11 +13,6 @@ type ClusterVersion struct {
|
||||
String string `json:"string"`
|
||||
}
|
||||
|
||||
type ClusterInfoOutput struct {
|
||||
ClusterVersion []byte `json:"cluster-info/cluster_version.json,omitempty"`
|
||||
Errors []byte `json:"cluster-info/errors.json,omitempty"`
|
||||
}
|
||||
|
||||
func ClusterInfo(ctx *Context) (map[string][]byte, error) {
|
||||
client, err := kubernetes.NewForConfig(ctx.ClientConfig)
|
||||
if err != nil {
|
||||
|
||||
@@ -160,13 +160,6 @@ func ClusterResources(ctx *Context) (map[string][]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ctx.Redact {
|
||||
clusterResourcesOutput, err = redactMap(clusterResourcesOutput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return clusterResourcesOutput, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -40,129 +40,142 @@ func isExcluded(excludeVal multitype.BoolOrString) (bool, error) {
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
func (c *Collector) RunCollectorSync() (map[string][]byte, error) {
|
||||
func (c *Collector) RunCollectorSync(globalRedactors []*troubleshootv1beta1.Redact) (map[string][]byte, error) {
|
||||
var unRedacted map[string][]byte
|
||||
var isExcludedResult bool
|
||||
var err error
|
||||
var redactors []*troubleshootv1beta1.Redact
|
||||
if c.Collect.ClusterInfo != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.ClusterInfo.Exclude)
|
||||
isExcludedResult, err = isExcluded(c.Collect.ClusterInfo.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return ClusterInfo(c.GetContext())
|
||||
}
|
||||
if c.Collect.ClusterResources != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.ClusterResources.Exclude)
|
||||
unRedacted, err = ClusterInfo(c.GetContext())
|
||||
redactors = c.Collect.ClusterInfo.Redactors
|
||||
} else if c.Collect.ClusterResources != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.ClusterResources.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return ClusterResources(c.GetContext())
|
||||
}
|
||||
if c.Collect.Secret != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Secret.Exclude)
|
||||
unRedacted, err = ClusterResources(c.GetContext())
|
||||
redactors = c.Collect.ClusterResources.Redactors
|
||||
} else if c.Collect.Secret != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Secret.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Secret(c.GetContext(), c.Collect.Secret)
|
||||
}
|
||||
if c.Collect.Logs != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Logs.Exclude)
|
||||
unRedacted, err = Secret(c.GetContext(), c.Collect.Secret)
|
||||
redactors = c.Collect.Secret.Redactors
|
||||
} else if c.Collect.Logs != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Logs.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Logs(c.GetContext(), c.Collect.Logs)
|
||||
}
|
||||
if c.Collect.Run != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Run.Exclude)
|
||||
unRedacted, err = Logs(c.GetContext(), c.Collect.Logs)
|
||||
redactors = c.Collect.Logs.Redactors
|
||||
} else if c.Collect.Run != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Run.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Run(c.GetContext(), c.Collect.Run)
|
||||
}
|
||||
if c.Collect.Exec != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Exec.Exclude)
|
||||
unRedacted, err = Run(c.GetContext(), c.Collect.Run)
|
||||
redactors = c.Collect.Run.Redactors
|
||||
} else if c.Collect.Exec != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Exec.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Exec(c.GetContext(), c.Collect.Exec)
|
||||
}
|
||||
if c.Collect.Data != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Data.Exclude)
|
||||
unRedacted, err = Exec(c.GetContext(), c.Collect.Exec)
|
||||
redactors = c.Collect.Exec.Redactors
|
||||
} else if c.Collect.Data != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Data.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Data(c.GetContext(), c.Collect.Data)
|
||||
}
|
||||
if c.Collect.Copy != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Copy.Exclude)
|
||||
unRedacted, err = Data(c.GetContext(), c.Collect.Data)
|
||||
redactors = c.Collect.Data.Redactors
|
||||
} else if c.Collect.Copy != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Copy.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Copy(c.GetContext(), c.Collect.Copy)
|
||||
}
|
||||
if c.Collect.HTTP != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.HTTP.Exclude)
|
||||
unRedacted, err = Copy(c.GetContext(), c.Collect.Copy)
|
||||
redactors = c.Collect.Copy.Redactors
|
||||
} else if c.Collect.HTTP != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.HTTP.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return HTTP(c.GetContext(), c.Collect.HTTP)
|
||||
}
|
||||
if c.Collect.Postgres != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Postgres.Exclude)
|
||||
unRedacted, err = HTTP(c.GetContext(), c.Collect.HTTP)
|
||||
redactors = c.Collect.HTTP.Redactors
|
||||
} else if c.Collect.Postgres != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Postgres.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Postgres(c.GetContext(), c.Collect.Postgres)
|
||||
}
|
||||
if c.Collect.Mysql != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Mysql.Exclude)
|
||||
unRedacted, err = Postgres(c.GetContext(), c.Collect.Postgres)
|
||||
redactors = c.Collect.Postgres.Redactors
|
||||
} else if c.Collect.Mysql != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Mysql.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Mysql(c.GetContext(), c.Collect.Mysql)
|
||||
}
|
||||
if c.Collect.Redis != nil {
|
||||
isExcluded, err := isExcluded(c.Collect.Redis.Exclude)
|
||||
unRedacted, err = Mysql(c.GetContext(), c.Collect.Mysql)
|
||||
redactors = c.Collect.Mysql.Redactors
|
||||
} else if c.Collect.Redis != nil {
|
||||
isExcludedResult, err = isExcluded(c.Collect.Redis.Exclude)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isExcluded {
|
||||
if isExcludedResult {
|
||||
return nil, nil
|
||||
}
|
||||
return Redis(c.GetContext(), c.Collect.Redis)
|
||||
unRedacted, err = Redis(c.GetContext(), c.Collect.Redis)
|
||||
redactors = c.Collect.Redis.Redactors
|
||||
} else {
|
||||
return nil, errors.New("no spec found to run")
|
||||
}
|
||||
|
||||
return nil, errors.New("no spec found to run")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.Redact {
|
||||
return redactMap(unRedacted, append(redactors, globalRedactors...))
|
||||
}
|
||||
return unRedacted, nil
|
||||
}
|
||||
|
||||
func (c *Collector) GetDisplayName() string {
|
||||
|
||||
265
pkg/collect/collector_test.go
Normal file
265
pkg/collect/collector_test.go
Normal file
@@ -0,0 +1,265 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/multitype"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.undefinedlabs.com/scopeagent"
|
||||
)
|
||||
|
||||
func TestCollector_RunCollectorSyncNoRedact(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
Collect *troubleshootv1beta1.Collect
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
name: "data with custom redactor",
|
||||
Collect: &troubleshootv1beta1.Collect{
|
||||
Data: &troubleshootv1beta1.Data{
|
||||
CollectorMeta: troubleshootv1beta1.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Redactors: []*troubleshootv1beta1.Redact{
|
||||
{
|
||||
Name: "",
|
||||
File: "",
|
||||
Files: nil,
|
||||
Values: nil,
|
||||
Regex: []string{
|
||||
`abc`,
|
||||
`(another)(?P<mask>.*)(here)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
another line here
|
||||
pwd=somethinggoeshere;`,
|
||||
},
|
||||
},
|
||||
want: map[string]string{
|
||||
"data/datacollectorname": ` 123
|
||||
another***HIDDEN***here
|
||||
pwd=***HIDDEN***;
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "data with custom redactor at a restricted path",
|
||||
Collect: &troubleshootv1beta1.Collect{
|
||||
Data: &troubleshootv1beta1.Data{
|
||||
CollectorMeta: troubleshootv1beta1.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Redactors: []*troubleshootv1beta1.Redact{
|
||||
{
|
||||
Name: "",
|
||||
File: "data/*",
|
||||
Values: nil,
|
||||
Regex: []string{
|
||||
`(another)(?P<mask>.*)(here)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
another line here
|
||||
pwd=somethinggoeshere;`,
|
||||
},
|
||||
},
|
||||
want: map[string]string{
|
||||
"data/datacollectorname": `abc 123
|
||||
another***HIDDEN***here
|
||||
pwd=***HIDDEN***;
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "data with custom redactor at other path",
|
||||
Collect: &troubleshootv1beta1.Collect{
|
||||
Data: &troubleshootv1beta1.Data{
|
||||
CollectorMeta: troubleshootv1beta1.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Redactors: []*troubleshootv1beta1.Redact{
|
||||
{
|
||||
Name: "",
|
||||
File: "notdata/*",
|
||||
Values: nil,
|
||||
Regex: []string{
|
||||
`(another)(?P<mask>.*)(here)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
another line here
|
||||
pwd=somethinggoeshere;`,
|
||||
},
|
||||
},
|
||||
want: map[string]string{
|
||||
"data/datacollectorname": `abc 123
|
||||
another line here
|
||||
pwd=***HIDDEN***;
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "data with custom redactor at second path",
|
||||
Collect: &troubleshootv1beta1.Collect{
|
||||
Data: &troubleshootv1beta1.Data{
|
||||
CollectorMeta: troubleshootv1beta1.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Redactors: []*troubleshootv1beta1.Redact{
|
||||
{
|
||||
Name: "",
|
||||
Files: []string{
|
||||
"notData/*",
|
||||
"data/*",
|
||||
},
|
||||
Values: nil,
|
||||
Regex: []string{
|
||||
`(another)(?P<mask>.*)(here)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
another line here
|
||||
pwd=somethinggoeshere;`,
|
||||
},
|
||||
},
|
||||
want: map[string]string{
|
||||
"data/datacollectorname": `abc 123
|
||||
another***HIDDEN***here
|
||||
pwd=***HIDDEN***;
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "data with literal string replacer",
|
||||
Collect: &troubleshootv1beta1.Collect{
|
||||
Data: &troubleshootv1beta1.Data{
|
||||
CollectorMeta: troubleshootv1beta1.CollectorMeta{
|
||||
CollectorName: "data/collectorname",
|
||||
Redactors: []*troubleshootv1beta1.Redact{
|
||||
{
|
||||
Name: "",
|
||||
Files: []string{
|
||||
"data/*/*",
|
||||
},
|
||||
Values: []string{
|
||||
`abc`,
|
||||
`123`,
|
||||
`another`,
|
||||
},
|
||||
},
|
||||
},
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
another line here
|
||||
pwd=somethinggoeshere;`,
|
||||
},
|
||||
},
|
||||
want: map[string]string{
|
||||
"data/data/collectorname": `***HIDDEN*** ***HIDDEN***
|
||||
***HIDDEN*** line here
|
||||
pwd=***HIDDEN***;
|
||||
`,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
scopetest := scopeagent.StartTest(t)
|
||||
defer scopetest.End()
|
||||
|
||||
req := require.New(t)
|
||||
c := &Collector{
|
||||
Collect: tt.Collect,
|
||||
Redact: true,
|
||||
}
|
||||
got, err := c.RunCollectorSync(nil)
|
||||
req.NoError(err)
|
||||
|
||||
// convert to string to make differences easier to see
|
||||
toString := map[string]string{}
|
||||
for k, v := range got {
|
||||
toString[k] = string(v)
|
||||
}
|
||||
req.EqualValues(tt.want, toString)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollector_RunCollectorSync(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
Collect *troubleshootv1beta1.Collect
|
||||
want map[string]string
|
||||
}{
|
||||
{
|
||||
name: "data with custom redactor - but redaction disabled",
|
||||
Collect: &troubleshootv1beta1.Collect{
|
||||
Data: &troubleshootv1beta1.Data{
|
||||
CollectorMeta: troubleshootv1beta1.CollectorMeta{
|
||||
CollectorName: "datacollectorname",
|
||||
Redactors: []*troubleshootv1beta1.Redact{
|
||||
{
|
||||
Name: "",
|
||||
File: "",
|
||||
Files: nil,
|
||||
Values: nil,
|
||||
Regex: []string{
|
||||
`abc`,
|
||||
`(another)(?P<mask>.*)(here)`,
|
||||
},
|
||||
},
|
||||
},
|
||||
Exclude: multitype.BoolOrString{},
|
||||
},
|
||||
Name: "data",
|
||||
Data: `abc 123
|
||||
another line here
|
||||
pwd=somethinggoeshere;`,
|
||||
},
|
||||
},
|
||||
want: map[string]string{
|
||||
"data/datacollectorname": `abc 123
|
||||
another line here
|
||||
pwd=somethinggoeshere;`,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
scopetest := scopeagent.StartTest(t)
|
||||
defer scopetest.End()
|
||||
|
||||
req := require.New(t)
|
||||
c := &Collector{
|
||||
Collect: tt.Collect,
|
||||
Redact: false,
|
||||
}
|
||||
got, err := c.RunCollectorSync(nil)
|
||||
req.NoError(err)
|
||||
|
||||
// convert to string to make differences easier to see
|
||||
toString := map[string]string{}
|
||||
for k, v := range got {
|
||||
toString[k] = string(v)
|
||||
}
|
||||
req.EqualValues(tt.want, toString)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -12,15 +12,13 @@ import (
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
type CopyOutput map[string][]byte
|
||||
|
||||
func Copy(ctx *Context, copyCollector *troubleshootv1beta1.Copy) (map[string][]byte, error) {
|
||||
client, err := kubernetes.NewForConfig(ctx.ClientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
copyOutput := CopyOutput{}
|
||||
copyOutput := map[string][]byte{}
|
||||
|
||||
pods, podsErrors := listPodsInSelectors(client, copyCollector.Namespace, copyCollector.Selector)
|
||||
if len(podsErrors) > 0 {
|
||||
@@ -49,13 +47,6 @@ func Copy(ctx *Context, copyCollector *troubleshootv1beta1.Copy) (map[string][]b
|
||||
copyOutput[filepath.Join(bundlePath, k)] = v
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Redact {
|
||||
copyOutput, err = copyOutput.Redact()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return copyOutput, nil
|
||||
@@ -120,15 +111,6 @@ func copyFiles(ctx *Context, client *kubernetes.Clientset, pod corev1.Pod, copyC
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c CopyOutput) Redact() (CopyOutput, error) {
|
||||
results, err := redactMap(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func getCopyErrosFileName(copyCollector *troubleshootv1beta1.Copy) string {
|
||||
if len(copyCollector.Name) > 0 {
|
||||
return fmt.Sprintf("%s-errors.json", copyCollector.Name)
|
||||
|
||||
@@ -6,11 +6,9 @@ import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
)
|
||||
|
||||
type DataOutput map[string][]byte
|
||||
|
||||
func Data(ctx *Context, dataCollector *troubleshootv1beta1.Data) (map[string][]byte, error) {
|
||||
bundlePath := filepath.Join(dataCollector.Name, dataCollector.CollectorName)
|
||||
dataOutput := DataOutput{
|
||||
dataOutput := map[string][]byte{
|
||||
bundlePath: []byte(dataCollector.Data),
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ import (
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
type ExecOutput map[string][]byte
|
||||
|
||||
func Exec(ctx *Context, execCollector *troubleshootv1beta1.Exec) (map[string][]byte, error) {
|
||||
if execCollector.Timeout == "" {
|
||||
return execWithoutTimeout(ctx, execCollector)
|
||||
@@ -54,7 +52,7 @@ func execWithoutTimeout(ctx *Context, execCollector *troubleshootv1beta1.Exec) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
execOutput := ExecOutput{}
|
||||
execOutput := map[string][]byte{}
|
||||
|
||||
pods, podsErrors := listPodsInSelectors(client, execCollector.Namespace, execCollector.Selector)
|
||||
if len(podsErrors) > 0 {
|
||||
@@ -86,13 +84,6 @@ func execWithoutTimeout(ctx *Context, execCollector *troubleshootv1beta1.Exec) (
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Redact {
|
||||
execOutput, err = execOutput.Redact()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return execOutput, nil
|
||||
@@ -142,15 +133,6 @@ func getExecOutputs(ctx *Context, client *kubernetes.Clientset, pod corev1.Pod,
|
||||
return stdout.Bytes(), stderr.Bytes(), nil
|
||||
}
|
||||
|
||||
func (r ExecOutput) Redact() (ExecOutput, error) {
|
||||
results, err := redactMap(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func getExecErrosFileName(execCollector *troubleshootv1beta1.Exec) string {
|
||||
if len(execCollector.Name) > 0 {
|
||||
return fmt.Sprintf("%s-errors.json", execCollector.Name)
|
||||
|
||||
@@ -10,11 +10,8 @@ import (
|
||||
"strings"
|
||||
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/redact"
|
||||
)
|
||||
|
||||
type HTTPOutput map[string][]byte
|
||||
|
||||
type httpResponse struct {
|
||||
Status int `json:"status"`
|
||||
Body string `json:"body"`
|
||||
@@ -48,7 +45,7 @@ func HTTP(ctx *Context, httpCollector *troubleshootv1beta1.HTTP) (map[string][]b
|
||||
if httpCollector.CollectorName != "" {
|
||||
fileName = httpCollector.CollectorName + ".json"
|
||||
}
|
||||
httpOutput := HTTPOutput{
|
||||
httpOutput := map[string][]byte{
|
||||
filepath.Join(httpCollector.Name, fileName): output,
|
||||
}
|
||||
|
||||
@@ -135,12 +132,5 @@ func responseToOutput(response *http.Response, err error, doRedact bool) ([]byte
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if doRedact {
|
||||
b, err = redact.Redact(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
@@ -15,15 +15,13 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
type LogsOutput map[string][]byte
|
||||
|
||||
func Logs(ctx *Context, logsCollector *troubleshootv1beta1.Logs) (map[string][]byte, error) {
|
||||
client, err := kubernetes.NewForConfig(ctx.ClientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logsOutput := LogsOutput{}
|
||||
logsOutput := map[string][]byte{}
|
||||
|
||||
pods, podsErrors := listPodsInSelectors(client, logsCollector.Namespace, logsCollector.Selector)
|
||||
if len(podsErrors) > 0 {
|
||||
@@ -83,13 +81,6 @@ func Logs(ctx *Context, logsCollector *troubleshootv1beta1.Logs) (map[string][]b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Redact {
|
||||
logsOutput, err = logsOutput.Redact()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return logsOutput, nil
|
||||
@@ -176,15 +167,6 @@ func getPodLogs(client *kubernetes.Clientset, pod corev1.Pod, name, container st
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (l LogsOutput) Redact() (LogsOutput, error) {
|
||||
podLogs, err := redactMap(l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return podLogs, nil
|
||||
}
|
||||
|
||||
func getLogsErrorsFileName(logsCollector *troubleshootv1beta1.Logs) string {
|
||||
if len(logsCollector.Name) > 0 {
|
||||
return fmt.Sprintf("%s/errors.json", logsCollector.Name)
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
)
|
||||
|
||||
type MysqlOutput map[string][]byte
|
||||
|
||||
func Mysql(ctx *Context, databaseCollector *troubleshootv1beta1.Database) (map[string][]byte, error) {
|
||||
databaseConnection := DatabaseConnection{}
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
)
|
||||
|
||||
type PostgresOutput map[string][]byte
|
||||
|
||||
func Postgres(ctx *Context, databaseCollector *troubleshootv1beta1.Database) (map[string][]byte, error) {
|
||||
databaseConnection := DatabaseConnection{}
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package collect
|
||||
|
||||
import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
"github.com/replicatedhq/troubleshoot/pkg/redact"
|
||||
)
|
||||
|
||||
func redactMap(input map[string][]byte) (map[string][]byte, error) {
|
||||
func redactMap(input map[string][]byte, additionalRedactors []*troubleshootv1beta1.Redact) (map[string][]byte, error) {
|
||||
result := make(map[string][]byte)
|
||||
for k, v := range input {
|
||||
if v != nil {
|
||||
redacted, err := redact.Redact(v)
|
||||
redacted, err := redact.Redact(v, k, additionalRedactors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import (
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
)
|
||||
|
||||
type RedisOutput map[string][]byte
|
||||
|
||||
func Redis(ctx *Context, databaseCollector *troubleshootv1beta1.Database) (map[string][]byte, error) {
|
||||
databaseConnection := DatabaseConnection{}
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
type RunOutput map[string][]byte
|
||||
|
||||
func Run(ctx *Context, runCollector *troubleshootv1beta1.Run) (map[string][]byte, error) {
|
||||
client, err := kubernetes.NewForConfig(ctx.ClientConfig)
|
||||
if err != nil {
|
||||
@@ -79,7 +77,7 @@ func runWithoutTimeout(ctx *Context, pod *corev1.Pod, runCollector *troubleshoot
|
||||
time.Sleep(time.Second * 1)
|
||||
}
|
||||
|
||||
runOutput := RunOutput{}
|
||||
runOutput := map[string][]byte{}
|
||||
|
||||
limits := troubleshootv1beta1.LogLimits{
|
||||
MaxLines: 10000,
|
||||
@@ -93,13 +91,6 @@ func runWithoutTimeout(ctx *Context, pod *corev1.Pod, runCollector *troubleshoot
|
||||
runOutput[k] = v
|
||||
}
|
||||
|
||||
if ctx.Redact {
|
||||
runOutput, err = runOutput.Redact()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to redact pod logs")
|
||||
}
|
||||
}
|
||||
|
||||
return runOutput, nil
|
||||
}
|
||||
|
||||
@@ -150,12 +141,3 @@ func runPod(client *kubernetes.Clientset, runCollector *troubleshootv1beta1.Run,
|
||||
|
||||
return created, nil
|
||||
}
|
||||
|
||||
func (r RunOutput) Redact() (RunOutput, error) {
|
||||
podLogs, err := redactMap(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return podLogs, nil
|
||||
}
|
||||
|
||||
@@ -20,11 +20,6 @@ type FoundSecret struct {
|
||||
Value string `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type SecretOutput struct {
|
||||
FoundSecret map[string][]byte `json:"secrets/,omitempty"`
|
||||
Errors map[string][]byte `json:"secrets-errors/,omitempty"`
|
||||
}
|
||||
|
||||
func Secret(ctx *Context, secretCollector *troubleshootv1beta1.Secret) (map[string][]byte, error) {
|
||||
client, err := kubernetes.NewForConfig(ctx.ClientConfig)
|
||||
if err != nil {
|
||||
@@ -45,13 +40,6 @@ func Secret(ctx *Context, secretCollector *troubleshootv1beta1.Secret) (map[stri
|
||||
secretOutput[path.Join("secrets", filePath)] = encoded
|
||||
}
|
||||
|
||||
if ctx.Redact {
|
||||
secretOutput, err = redactMap(secretOutput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return secretOutput, nil
|
||||
}
|
||||
|
||||
@@ -104,15 +92,3 @@ func secret(client *kubernetes.Clientset, secretCollector *troubleshootv1beta1.S
|
||||
|
||||
return path, b, nil
|
||||
}
|
||||
|
||||
func (s *SecretOutput) Redact() (*SecretOutput, error) {
|
||||
foundSecret, err := redactMap(s.FoundSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SecretOutput{
|
||||
FoundSecret: foundSecret,
|
||||
Errors: s.Errors,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func Collect(opts CollectOpts, p *troubleshootv1beta1.Preflight) (CollectResult,
|
||||
}
|
||||
}
|
||||
|
||||
result, err := collector.RunCollectorSync()
|
||||
result, err := collector.RunCollectorSync(nil)
|
||||
if err != nil {
|
||||
opts.ProgressChan <- errors.Errorf("failed to run collector %s: %v\n", collector.GetDisplayName(), err)
|
||||
continue
|
||||
|
||||
47
pkg/redact/literal.go
Normal file
47
pkg/redact/literal.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package redact
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type literalRedactor struct {
|
||||
matchString string
|
||||
}
|
||||
|
||||
func literalString(matchString string) Redactor {
|
||||
return literalRedactor{matchString: matchString}
|
||||
}
|
||||
|
||||
func (r literalRedactor) Redact(input io.Reader) io.Reader {
|
||||
reader, writer := io.Pipe()
|
||||
|
||||
go func() {
|
||||
var err error
|
||||
defer func() {
|
||||
if err == io.EOF {
|
||||
writer.Close()
|
||||
} else {
|
||||
writer.CloseWithError(err)
|
||||
}
|
||||
}()
|
||||
|
||||
reader := bufio.NewReader(input)
|
||||
for {
|
||||
var line string
|
||||
line, err = readLine(reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// io.WriteString would be nicer, but scanner strips new lines
|
||||
fmt.Fprintf(writer, "%s\n", strings.ReplaceAll(line, r.matchString, MASK_TEXT))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return reader
|
||||
}
|
||||
@@ -6,7 +6,11 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -17,12 +21,18 @@ type Redactor interface {
|
||||
Redact(input io.Reader) io.Reader
|
||||
}
|
||||
|
||||
func Redact(input []byte) ([]byte, error) {
|
||||
redactors, err := GetRedactors()
|
||||
func Redact(input []byte, path string, additionalRedactors []*troubleshootv1beta1.Redact) ([]byte, error) {
|
||||
redactors, err := getRedactors()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
builtRedactors, err := buildAdditionalRedactors(path, additionalRedactors)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "build custom redactors")
|
||||
}
|
||||
redactors = append(redactors, builtRedactors...)
|
||||
|
||||
nextReader := io.Reader(bytes.NewReader(input))
|
||||
for _, r := range redactors {
|
||||
nextReader = r.Redact(nextReader)
|
||||
@@ -36,7 +46,66 @@ func Redact(input []byte) ([]byte, error) {
|
||||
return redacted, nil
|
||||
}
|
||||
|
||||
func GetRedactors() ([]Redactor, error) {
|
||||
func buildAdditionalRedactors(path string, redacts []*troubleshootv1beta1.Redact) ([]Redactor, error) {
|
||||
additionalRedactors := []Redactor{}
|
||||
for _, redact := range redacts {
|
||||
if redact == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// check if redact matches path
|
||||
matches, err := redactMatchesPath(path, redact)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !matches {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, re := range redact.Regex {
|
||||
r, err := NewSingleLineRedactor(re, MASK_TEXT)
|
||||
if err != nil {
|
||||
return nil, err // maybe skip broken ones?
|
||||
}
|
||||
additionalRedactors = append(additionalRedactors, r)
|
||||
}
|
||||
|
||||
for _, literal := range redact.Values {
|
||||
additionalRedactors = append(additionalRedactors, literalString(literal))
|
||||
}
|
||||
}
|
||||
return additionalRedactors, nil
|
||||
}
|
||||
|
||||
func redactMatchesPath(path string, redact *troubleshootv1beta1.Redact) (bool, error) {
|
||||
if redact.File == "" && len(redact.Files) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if redact.File != "" {
|
||||
matches, err := filepath.Match(redact.File, path)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "invalid file match string %q", redact.File)
|
||||
}
|
||||
if matches {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
for i, fileGlobString := range redact.Files {
|
||||
matches, err := filepath.Match(fileGlobString, path)
|
||||
if err != nil {
|
||||
return false, errors.Wrapf(err, "invalid file match string %d %q", i, fileGlobString)
|
||||
}
|
||||
if matches {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func getRedactors() ([]Redactor, error) {
|
||||
// TODO: Make this configurable
|
||||
|
||||
// (?i) makes it case insensitive
|
||||
|
||||
@@ -6,7 +6,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
troubleshootv1beta1 "github.com/replicatedhq/troubleshoot/pkg/apis/troubleshoot/v1beta1"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.undefinedlabs.com/scopeagent"
|
||||
)
|
||||
|
||||
@@ -1622,8 +1623,9 @@ func Test_Redactors(t *testing.T) {
|
||||
t.Run("test default redactors", func(t *testing.T) {
|
||||
scopetest := scopeagent.StartTest(t)
|
||||
defer scopetest.End()
|
||||
redactors, err := GetRedactors()
|
||||
assert.NoError(t, err)
|
||||
req := require.New(t)
|
||||
redactors, err := getRedactors()
|
||||
req.NoError(err)
|
||||
|
||||
nextReader := io.Reader(strings.NewReader(original))
|
||||
for _, r := range redactors {
|
||||
@@ -1631,8 +1633,101 @@ func Test_Redactors(t *testing.T) {
|
||||
}
|
||||
|
||||
redacted, err := ioutil.ReadAll(nextReader)
|
||||
assert.NoError(t, err)
|
||||
req.NoError(err)
|
||||
|
||||
assert.JSONEq(t, expected, string(redacted))
|
||||
req.JSONEq(expected, string(redacted))
|
||||
})
|
||||
}
|
||||
|
||||
func Test_redactMatchesPath(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
redact *troubleshootv1beta1.Redact
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "literal path",
|
||||
args: args{
|
||||
path: "/my/test/path",
|
||||
redact: &troubleshootv1beta1.Redact{
|
||||
File: "/my/test/path",
|
||||
Files: nil,
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "no path",
|
||||
args: args{
|
||||
path: "/my/test/path",
|
||||
redact: &troubleshootv1beta1.Redact{
|
||||
File: "",
|
||||
Files: nil,
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "wrong literal path",
|
||||
args: args{
|
||||
path: "/my/test/path",
|
||||
redact: &troubleshootv1beta1.Redact{
|
||||
File: "/my/test/path/two",
|
||||
Files: nil,
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "path with glob",
|
||||
args: args{
|
||||
path: "/my/test/path/two",
|
||||
redact: &troubleshootv1beta1.Redact{
|
||||
File: "/my/test/path/*",
|
||||
Files: nil,
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "path with glob in middle",
|
||||
args: args{
|
||||
path: "/my/test/path/two",
|
||||
redact: &troubleshootv1beta1.Redact{
|
||||
File: "/my/test/*/*",
|
||||
Files: nil,
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "multiple paths",
|
||||
args: args{
|
||||
path: "/my/test/path/two",
|
||||
redact: &troubleshootv1beta1.Redact{
|
||||
File: "",
|
||||
Files: []string{
|
||||
"/not/the/path",
|
||||
"/my/test/*/*",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
scopetest := scopeagent.StartTest(t)
|
||||
defer scopetest.End()
|
||||
req := require.New(t)
|
||||
|
||||
got, err := redactMatchesPath(tt.args.path, tt.args.redact)
|
||||
req.NoError(err)
|
||||
req.Equal(tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
53
pkg/redact/single_line_test.go
Normal file
53
pkg/redact/single_line_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package redact
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.undefinedlabs.com/scopeagent"
|
||||
)
|
||||
|
||||
func TestNewSingleLineRedactor(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
re string
|
||||
inputString string
|
||||
wantString string
|
||||
}{
|
||||
{
|
||||
name: "copied from default redactors",
|
||||
re: `(?i)(Pwd *= *)(?P<mask>[^\;]+)(;)`,
|
||||
inputString: `pwd = abcdef;`,
|
||||
wantString: "pwd = ***HIDDEN***;\n",
|
||||
},
|
||||
{
|
||||
name: "no leading matching group", // this is not the ideal behavior - why are we dropping ungrouped match components?
|
||||
re: `(?i)Pwd *= *(?P<mask>[^\;]+)(;)`,
|
||||
inputString: `pwd = abcdef;`,
|
||||
wantString: "***HIDDEN***;\n",
|
||||
},
|
||||
{
|
||||
name: "multiple matching literals",
|
||||
re: `(?i)(Pwd *= *)(?P<mask>[^\;]+)(;)`,
|
||||
inputString: `pwd = abcdef;abcdef`,
|
||||
wantString: "pwd = ***HIDDEN***;abcdef\n",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
scopetest := scopeagent.StartTest(t)
|
||||
defer scopetest.End()
|
||||
|
||||
req := require.New(t)
|
||||
reRunner, err := NewSingleLineRedactor(tt.re, MASK_TEXT)
|
||||
req.NoError(err)
|
||||
|
||||
outReader := reRunner.Redact(bytes.NewReader([]byte(tt.inputString)))
|
||||
gotBytes, err := ioutil.ReadAll(outReader)
|
||||
req.NoError(err)
|
||||
req.Equal(tt.wantString, string(gotBytes))
|
||||
})
|
||||
}
|
||||
}
|
||||
13
sample-redactors.yaml
Normal file
13
sample-redactors.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
apiVersion: troubleshoot.replicated.com/v1beta1
|
||||
kind: Redactor
|
||||
metadata:
|
||||
name: my-application-name
|
||||
spec:
|
||||
redacts:
|
||||
- name: replace password # names are not used internally, but are useful for recordkeeping
|
||||
file: data/my-password-dump # this targets a single file
|
||||
values:
|
||||
- abc123 # this is a very good password, and I don't want it to be exposed
|
||||
- name: all files # as no file is specified, this redactor will run against all files
|
||||
regex:
|
||||
- (another)(?P<mask>.*)(here) # this will replace anything between the strings `another` and `here` with `***HIDDEN***`
|
||||
@@ -12,3 +12,12 @@ spec:
|
||||
name: healthz
|
||||
get:
|
||||
url: http://api:3000/healthz
|
||||
- data:
|
||||
collectorName: my-password-dump
|
||||
name: data
|
||||
data: |
|
||||
my super secret password is abc123
|
||||
another redaction will go here
|
||||
redactors:
|
||||
- values:
|
||||
- secret # this will replace the string 'secret' with '***HIDDEN***' in the files produced by this collector
|
||||
|
||||
Reference in New Issue
Block a user