From d2e91b4ffa098348148caa2d4cad2445381ec768 Mon Sep 17 00:00:00 2001 From: Igor Gov Date: Wed, 23 Feb 2022 09:20:19 +0200 Subject: [PATCH 01/10] Fix: tapper tries to load agent config map (#844) --- agent/main.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/agent/main.go b/agent/main.go index 4b91de770..7974669f8 100644 --- a/agent/main.go +++ b/agent/main.go @@ -58,9 +58,7 @@ func main() { logLevel := determineLogLevel() logger.InitLoggerStd(logLevel) flag.Parse() - if err := config.LoadConfig(); err != nil { - logger.Log.Fatalf("Error loading config file %v", err) - } + app.LoadExtensions() if !*tapperMode && !*apiServerMode && !*standaloneMode && !*harsReaderMode { @@ -139,6 +137,9 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin } func runInApiServerMode(namespace string) *gin.Engine { + if err := config.LoadConfig(); err != nil { + logger.Log.Fatalf("Error loading config file %v", err) + } app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort) startTime = time.Now().UnixNano() / int64(time.Millisecond) api.StartResolving(namespace) From 97cce32e3f47a89a163db81fdc64ec6f68651acd Mon Sep 17 00:00:00 2001 From: Igor Gov Date: Wed, 23 Feb 2022 09:35:05 +0200 Subject: [PATCH 02/10] Fix: service map component aware of agent config (#845) * Fix: Service map component aware of mizu config --- agent/main.go | 2 +- .../controllers/service_map_controller_test.go | 5 +---- agent/pkg/servicemap/servicemap.go | 16 ++++++---------- agent/pkg/servicemap/servicemap_test.go | 5 +---- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/agent/main.go b/agent/main.go index 7974669f8..1db69f27d 100644 --- a/agent/main.go +++ b/agent/main.go @@ -216,7 +216,7 @@ func enableExpFeatureIfNeeded() { oas.GetOasGeneratorInstance().Start() } if config.Config.ServiceMap { - servicemap.GetInstance().SetConfig(config.Config) + servicemap.GetInstance().Enable() } elastic.GetInstance().Configure(config.Config.Elastic) } diff --git a/agent/pkg/controllers/service_map_controller_test.go b/agent/pkg/controllers/service_map_controller_test.go index c6b372406..9602efd7e 100644 --- a/agent/pkg/controllers/service_map_controller_test.go +++ b/agent/pkg/controllers/service_map_controller_test.go @@ -11,7 +11,6 @@ import ( "github.com/gin-gonic/gin" "github.com/stretchr/testify/suite" - "github.com/up9inc/mizu/shared" tapApi "github.com/up9inc/mizu/tap/api" ) @@ -59,9 +58,7 @@ type ServiceMapControllerSuite struct { func (s *ServiceMapControllerSuite) SetupTest() { s.c = NewServiceMapController() - s.c.service.SetConfig(&shared.MizuAgentConfig{ - ServiceMap: true, - }) + s.c.service.Enable() s.c.service.NewTCPEntry(TCPEntryA, TCPEntryB, ProtocolHttp) s.w = httptest.NewRecorder() diff --git a/agent/pkg/servicemap/servicemap.go b/agent/pkg/servicemap/servicemap.go index 3537e9855..3f7359feb 100644 --- a/agent/pkg/servicemap/servicemap.go +++ b/agent/pkg/servicemap/servicemap.go @@ -3,7 +3,6 @@ package servicemap import ( "sync" - "github.com/up9inc/mizu/shared" "github.com/up9inc/mizu/shared/logger" tapApi "github.com/up9inc/mizu/tap/api" ) @@ -26,13 +25,13 @@ func GetInstance() ServiceMap { } type serviceMap struct { - config *shared.MizuAgentConfig + enabled bool graph *graph entriesProcessed int } type ServiceMap interface { - SetConfig(config *shared.MizuAgentConfig) + Enable() IsEnabled() bool NewTCPEntry(source *tapApi.TCP, destination *tapApi.TCP, protocol *tapApi.Protocol) GetStatus() ServiceMapStatus @@ -46,7 +45,7 @@ type ServiceMap interface { func newServiceMap() *serviceMap { return &serviceMap{ - config: nil, + enabled: false, entriesProcessed: 0, graph: newDirectedGraph(), } @@ -156,15 +155,12 @@ func (s *serviceMap) addEdge(u, v *entryData, p *tapApi.Protocol) { s.entriesProcessed++ } -func (s *serviceMap) SetConfig(config *shared.MizuAgentConfig) { - s.config = config +func (s *serviceMap) Enable() { + s.enabled = true } func (s *serviceMap) IsEnabled() bool { - if s.config != nil && s.config.ServiceMap { - return true - } - return false + return s.enabled } func (s *serviceMap) NewTCPEntry(src *tapApi.TCP, dst *tapApi.TCP, p *tapApi.Protocol) { diff --git a/agent/pkg/servicemap/servicemap_test.go b/agent/pkg/servicemap/servicemap_test.go index 9a0de04b6..6dc2126e4 100644 --- a/agent/pkg/servicemap/servicemap_test.go +++ b/agent/pkg/servicemap/servicemap_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/stretchr/testify/suite" - "github.com/up9inc/mizu/shared" tapApi "github.com/up9inc/mizu/tap/api" ) @@ -96,9 +95,7 @@ func (s *ServiceMapDisabledSuite) SetupTest() { func (s *ServiceMapEnabledSuite) SetupTest() { s.instance = GetInstance() - s.instance.SetConfig(&shared.MizuAgentConfig{ - ServiceMap: true, - }) + s.instance.Enable() } func (s *ServiceMapDisabledSuite) TestServiceMapInstance() { From 371e513249ef834a0b2f38f14a2c081fca387016 Mon Sep 17 00:00:00 2001 From: Igor Gov Date: Wed, 23 Feb 2022 10:06:19 +0200 Subject: [PATCH 03/10] Remove config dependency from basenine init (#846) * Remove config dependency from basenine init --- agent/main.go | 2 +- agent/pkg/app/main.go | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/agent/main.go b/agent/main.go index 1db69f27d..a4101091d 100644 --- a/agent/main.go +++ b/agent/main.go @@ -140,7 +140,7 @@ func runInApiServerMode(namespace string) *gin.Engine { if err := config.LoadConfig(); err != nil { logger.Log.Fatalf("Error loading config file %v", err) } - app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort) + app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort, config.Config.MaxDBSizeBytes, config.Config.LogLevel) startTime = time.Now().UnixNano() / int64(time.Millisecond) api.StartResolving(namespace) diff --git a/agent/pkg/app/main.go b/agent/pkg/app/main.go index 1e7a9d0dd..003487883 100644 --- a/agent/pkg/app/main.go +++ b/agent/pkg/app/main.go @@ -9,7 +9,6 @@ import ( "github.com/op/go-logging" basenine "github.com/up9inc/basenine/client/go" "github.com/up9inc/mizu/agent/pkg/api" - "github.com/up9inc/mizu/agent/pkg/config" "github.com/up9inc/mizu/agent/pkg/controllers" "github.com/up9inc/mizu/shared/logger" tapApi "github.com/up9inc/mizu/tap/api" @@ -63,20 +62,18 @@ func LoadExtensions() { controllers.InitExtensionsMap(ExtensionsMap) } -func ConfigureBasenineServer(host string, port string) { +func ConfigureBasenineServer(host string, port string, dbSize int64, logLevel logging.Level) { if !wait.New( wait.WithProto("tcp"), wait.WithWait(200*time.Millisecond), wait.WithBreak(50*time.Millisecond), wait.WithDeadline(5*time.Second), - wait.WithDebug(config.Config.LogLevel == logging.DEBUG), + wait.WithDebug(logLevel == logging.DEBUG), ).Do([]string{fmt.Sprintf("%s:%s", host, port)}) { logger.Log.Panicf("Basenine is not available!") } - // Limit the database size to default 200MB - err := basenine.Limit(host, port, config.Config.MaxDBSizeBytes) - if err != nil { + if err := basenine.Limit(host, port, dbSize); err != nil { logger.Log.Panicf("Error while limiting database size: %v", err) } @@ -84,8 +81,7 @@ func ConfigureBasenineServer(host string, port string) { for _, extension := range Extensions { macros := extension.Dissector.Macros() for macro, expanded := range macros { - err = basenine.Macro(host, port, macro, expanded) - if err != nil { + if err := basenine.Macro(host, port, macro, expanded); err != nil { logger.Log.Panicf("Error while adding a macro: %v", err) } } From 852a5ff045c5b04fc5c37c9fa53550ed833064a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Mert=20Y=C4=B1ld=C4=B1ran?= Date: Wed, 23 Feb 2022 13:29:47 +0300 Subject: [PATCH 04/10] Bring back the `query` argument of `getEntry` call which is accidentally removed with #631 (#842) --- ui/src/components/EntryDetailed.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui/src/components/EntryDetailed.tsx b/ui/src/components/EntryDetailed.tsx index ac9106a8c..b31a15195 100644 --- a/ui/src/components/EntryDetailed.tsx +++ b/ui/src/components/EntryDetailed.tsx @@ -8,6 +8,7 @@ import {toast} from "react-toastify"; import {useRecoilValue} from "recoil"; import focusedEntryIdAtom from "../recoil/focusedEntryId"; import Api from "../helpers/api"; +import queryAtom from "../recoil/query"; const useStyles = makeStyles(() => ({ entryTitle: { @@ -82,6 +83,7 @@ const api = Api.getInstance(); export const EntryDetailed = () => { const focusedEntryId = useRecoilValue(focusedEntryIdAtom); + const query = useRecoilValue(queryAtom); const [entryData, setEntryData] = useState(null); useEffect(() => { @@ -89,7 +91,7 @@ export const EntryDetailed = () => { setEntryData(null); (async () => { try { - const entryData = await api.getEntry(focusedEntryId); + const entryData = await api.getEntry(focusedEntryId, query); setEntryData(entryData); } catch (error) { if (error.response?.data?.type) { From cf127c781c2ad8737f7a7bccfc73cc6e62f632b4 Mon Sep 17 00:00:00 2001 From: RamiBerm <54766858+RamiBerm@users.noreply.github.com> Date: Wed, 23 Feb 2022 14:40:47 +0200 Subject: [PATCH 05/10] Dont mount config map on tappers (#849) --- shared/kubernetes/provider.go | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/shared/kubernetes/provider.go b/shared/kubernetes/provider.go index 027091bb9..18301cb05 100644 --- a/shared/kubernetes/provider.go +++ b/shared/kubernetes/provider.go @@ -829,7 +829,7 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac if tls { mizuCmd = append(mizuCmd, "--tls") } - + if serviceMesh || tls { mizuCmd = append(mizuCmd, "--procfs", procfsMountPath) } @@ -939,24 +939,6 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac sysfsVolumeMount := applyconfcore.VolumeMount().WithName(sysfsVolumeName).WithMountPath(sysfsMountPath).WithReadOnly(true) agentContainer.WithVolumeMounts(sysfsVolumeMount) - volumeName := ConfigMapName - configMapVolume := applyconfcore.VolumeApplyConfiguration{ - Name: &volumeName, - VolumeSourceApplyConfiguration: applyconfcore.VolumeSourceApplyConfiguration{ - ConfigMap: &applyconfcore.ConfigMapVolumeSourceApplyConfiguration{ - LocalObjectReferenceApplyConfiguration: applyconfcore.LocalObjectReferenceApplyConfiguration{ - Name: &volumeName, - }, - }, - }, - } - mountPath := shared.ConfigDirPath - configMapVolumeMount := applyconfcore.VolumeMountApplyConfiguration{ - Name: &volumeName, - MountPath: &mountPath, - } - agentContainer.WithVolumeMounts(&configMapVolumeMount) - podSpec := applyconfcore.PodSpec() podSpec.WithHostNetwork(true) podSpec.WithDNSPolicy(core.DNSClusterFirstWithHostNet) @@ -967,7 +949,7 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac podSpec.WithContainers(agentContainer) podSpec.WithAffinity(affinity) podSpec.WithTolerations(noExecuteToleration, noScheduleToleration) - podSpec.WithVolumes(&configMapVolume, procfsVolume, sysfsVolume) + podSpec.WithVolumes(procfsVolume, sysfsVolume) podTemplate := applyconfcore.PodTemplateSpec() podTemplate.WithLabels(map[string]string{ @@ -981,7 +963,7 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac labelSelector.WithMatchLabels(map[string]string{"app": tapperPodName}) applyOptions := metav1.ApplyOptions{ - Force: true, + Force: true, FieldManager: fieldManagerName, } From cdbacff99647931e0e815d50f1b78d635aee3d60 Mon Sep 17 00:00:00 2001 From: Adam Kol <93466081+AdamKol-up9@users.noreply.github.com> Date: Wed, 23 Feb 2022 17:36:31 +0200 Subject: [PATCH 06/10] Cypress: Service Map test (#847) --- .../cypress/integration/tests/UiTest.js | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/acceptanceTests/cypress/integration/tests/UiTest.js b/acceptanceTests/cypress/integration/tests/UiTest.js index f9825cd9d..af5ca6332 100644 --- a/acceptanceTests/cypress/integration/tests/UiTest.js +++ b/acceptanceTests/cypress/integration/tests/UiTest.js @@ -64,6 +64,8 @@ it('right side sanity test', function () { }); }); +serviceMapCheck(); + checkIllegalFilter('invalid filter'); checkFilter({ @@ -188,7 +190,7 @@ function checkFilter(filterDetails){ const entriesForDeeperCheck = 5; it(`checking the filter: ${name}`, function () { - cy.get('#total-entries').then(number => { + cy.get('#total-entries').should('not.have.text', '0').then(number => { const totalEntries = number.text(); // checks the hover on the last entry (the only one in DOM at the beginning) @@ -320,3 +322,42 @@ function checkOnlyLineNumberes(jsonItems, decodedText) { cy.get(`${Cypress.env('bodyJsonClass')} >`).should('have.length', 1).and('have.text', decodedText); cy.get(`${Cypress.env('bodyJsonClass')} > >`).should('have.length', jsonItems) } + +function serviceMapCheck() { + it('service map test', function () { + cy.intercept(`${Cypress.env('testUrl')}/servicemap/get`).as('serviceMapRequest'); + cy.get('#total-entries').should('not.have.text', '0').then(() => { + cy.get('#total-entries').invoke('text').then(entriesNum => { + cy.get('[alt="service-map"]').click(); + cy.wait('@serviceMapRequest').then(({response}) => { + const body = response.body; + const nodeParams = { + destination: 'httpbin.mizu-tests', + source: '127.0.0.1' + }; + serviceMapAPICheck(body, parseInt(entriesNum), nodeParams); + cy.reload(); + }); + }); + }); + }); +} + +function serviceMapAPICheck(body, entriesNum, nodeParams) { + const {nodes, edges} = body; + + expect(nodes.length).to.equal(Object.keys(nodeParams).length, `Expected nodes count`); + + expect(edges.some(edge => edge.source.name === nodeParams.source)).to.be.true; + expect(edges.some(edge => edge.destination.name === nodeParams.destination)).to.be.true; + + let count = 0; + edges.forEach(edge => { + count += edge.count; + if (edge.destination.name === nodeParams.destination) { + expect(edge.source.name).to.equal(nodeParams.source); + } + }); + + expect(count).to.equal(entriesNum); +} From 30a85a4b9284dcf80040584e5365238964af9d0b Mon Sep 17 00:00:00 2001 From: RoyUP9 <87927115+RoyUP9@users.noreply.github.com> Date: Thu, 24 Feb 2022 11:48:42 +0200 Subject: [PATCH 07/10] Added tap pre check (#848) --- cli/cmd/check.go | 10 +++ cli/cmd/checkRunner.go | 106 +++++++++++++++++++++--- cli/config/configStruct.go | 1 + cli/config/configStructs/checkConfig.go | 9 ++ shared/fileUtils.go | 20 +++++ shared/kubernetes/provider.go | 21 +++++ 6 files changed, 155 insertions(+), 12 deletions(-) create mode 100644 cli/config/configStructs/checkConfig.go create mode 100644 shared/fileUtils.go diff --git a/cli/cmd/check.go b/cli/cmd/check.go index b3c658a40..d5187ef8c 100644 --- a/cli/cmd/check.go +++ b/cli/cmd/check.go @@ -1,8 +1,11 @@ package cmd import ( + "github.com/creasty/defaults" "github.com/spf13/cobra" + "github.com/up9inc/mizu/cli/config/configStructs" "github.com/up9inc/mizu/cli/telemetry" + "github.com/up9inc/mizu/shared/logger" ) var checkCmd = &cobra.Command{ @@ -17,4 +20,11 @@ var checkCmd = &cobra.Command{ func init() { rootCmd.AddCommand(checkCmd) + + defaultCheckConfig := configStructs.CheckConfig{} + if err := defaults.Set(&defaultCheckConfig); err != nil { + logger.Log.Debug(err) + } + + checkCmd.Flags().Bool(configStructs.PreTapCheckName, defaultCheckConfig.PreTap, "Check pre-tap Mizu installation for potential problems") } diff --git a/cli/cmd/checkRunner.go b/cli/cmd/checkRunner.go index 7bbb0d8d0..24d140acd 100644 --- a/cli/cmd/checkRunner.go +++ b/cli/cmd/checkRunner.go @@ -3,6 +3,10 @@ package cmd import ( "context" "fmt" + "github.com/up9inc/mizu/shared" + rbac "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/scheme" "regexp" "github.com/up9inc/mizu/cli/apiserver" @@ -14,7 +18,7 @@ import ( ) func runMizuCheck() { - logger.Log.Infof("Mizu install checks\n===================") + logger.Log.Infof("Mizu checks\n===================") ctx, cancel := context.WithCancel(context.Background()) defer cancel() // cancel will be called when this function exits @@ -25,17 +29,23 @@ func runMizuCheck() { checkPassed = checkKubernetesVersion(kubernetesVersion) } - var isInstallCommand bool - if checkPassed { - checkPassed, isInstallCommand = checkMizuMode(ctx, kubernetesProvider) - } + if config.Config.Check.PreTap { + if checkPassed { + checkPassed = checkK8sTapPermissions(ctx, kubernetesProvider) + } + } else { + var isInstallCommand bool + if checkPassed { + checkPassed, isInstallCommand = checkMizuMode(ctx, kubernetesProvider) + } - if checkPassed { - checkPassed = checkK8sResources(ctx, kubernetesProvider, isInstallCommand) - } + if checkPassed { + checkPassed = checkK8sResources(ctx, kubernetesProvider, isInstallCommand) + } - if checkPassed { - checkPassed = checkServerConnection(kubernetesProvider) + if checkPassed { + checkPassed = checkServerConnection(kubernetesProvider) + } } if checkPassed { @@ -273,9 +283,81 @@ func checkResourceExist(resourceName string, resourceType string, exist bool, er } else if !exist { logger.Log.Errorf("%v '%v' %v doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType) return false - } else { - logger.Log.Infof("%v '%v' %v exists", fmt.Sprintf(uiUtils.Green, "√"), resourceName, resourceType) } + logger.Log.Infof("%v '%v' %v exists", fmt.Sprintf(uiUtils.Green, "√"), resourceName, resourceType) + return true +} + +func checkK8sTapPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool { + logger.Log.Infof("\nkubernetes-permissions\n--------------------") + + var filePath string + if config.Config.IsNsRestrictedMode() { + filePath = "./examples/roles/permissions-ns-tap.yaml" + } else { + filePath = "./examples/roles/permissions-all-namespaces-tap.yaml" + } + + data, err := shared.ReadFromFile(filePath) + if err != nil { + logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err) + return false + } + + obj, err := getDecodedObject(data) + if err != nil { + logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err) + return false + } + + var rules []rbac.PolicyRule + if config.Config.IsNsRestrictedMode() { + rules = obj.(*rbac.Role).Rules + } else { + rules = obj.(*rbac.ClusterRole).Rules + } + + return checkPermissions(ctx, kubernetesProvider, rules) +} + +func getDecodedObject(data []byte) (runtime.Object, error) { + decode := scheme.Codecs.UniversalDeserializer().Decode + + obj, _, err := decode(data, nil, nil) + if err != nil { + return nil, err + } + + return obj, nil +} + +func checkPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider, rules []rbac.PolicyRule) bool { + permissionsExist := true + + for _, rule := range rules { + for _, group := range rule.APIGroups { + for _, resource := range rule.Resources { + for _, verb := range rule.Verbs { + exist, err := kubernetesProvider.CanI(ctx, config.Config.MizuResourcesNamespace, resource, verb, group) + permissionsExist = checkPermissionExist(group, resource, verb, exist, err) && permissionsExist + } + } + } + } + + return permissionsExist +} + +func checkPermissionExist(group string, resource string, verb string, exist bool, err error) bool { + if err != nil { + logger.Log.Errorf("%v error checking permission for %v %v in group '%v', err: %v", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group, err) + return false + } else if !exist { + logger.Log.Errorf("%v can't %v %v in group '%v'", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group) + return false + } + + logger.Log.Infof("%v can %v %v in group '%v'", fmt.Sprintf(uiUtils.Green, "√"), verb, resource, group) return true } diff --git a/cli/config/configStruct.go b/cli/config/configStruct.go index a993e1616..c64c795a0 100644 --- a/cli/config/configStruct.go +++ b/cli/config/configStruct.go @@ -22,6 +22,7 @@ const ( type ConfigStruct struct { Tap configStructs.TapConfig `yaml:"tap"` + Check configStructs.CheckConfig `yaml:"check"` Version configStructs.VersionConfig `yaml:"version"` View configStructs.ViewConfig `yaml:"view"` Logs configStructs.LogsConfig `yaml:"logs"` diff --git a/cli/config/configStructs/checkConfig.go b/cli/config/configStructs/checkConfig.go new file mode 100644 index 000000000..699fe9d23 --- /dev/null +++ b/cli/config/configStructs/checkConfig.go @@ -0,0 +1,9 @@ +package configStructs + +const ( + PreTapCheckName = "pre-tap" +) + +type CheckConfig struct { + PreTap bool `yaml:"pre-tap"` +} diff --git a/shared/fileUtils.go b/shared/fileUtils.go new file mode 100644 index 000000000..976ff6c2d --- /dev/null +++ b/shared/fileUtils.go @@ -0,0 +1,20 @@ +package shared + +import ( + "io/ioutil" + "os" +) + +func ReadFromFile(path string) ([]byte, error) { + reader, err := os.Open(path) + if err != nil { + return nil, err + } + + data, err := ioutil.ReadAll(reader) + if err != nil { + return nil, err + } + + return data, nil +} diff --git a/shared/kubernetes/provider.go b/shared/kubernetes/provider.go index 18301cb05..0b16cb2a8 100644 --- a/shared/kubernetes/provider.go +++ b/shared/kubernetes/provider.go @@ -17,6 +17,7 @@ import ( "github.com/up9inc/mizu/shared/semver" "github.com/up9inc/mizu/tap/api" v1 "k8s.io/api/apps/v1" + auth "k8s.io/api/authorization/v1" core "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -443,6 +444,26 @@ func (provider *Provider) CreateService(ctx context.Context, namespace string, s return provider.clientSet.CoreV1().Services(namespace).Create(ctx, &service, metav1.CreateOptions{}) } +func (provider *Provider) CanI(ctx context.Context, namespace string, resource string, verb string, group string) (bool, error) { + selfSubjectAccessReview := &auth.SelfSubjectAccessReview{ + Spec: auth.SelfSubjectAccessReviewSpec{ + ResourceAttributes: &auth.ResourceAttributes{ + Namespace: namespace, + Resource: resource, + Verb: verb, + Group: group, + }, + }, + } + + response, err := provider.clientSet.AuthorizationV1().SelfSubjectAccessReviews().Create(ctx, selfSubjectAccessReview, metav1.CreateOptions{}) + if err != nil { + return false, err + } + + return response.Status.Allowed, nil +} + func (provider *Provider) DoesNamespaceExist(ctx context.Context, name string) (bool, error) { namespaceResource, err := provider.clientSet.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{}) return provider.doesResourceExist(namespaceResource, err) From a54cb917d01ded118ca0152833d42a95d081b71b Mon Sep 17 00:00:00 2001 From: Adam Kol <93466081+AdamKol-up9@users.noreply.github.com> Date: Thu, 24 Feb 2022 15:55:30 +0200 Subject: [PATCH 08/10] Cypress: minimum entries check (#850) --- acceptanceTests/cypress.json | 1 - .../cypress/integration/testHelpers/TrafficHelper.js | 12 +++++++----- acceptanceTests/cypress/integration/tests/GuiPort.js | 3 --- .../cypress/integration/tests/IgnoredUserAgents.js | 3 --- .../cypress/integration/tests/NoRedact.js | 4 +--- acceptanceTests/cypress/integration/tests/Redact.js | 4 +--- .../cypress/integration/tests/RegexMasking.js | 4 +--- acceptanceTests/tap_test.go | 2 +- 8 files changed, 11 insertions(+), 22 deletions(-) diff --git a/acceptanceTests/cypress.json b/acceptanceTests/cypress.json index bdb63c4d1..d6757fcb3 100644 --- a/acceptanceTests/cypress.json +++ b/acceptanceTests/cypress.json @@ -24,7 +24,6 @@ "redactHeaderContent": "User-Header[REDACTED]", "redactBodyContent": "{ \"User\": \"[REDACTED]\" }", "regexMaskingBodyContent": "[REDACTED]", - "minimumEntries": 25, "greenFilterColor": "rgb(210, 250, 210)", "redFilterColor": "rgb(250, 214, 220)", "bodyJsonClass": ".hljs", diff --git a/acceptanceTests/cypress/integration/testHelpers/TrafficHelper.js b/acceptanceTests/cypress/integration/testHelpers/TrafficHelper.js index 4471e4a6a..a38953e66 100644 --- a/acceptanceTests/cypress/integration/testHelpers/TrafficHelper.js +++ b/acceptanceTests/cypress/integration/testHelpers/TrafficHelper.js @@ -25,14 +25,16 @@ export function resizeToNormalMizu() { } export function verifyMinimumEntries() { - const minimumEntries = Cypress.env('minimumEntries'); - it(`Making sure that mizu shows at least ${minimumEntries} entries`, async function () { + const entriesSent = Cypress.env('entriesCount'); + const minimumEntries = Math.round((0.75 * entriesSent)); + + it(`Making sure that mizu shows at least ${minimumEntries} entries`, function () { cy.get('#total-entries').then(number => { const getNum = () => { - const numOfEntries = number.text(); - return parseInt(numOfEntries); + return parseInt(number.text()); }; - cy.wrap({there: getNum}).invoke('there').should('be.gte', minimumEntries); + + cy.wrap({num: getNum}).invoke('num').should('be.gt', minimumEntries); }); }); } diff --git a/acceptanceTests/cypress/integration/tests/GuiPort.js b/acceptanceTests/cypress/integration/tests/GuiPort.js index 4cd0705e5..16627db19 100644 --- a/acceptanceTests/cypress/integration/tests/GuiPort.js +++ b/acceptanceTests/cypress/integration/tests/GuiPort.js @@ -1,5 +1,4 @@ import {findLineAndCheck, getExpectedDetailsDict} from "../testHelpers/StatusBarHelper"; -import {verifyMinimumEntries} from "../testHelpers/TrafficHelper"; it('check', function () { const podName = Cypress.env('name'), namespace = Cypress.env('namespace'); @@ -9,8 +8,6 @@ it('check', function () { cy.visit(`http://localhost:${port}`); cy.wait('@statusTap').its('response.statusCode').should('match', /^2\d{2}/); - verifyMinimumEntries(); - cy.get('.podsCount').trigger('mouseover'); findLineAndCheck(getExpectedDetailsDict(podName, namespace)); }); diff --git a/acceptanceTests/cypress/integration/tests/IgnoredUserAgents.js b/acceptanceTests/cypress/integration/tests/IgnoredUserAgents.js index b608d12ac..af49fc55c 100644 --- a/acceptanceTests/cypress/integration/tests/IgnoredUserAgents.js +++ b/acceptanceTests/cypress/integration/tests/IgnoredUserAgents.js @@ -2,15 +2,12 @@ import { checkThatAllEntriesShown, isValueExistsInElement, resizeToHugeMizu, - verifyMinimumEntries } from "../testHelpers/TrafficHelper"; it('Loading Mizu', function () { cy.visit(Cypress.env('testUrl')); }); -verifyMinimumEntries(); - checkEntries(); function checkEntries() { diff --git a/acceptanceTests/cypress/integration/tests/NoRedact.js b/acceptanceTests/cypress/integration/tests/NoRedact.js index d3e640a48..ef6648b4e 100644 --- a/acceptanceTests/cypress/integration/tests/NoRedact.js +++ b/acceptanceTests/cypress/integration/tests/NoRedact.js @@ -1,10 +1,8 @@ -import {isValueExistsInElement, verifyMinimumEntries} from '../testHelpers/TrafficHelper'; +import {isValueExistsInElement} from '../testHelpers/TrafficHelper'; it('Loading Mizu', function () { cy.visit(Cypress.env('testUrl')); }); -verifyMinimumEntries(); - isValueExistsInElement(false, Cypress.env('redactHeaderContent'), '#tbody-Headers'); isValueExistsInElement(false, Cypress.env('redactBodyContent'), Cypress.env('bodyJsonClass')); diff --git a/acceptanceTests/cypress/integration/tests/Redact.js b/acceptanceTests/cypress/integration/tests/Redact.js index 43f5d81e1..79db59b51 100644 --- a/acceptanceTests/cypress/integration/tests/Redact.js +++ b/acceptanceTests/cypress/integration/tests/Redact.js @@ -1,10 +1,8 @@ -import {isValueExistsInElement, verifyMinimumEntries} from '../testHelpers/TrafficHelper'; +import {isValueExistsInElement} from '../testHelpers/TrafficHelper'; it('Loading Mizu', function () { cy.visit(Cypress.env('testUrl')); }); -verifyMinimumEntries(); - isValueExistsInElement(true, Cypress.env('redactHeaderContent'), '#tbody-Headers'); isValueExistsInElement(true, Cypress.env('redactBodyContent'), Cypress.env('bodyJsonClass')); diff --git a/acceptanceTests/cypress/integration/tests/RegexMasking.js b/acceptanceTests/cypress/integration/tests/RegexMasking.js index c0f53e388..9f3f20fac 100644 --- a/acceptanceTests/cypress/integration/tests/RegexMasking.js +++ b/acceptanceTests/cypress/integration/tests/RegexMasking.js @@ -1,9 +1,7 @@ -import {isValueExistsInElement, verifyMinimumEntries} from "../testHelpers/TrafficHelper"; +import {isValueExistsInElement} from "../testHelpers/TrafficHelper"; it('Loading Mizu', function () { cy.visit(Cypress.env('testUrl')); }); -verifyMinimumEntries(); - isValueExistsInElement(true, Cypress.env('regexMaskingBodyContent'), Cypress.env('bodyJsonClass')); diff --git a/acceptanceTests/tap_test.go b/acceptanceTests/tap_test.go index 3840f7799..b27c2907b 100644 --- a/acceptanceTests/tap_test.go +++ b/acceptanceTests/tap_test.go @@ -62,7 +62,7 @@ func TestTap(t *testing.T) { } } - runCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/UiTest.js\"") + runCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/UiTest.js\" --env entriesCount=%d", entriesCount)) }) } } From c5a36a494abd5ca901dbf4255122a4712d2fce45 Mon Sep 17 00:00:00 2001 From: RoyUP9 <87927115+RoyUP9@users.noreply.github.com> Date: Thu, 24 Feb 2022 16:08:36 +0200 Subject: [PATCH 09/10] Removed install check (#851) * Removed install check * Update cli/cmd/checkRunner.go Co-authored-by: Igor Gov * no message Co-authored-by: Igor Gov --- cli/cmd/checkRunner.go | 54 ++++-------------------------------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/cli/cmd/checkRunner.go b/cli/cmd/checkRunner.go index 24d140acd..5a05c10a8 100644 --- a/cli/cmd/checkRunner.go +++ b/cli/cmd/checkRunner.go @@ -34,13 +34,8 @@ func runMizuCheck() { checkPassed = checkK8sTapPermissions(ctx, kubernetesProvider) } } else { - var isInstallCommand bool if checkPassed { - checkPassed, isInstallCommand = checkMizuMode(ctx, kubernetesProvider) - } - - if checkPassed { - checkPassed = checkK8sResources(ctx, kubernetesProvider, isInstallCommand) + checkPassed = checkK8sResources(ctx, kubernetesProvider) } if checkPassed { @@ -75,27 +70,6 @@ func checkKubernetesApi() (*kubernetes.Provider, *semver.SemVersion, bool) { return kubernetesProvider, kubernetesVersion, true } -func checkMizuMode(ctx context.Context, kubernetesProvider *kubernetes.Provider) (bool, bool) { - logger.Log.Infof("\nmode\n--------------------") - - if exist, err := kubernetesProvider.DoesDeploymentExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName); err != nil { - logger.Log.Errorf("%v can't check mizu command, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err) - return false, false - } else if exist { - logger.Log.Infof("%v mizu running with install command", fmt.Sprintf(uiUtils.Green, "√")) - return true, true - } else if exist, err = kubernetesProvider.DoesPodExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName); err != nil { - logger.Log.Errorf("%v can't check mizu command, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err) - return false, false - } else if exist { - logger.Log.Infof("%v mizu running with tap command", fmt.Sprintf(uiUtils.Green, "√")) - return true, false - } else { - logger.Log.Infof("%v mizu is not running", fmt.Sprintf(uiUtils.Red, "✗")) - return false, false - } -} - func checkKubernetesVersion(kubernetesVersion *semver.SemVersion) bool { logger.Log.Infof("\nkubernetes-version\n--------------------") @@ -179,7 +153,7 @@ func checkPortForward(serverUrl string, kubernetesProvider *kubernetes.Provider) return nil } -func checkK8sResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, isInstallCommand bool) bool { +func checkK8sResources(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool { logger.Log.Infof("\nk8s-components\n--------------------") exist, err := kubernetesProvider.DoesNamespaceExist(ctx, config.Config.MizuResourcesNamespace) @@ -208,32 +182,12 @@ func checkK8sResources(ctx context.Context, kubernetesProvider *kubernetes.Provi exist, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName) allResourcesExist = checkResourceExist(kubernetes.ApiServerPodName, "service", exist, err) && allResourcesExist - if isInstallCommand { - allResourcesExist = checkInstallResourcesExist(ctx, kubernetesProvider) && allResourcesExist - } else { - allResourcesExist = checkTapResourcesExist(ctx, kubernetesProvider) && allResourcesExist - } + allResourcesExist = checkPodResourcesExist(ctx, kubernetesProvider) && allResourcesExist return allResourcesExist } -func checkInstallResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool { - exist, err := kubernetesProvider.DoesRoleExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.DaemonRoleName) - installResourcesExist := checkResourceExist(kubernetes.DaemonRoleName, "role", exist, err) - - exist, err = kubernetesProvider.DoesRoleBindingExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.DaemonRoleBindingName) - installResourcesExist = checkResourceExist(kubernetes.DaemonRoleBindingName, "role binding", exist, err) && installResourcesExist - - exist, err = kubernetesProvider.DoesPersistentVolumeClaimExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.PersistentVolumeClaimName) - installResourcesExist = checkResourceExist(kubernetes.PersistentVolumeClaimName, "persistent volume claim", exist, err) && installResourcesExist - - exist, err = kubernetesProvider.DoesDeploymentExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName) - installResourcesExist = checkResourceExist(kubernetes.ApiServerPodName, "deployment", exist, err) && installResourcesExist - - return installResourcesExist -} - -func checkTapResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool { +func checkPodResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool { exist, err := kubernetesProvider.DoesPodExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName) tapResourcesExist := checkResourceExist(kubernetes.ApiServerPodName, "pod", exist, err) From d8c0132a9842a975b63bfd9db15af520d91c02bf Mon Sep 17 00:00:00 2001 From: RoyUP9 <87927115+RoyUP9@users.noreply.github.com> Date: Thu, 24 Feb 2022 16:46:51 +0200 Subject: [PATCH 10/10] Fixed location of pre tap permission files (#852) --- cli/cmd/checkRunner.go | 13 ++++++++---- ...issions-all-namespaces-debug-optional.yaml | 0 ...all-namespaces-ip-resolution-optional.yaml | 0 .../permissions-all-namespaces-tap.yaml | 0 .../permissions-ns-debug-optional.yaml | 0 ...permissions-ns-ip-resolution-optional.yaml | 0 .../permissionFiles}/permissions-ns-tap.yaml | 0 docs/PERMISSIONS.md | 2 +- shared/fileUtils.go | 20 ------------------- 9 files changed, 10 insertions(+), 25 deletions(-) rename {examples/roles => cli/cmd/permissionFiles}/permissions-all-namespaces-debug-optional.yaml (100%) rename {examples/roles => cli/cmd/permissionFiles}/permissions-all-namespaces-ip-resolution-optional.yaml (100%) rename {examples/roles => cli/cmd/permissionFiles}/permissions-all-namespaces-tap.yaml (100%) rename {examples/roles => cli/cmd/permissionFiles}/permissions-ns-debug-optional.yaml (100%) rename {examples/roles => cli/cmd/permissionFiles}/permissions-ns-ip-resolution-optional.yaml (100%) rename {examples/roles => cli/cmd/permissionFiles}/permissions-ns-tap.yaml (100%) delete mode 100644 shared/fileUtils.go diff --git a/cli/cmd/checkRunner.go b/cli/cmd/checkRunner.go index 5a05c10a8..7bf75d090 100644 --- a/cli/cmd/checkRunner.go +++ b/cli/cmd/checkRunner.go @@ -2,8 +2,8 @@ package cmd import ( "context" + "embed" "fmt" - "github.com/up9inc/mizu/shared" rbac "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/scheme" @@ -17,6 +17,11 @@ import ( "github.com/up9inc/mizu/shared/semver" ) +var ( + //go:embed permissionFiles + embedFS embed.FS +) + func runMizuCheck() { logger.Log.Infof("Mizu checks\n===================") @@ -248,12 +253,12 @@ func checkK8sTapPermissions(ctx context.Context, kubernetesProvider *kubernetes. var filePath string if config.Config.IsNsRestrictedMode() { - filePath = "./examples/roles/permissions-ns-tap.yaml" + filePath = "permissionFiles/permissions-ns-tap.yaml" } else { - filePath = "./examples/roles/permissions-all-namespaces-tap.yaml" + filePath = "permissionFiles/permissions-all-namespaces-tap.yaml" } - data, err := shared.ReadFromFile(filePath) + data, err := embedFS.ReadFile(filePath) if err != nil { logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err) return false diff --git a/examples/roles/permissions-all-namespaces-debug-optional.yaml b/cli/cmd/permissionFiles/permissions-all-namespaces-debug-optional.yaml similarity index 100% rename from examples/roles/permissions-all-namespaces-debug-optional.yaml rename to cli/cmd/permissionFiles/permissions-all-namespaces-debug-optional.yaml diff --git a/examples/roles/permissions-all-namespaces-ip-resolution-optional.yaml b/cli/cmd/permissionFiles/permissions-all-namespaces-ip-resolution-optional.yaml similarity index 100% rename from examples/roles/permissions-all-namespaces-ip-resolution-optional.yaml rename to cli/cmd/permissionFiles/permissions-all-namespaces-ip-resolution-optional.yaml diff --git a/examples/roles/permissions-all-namespaces-tap.yaml b/cli/cmd/permissionFiles/permissions-all-namespaces-tap.yaml similarity index 100% rename from examples/roles/permissions-all-namespaces-tap.yaml rename to cli/cmd/permissionFiles/permissions-all-namespaces-tap.yaml diff --git a/examples/roles/permissions-ns-debug-optional.yaml b/cli/cmd/permissionFiles/permissions-ns-debug-optional.yaml similarity index 100% rename from examples/roles/permissions-ns-debug-optional.yaml rename to cli/cmd/permissionFiles/permissions-ns-debug-optional.yaml diff --git a/examples/roles/permissions-ns-ip-resolution-optional.yaml b/cli/cmd/permissionFiles/permissions-ns-ip-resolution-optional.yaml similarity index 100% rename from examples/roles/permissions-ns-ip-resolution-optional.yaml rename to cli/cmd/permissionFiles/permissions-ns-ip-resolution-optional.yaml diff --git a/examples/roles/permissions-ns-tap.yaml b/cli/cmd/permissionFiles/permissions-ns-tap.yaml similarity index 100% rename from examples/roles/permissions-ns-tap.yaml rename to cli/cmd/permissionFiles/permissions-ns-tap.yaml diff --git a/docs/PERMISSIONS.md b/docs/PERMISSIONS.md index 0574cdfd0..5301693bf 100644 --- a/docs/PERMISSIONS.md +++ b/docs/PERMISSIONS.md @@ -85,4 +85,4 @@ By default Mizu requires cluster-wide permissions. If these are not available to the user, it is possible to run Mizu in namespace-restricted mode which has a reduced set of requirements. This is done by by setting the `mizu-resources-namespace` config option. See [configuration](CONFIGURATION.md) for instructions. -The different requirements are listed in [the example roles dir](../examples/roles) +The different requirements are listed in [the permission templates dir](../cli/cmd/permissionFiles) diff --git a/shared/fileUtils.go b/shared/fileUtils.go deleted file mode 100644 index 976ff6c2d..000000000 --- a/shared/fileUtils.go +++ /dev/null @@ -1,20 +0,0 @@ -package shared - -import ( - "io/ioutil" - "os" -) - -func ReadFromFile(path string) ([]byte, error) { - reader, err := os.Open(path) - if err != nil { - return nil, err - } - - data, err := ioutil.ReadAll(reader) - if err != nil { - return nil, err - } - - return data, nil -}