From fbcfc103ddd08f5004ec7d43d6efcc2ebb128bef Mon Sep 17 00:00:00 2001 From: Edgar Gomes Date: Thu, 22 Aug 2024 10:46:51 -0300 Subject: [PATCH 1/7] chore: clean-up GH cache (#21) * add cache cleaning after merges * add comment --- .github/workflows/cache-clean-up.yaml | 29 +++++++++++++++++++++++++++ .github/workflows/ci.yml | 7 ++++--- 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/cache-clean-up.yaml diff --git a/.github/workflows/cache-clean-up.yaml b/.github/workflows/cache-clean-up.yaml new file mode 100644 index 0000000..e6bdb12 --- /dev/null +++ b/.github/workflows/cache-clean-up.yaml @@ -0,0 +1,29 @@ +name: cleanup caches by a branch +on: + pull_request: + types: + - closed + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + echo "Fetching list of cache key" + cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 ) + + ## Setting this to not fail the workflow while deleting cache keys. + set +e + echo "Deleting caches..." + for cacheKey in $cacheKeysForPR + do + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + echo "Done" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e1e7ed7..2d3f661 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,7 +62,8 @@ jobs: strategy: matrix: component: [kontrol-service, kontrol-frontend] - # arch: [amd64, arm64] + # Skipping arm64 builds due GH cache rate limit casue by the + # number of cache entries generated by pkgsCross builds arch: [amd64] steps: - name: Git checkout @@ -77,14 +78,14 @@ jobs: # relax sandbox due impure kontrol-service tests during build extra_nix_config: | sandbox = relaxed - # extra-platforms = aarch64-linux + extra-platforms = aarch64-linux - name: Magic cache uses: DeterminateSystems/magic-nix-cache-action@v7 - name: Build ${{ matrix.component }} run: | - nix build .#${{ matrix.component }} --print-build-logs + nix build .#${{ matrix.component }} --no-link --print-out-paths --print-build-logs - name: Build ${{ matrix.component }} for ${{ matrix.arch }} run: | From daeb5538b92e7f657d1365b321228f12acdeb973 Mon Sep 17 00:00:00 2001 From: Skylar Date: Thu, 22 Aug 2024 13:21:45 -0700 Subject: [PATCH 2/7] feat: Templates UI part 3 (#18) * fix: fix disabled state and form input values * feat: index view for templates * feat: select services from the graph * chore: pin.json * Update pin.json * Update pin.json * Update pin.json * chore: bun.lockb * fix: stable hashes (#22) * dbg: frontend hashes * dbg: add x64 hash * dbg: reduce logs * fix lint * re-enable relaxed sandbox for testing * Update pin.json --------- Co-authored-by: Edgar Gomes --- .github/workflows/ci.yml | 6 +- kontrol-frontend/bun.lockb | Bin 383796 -> 384411 bytes kontrol-frontend/package.json | 1 + kontrol-frontend/pin.json | 8 +- .../src/components/CytoscapeGraph/index.tsx | 16 ++-- kontrol-frontend/src/components/Fallback.tsx | 2 - .../src/components/Footer/Footer.stories.tsx | 14 --- .../src/components/Footer/index.tsx | 23 ----- .../src/components/Input/index.tsx | 4 +- .../{Table => TemplatesTable}/Hat.tsx | 0 .../{Table => TemplatesTable}/Head.tsx | 6 +- .../{Table => TemplatesTable}/Row.tsx | 13 +-- .../TemplatesTable.stories.tsx} | 0 .../{Table => TemplatesTable}/index.tsx | 15 ++-- kontrol-frontend/src/contexts/ApiContext.tsx | 6 +- kontrol-frontend/src/pages/FlowsCreate.tsx | 83 +++++++++++++----- kontrol-frontend/src/pages/FlowsIndex.tsx | 36 ++++++-- kontrol-frontend/src/theme.ts | 39 +++++++- kontrol-frontend/src/types.d.ts | 4 + 19 files changed, 175 insertions(+), 101 deletions(-) delete mode 100644 kontrol-frontend/src/components/Footer/Footer.stories.tsx delete mode 100644 kontrol-frontend/src/components/Footer/index.tsx rename kontrol-frontend/src/components/{Table => TemplatesTable}/Hat.tsx (100%) rename kontrol-frontend/src/components/{Table => TemplatesTable}/Head.tsx (92%) rename kontrol-frontend/src/components/{Table => TemplatesTable}/Row.tsx (90%) rename kontrol-frontend/src/components/{Table/Table.stories.tsx => TemplatesTable/TemplatesTable.stories.tsx} (100%) rename kontrol-frontend/src/components/{Table => TemplatesTable}/index.tsx (72%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d3f661..96a45f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,16 +77,16 @@ jobs: with: # relax sandbox due impure kontrol-service tests during build extra_nix_config: | - sandbox = relaxed extra-platforms = aarch64-linux + sandbox = relaxed - name: Magic cache uses: DeterminateSystems/magic-nix-cache-action@v7 - name: Build ${{ matrix.component }} run: | - nix build .#${{ matrix.component }} --no-link --print-out-paths --print-build-logs + nix build .#${{ matrix.component }} --no-link --print-out-paths - name: Build ${{ matrix.component }} for ${{ matrix.arch }} run: | - nix build ./#containers.x86_64-linux.${{ matrix.component }}.${{ matrix.arch }} --no-link --print-out-paths --print-build-logs + nix build ./#containers.x86_64-linux.${{ matrix.component }}.${{ matrix.arch }} --no-link --print-out-paths diff --git a/kontrol-frontend/bun.lockb b/kontrol-frontend/bun.lockb index 3ca57b6610c78473a878133e66d1162627835d3b..9248283d6b6aaabb609d550a657462f689d7a21d 100755 GIT binary patch delta 72425 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�FuVDerVFj5TY@k`_xqo5)YF3n+XVmVhN< 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

>pba-=w4YN&6LAx=r1eX>W3FYO+r&Vk0e| z3^}4@lsN~r?D^xnM)&R1u|)rVu|48bM2_z_s0X~`2gUd6)Kj7kY6WH30j-e81w7q4 zpw*TFhqT?Y=&9@3im R%GRaYa^t=F1MSK4{{x9I2c-Z2 delta 72091 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 P!eJ$I;-*K+lNbLFh>ueW diff --git a/kontrol-frontend/package.json b/kontrol-frontend/package.json index af525f1..57d22f6 100644 --- a/kontrol-frontend/package.json +++ b/kontrol-frontend/package.json @@ -18,6 +18,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@react-hooks-library/core": "^0.6.2", + "chakra-multiselect": "^0.4.13", "cli-kontrol-api": "file:../.cli-kontrol-api", "cytoscape": "^3.29.2", "cytoscape-dagre": "^2.5.0", diff --git a/kontrol-frontend/pin.json b/kontrol-frontend/pin.json index e70ea37..483271d 100644 --- a/kontrol-frontend/pin.json +++ b/kontrol-frontend/pin.json @@ -1,7 +1,7 @@ { - "version": "0.7.0", + "version": "0.8.0", "x86_64-darwin": "", - "x86_64-linux": "sha256-BL4hEU89HISHpf4ZdEchk44DeCXoqZgCOYUY8uhvIrI=", - "aarch64-darwin": "sha256-pUzndLxvEN5rQhiBtX8oxlPZKVDJOcSZzF1JhejQkcc=", - "aarch64-linux": "sha256-l509Oy4gSClFGMk5anfdq4JFyXMXOTbpn2H2XLaAzb4=" + "x86_64-linux": "sha256-4lx4eSRv+auM27K4RLyLVS3lk4+a5SCFrsyBrOY2qMI=", + "aarch64-darwin": "sha256-mSmC23SczyR2V7xoS7+bnN5g+X5EVJTy74pH3+Ld/C8=", + "aarch64-linux": "sha256-iHZRAxgNluI3bvXIc6hgkAs/xM9Z4ib5W1ifnvGs9SQ=" } diff --git a/kontrol-frontend/src/components/CytoscapeGraph/index.tsx b/kontrol-frontend/src/components/CytoscapeGraph/index.tsx index 368f957..68d4c04 100644 --- a/kontrol-frontend/src/components/CytoscapeGraph/index.tsx +++ b/kontrol-frontend/src/components/CytoscapeGraph/index.tsx @@ -19,9 +19,14 @@ const INIT_ANIMATIONS_ENABLED = false; interface Props { elements: cytoscape.ElementDefinition[]; layout?: cytoscape.LayoutOptions; + onNodeClick?: (node: cytoscape.NodeSingular) => void; } -const CytoscapeGraph = ({ elements, layout = dagreLayout }: Props) => { +const CytoscapeGraph = ({ + elements, + layout = dagreLayout, + onNodeClick, +}: Props) => { // keep a ref to the cy instance. using state will cause infinite re-renders const cy = useRef(); const tooltip = useRef(null); @@ -43,11 +48,11 @@ const CytoscapeGraph = ({ elements, layout = dagreLayout }: Props) => { // set mutable cy instance cy.current = cyInstance; // add event listeners to create tooltips on hover - cy.current.on("mouseover", function (ele: cytoscape.EventObject) { + cy.current.on("mouseover", function (e: cytoscape.EventObject) { if (tooltip.current != null) { tooltip.current.destroy(); } - tooltip.current = createTooltip(ele.target); + tooltip.current = createTooltip(e.target); }); cy.current.on("mouseout", function () { if (tooltip.current != null) { @@ -67,11 +72,12 @@ const CytoscapeGraph = ({ elements, layout = dagreLayout }: Props) => { tooltip.current = null; }); // re-start animations when the user is done with interactions - cy.current.on("tapend", function () { + cy.current.on("tapend", function (e: cytoscape.EventObject) { setTimeout(() => setAnimationsEnabled(INIT_ANIMATIONS_ENABLED), 0); + onNodeClick?.(e.target); }); }, - [setAnimationsEnabled], + [setAnimationsEnabled, onNodeClick], ); // when animation is disabled, remove all animated traffic nodes diff --git a/kontrol-frontend/src/components/Fallback.tsx b/kontrol-frontend/src/components/Fallback.tsx index 456b840..98b58ea 100644 --- a/kontrol-frontend/src/components/Fallback.tsx +++ b/kontrol-frontend/src/components/Fallback.tsx @@ -15,8 +15,6 @@ interface Props { } const Fallback = ({ error, resetErrorBoundary }: Props) => { - // Call resetErrorBoundary() to reset the error boundary and retry the render. - console.debug({ error }); const { onClose } = useDisclosure(); return ( diff --git a/kontrol-frontend/src/components/Footer/Footer.stories.tsx b/kontrol-frontend/src/components/Footer/Footer.stories.tsx deleted file mode 100644 index cbd1b07..0000000 --- a/kontrol-frontend/src/components/Footer/Footer.stories.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import type { Meta, StoryObj } from "@storybook/react"; - -import Footer from "."; - -const meta: Meta = { - component: Footer, -}; - -export default meta; -type Story = StoryObj; - -export const Example: Story = { - args: {}, -}; diff --git a/kontrol-frontend/src/components/Footer/index.tsx b/kontrol-frontend/src/components/Footer/index.tsx deleted file mode 100644 index 44999d1..0000000 --- a/kontrol-frontend/src/components/Footer/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Flex } from "@chakra-ui/react"; -import Button from "@/components/Button"; -import { Link } from "react-router-dom"; -import { useFlowsContext } from "@/contexts/FlowsContext"; - -const Footer = () => { - const { createExampleFlow } = useFlowsContext(); - return ( - - - - ); -}; - -export default Footer; diff --git a/kontrol-frontend/src/components/Input/index.tsx b/kontrol-frontend/src/components/Input/index.tsx index f2624a5..42b850b 100644 --- a/kontrol-frontend/src/components/Input/index.tsx +++ b/kontrol-frontend/src/components/Input/index.tsx @@ -1,9 +1,11 @@ import TextInput, { Props as TextInputProps } from "./TextInput"; import SelectInput, { Props as SelectInputProps } from "./SelectInput"; +import { MultiSelect, Option } from "chakra-multiselect"; -export type { TextInputProps, SelectInputProps }; +export type { TextInputProps, SelectInputProps, Option }; export default { Text: TextInput, Select: SelectInput, + MultiSelect, }; diff --git a/kontrol-frontend/src/components/Table/Hat.tsx b/kontrol-frontend/src/components/TemplatesTable/Hat.tsx similarity index 100% rename from kontrol-frontend/src/components/Table/Hat.tsx rename to kontrol-frontend/src/components/TemplatesTable/Hat.tsx diff --git a/kontrol-frontend/src/components/Table/Head.tsx b/kontrol-frontend/src/components/TemplatesTable/Head.tsx similarity index 92% rename from kontrol-frontend/src/components/Table/Head.tsx rename to kontrol-frontend/src/components/TemplatesTable/Head.tsx index 1a49ab1..df678d4 100644 --- a/kontrol-frontend/src/components/Table/Head.tsx +++ b/kontrol-frontend/src/components/TemplatesTable/Head.tsx @@ -14,14 +14,16 @@ const Head = () => { {/* empty */} - Flow template + Template name - Service + Template ID + {/* Data layer + */} void; } -const Row = ({ id, isExpanded, onExpandRow }: Props) => { +const Row = ({ template, id, isExpanded, onExpandRow }: Props) => { const { deleteExampleFlow } = useFlowsContext(); return ( @@ -80,7 +81,7 @@ const Row = ({ id, isExpanded, onExpandRow }: Props) => { } > - Early development flow + {template.name} { } > - awesome-kardinal-example + {template["template-id"]} + {/* @@ -108,6 +110,7 @@ const Row = ({ id, isExpanded, onExpandRow }: Props) => { + */} } aria-label="Play" variant="ghost" /> diff --git a/kontrol-frontend/src/components/Table/Table.stories.tsx b/kontrol-frontend/src/components/TemplatesTable/TemplatesTable.stories.tsx similarity index 100% rename from kontrol-frontend/src/components/Table/Table.stories.tsx rename to kontrol-frontend/src/components/TemplatesTable/TemplatesTable.stories.tsx diff --git a/kontrol-frontend/src/components/Table/index.tsx b/kontrol-frontend/src/components/TemplatesTable/index.tsx similarity index 72% rename from kontrol-frontend/src/components/Table/index.tsx rename to kontrol-frontend/src/components/TemplatesTable/index.tsx index b14387e..a9f8beb 100644 --- a/kontrol-frontend/src/components/Table/index.tsx +++ b/kontrol-frontend/src/components/TemplatesTable/index.tsx @@ -3,10 +3,12 @@ import Hat from "./Hat"; import Head from "./Head"; import Row from "./Row"; import { useState } from "react"; +import { Template } from "@/types"; -const rows = ["a"]; - -const FlowConfigurationTable = () => { +interface Props { + templates: Template[]; +} +const FlowConfigurationTable = ({ templates }: Props) => { const [expandedRowId, setExpandedRowId] = useState(null); const handleExpandRow = (rowId: string | null) => { @@ -26,10 +28,11 @@ const FlowConfigurationTable = () => { - {rows.map((rowId) => ( + {templates.map((t) => ( ))} diff --git a/kontrol-frontend/src/contexts/ApiContext.tsx b/kontrol-frontend/src/contexts/ApiContext.tsx index 182b52e..a1ae374 100644 --- a/kontrol-frontend/src/contexts/ApiContext.tsx +++ b/kontrol-frontend/src/contexts/ApiContext.tsx @@ -2,6 +2,7 @@ import { paths, components } from "cli-kontrol-api/api/typescript/client/types"; import { matchPath } from "react-router-dom"; import createClient from "openapi-fetch"; import type { HttpMethod } from "openapi-typescript-helpers"; +import { Flow, Template } from "@/types"; const client = createClient({ baseUrl: import.meta.env.VITE_API_URL }); @@ -14,10 +15,6 @@ import { PropsWithChildren, } from "react"; -// Type aliases for ease of use -export type Template = components["schemas"]["Template"]; -export type Flow = components["schemas"]["Flow"]; - // infer the request body type from the OpenAPI schema export type RequestBody< T extends keyof paths, @@ -141,7 +138,6 @@ export const ApiContextProvider = ({ children }: PropsWithChildren) => { // GET "/tenant/{uuid}/topology" const getTopology = useCallback(async () => { if (uuid == null) { - debugger; throw new Error("Invalid or missing tenant UUID"); } const topology = await handleApiCall( diff --git a/kontrol-frontend/src/pages/FlowsCreate.tsx b/kontrol-frontend/src/pages/FlowsCreate.tsx index 550b1d0..026195a 100644 --- a/kontrol-frontend/src/pages/FlowsCreate.tsx +++ b/kontrol-frontend/src/pages/FlowsCreate.tsx @@ -1,19 +1,20 @@ import Layout from "@/components/Layout"; +import Button from "@/components/Button"; import Section from "@/components/Section"; import PageTitle from "@/components/PageTitle"; -import Footer from "@/components/Footer"; -import Input from "@/components/Input"; -import { Stack, Flex } from "@chakra-ui/react"; +import Input, { Option } from "@/components/Input"; +import { Stack, Flex, Grid } from "@chakra-ui/react"; import StatefulService from "@/components/StatefulService"; import CytoscapeGraph, { utils } from "@/components/CytoscapeGraph"; import { ChangeEvent, useEffect, useState } from "react"; import { ClusterTopology, Node } from "@/types"; import { useApi } from "@/contexts/ApiContext"; +import { useNavigate } from "react-router-dom"; // TODO: This should be imported from the OpenAPI schema once the types there // are generated correctly interface TemplateConfig { - service: string[]; + service: Option[]; /** @description The name to give the template */ name: string; /** @description The description of the template */ @@ -21,7 +22,8 @@ interface TemplateConfig { } const Page = () => { - const { getTopology } = useApi(); + const navigate = useNavigate(); + const { getTopology, postTemplateCreate } = useApi(); const [loading, setLoading] = useState(true); @@ -37,7 +39,7 @@ const Page = () => { // All input values for the form const [formState, setFormState] = useState>({ name: "", - service: ["frontend"], + service: [], description: "", }); @@ -45,20 +47,22 @@ const Page = () => { const previewTopology = utils.normalizeData({ ...topology, nodes: topology.nodes.map((node) => { - console.log(services, "includes", node.id, services.includes(node.id)); return { ...node, - versions: formState.service.includes(node.id) - ? [...(node.versions || []), "preview"] - : node.versions, + versions: + formState.service.find((o) => o.value === node.id) != null + ? ["prod", "new-dev-flow"] + : ["prod"], }; }), }); // TODO: Not hardcoding this const templateContainsExternalApi = - formState.service.includes("jsdelivr-api"); - const templateContainsPostgres = formState.service.includes("postgres"); + formState.service.find((o) => o.value === "jsdelivr-api") != null; + // TODO: Not hardcoding this + const templateContainsPostgres = + formState.service.find((o) => o.value === "postgres") != null; useEffect(() => { async function fetchData() { @@ -93,13 +97,45 @@ const Page = () => { })); }; + const handleMultiSelectChange = + (field: keyof TemplateConfig) => (option: Option | Option[]) => { + console.log("option", option); + setFormState((prevState) => ({ + ...prevState, + [field]: option, + })); + }; + + const handleCreateFlowTemplate = async () => { + await postTemplateCreate(formState); + navigate("../"); + }; + + const handleNodeClick = (node: cytoscape.NodeSingular) => { + const nodeId = node.data("id"); + handleMultiSelectChange("service")([ + ...formState.service, + { + label: nodeId, + value: nodeId, + }, + ]); + }; + + const formIsValid = formState.name.length > 0 && formState.service.length > 0; + return ( Update traffic control and data isolation details below
- {!loading && } + {!loading && ( + + )}
@@ -119,15 +155,18 @@ const Page = () => { onChange={handleInputChange("description")} /> - - + ({ label: s, value: s })) || []} - value={formState.service[0] ?? ""} + options={services.map( + (service) => ({ label: service, value: service }) as Option, + )} + value={formState.service} id="service" - onChange={handleInputChange("service")} + onChange={handleMultiSelectChange("service")} + width={"100%"} /> - +
{templateContainsExternalApi && ( @@ -140,7 +179,11 @@ const Page = () => { )} -
+ + + ); }; diff --git a/kontrol-frontend/src/pages/FlowsIndex.tsx b/kontrol-frontend/src/pages/FlowsIndex.tsx index 4c05af8..5e66a4e 100644 --- a/kontrol-frontend/src/pages/FlowsIndex.tsx +++ b/kontrol-frontend/src/pages/FlowsIndex.tsx @@ -1,19 +1,41 @@ import EmptyState from "@/components/EmptyState"; import PageTitle from "@/components/PageTitle"; -import { useFlowsContext } from "@/contexts/FlowsContext"; -import { Stack } from "@chakra-ui/react"; +import { Spinner, Stack } from "@chakra-ui/react"; import { FiShield } from "react-icons/fi"; -import Table from "@/components/Table"; +import TemplatesTable from "@/components/TemplatesTable"; +import { useApi } from "@/contexts/ApiContext"; +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; const Page = () => { - const { flows } = useFlowsContext(); + const [loading, setLoading] = useState(true); + const { templates, getTemplates } = useApi(); + const navigate = useNavigate(); + useEffect(() => { + const fetchTemplates = async () => { + await getTemplates(); + }; + fetchTemplates(); + setLoading(false); + }, [getTemplates]); + + if (loading) { + return ; + } + return ( - + { + navigate("create"); + }} + > See a list of all available flow configurations for your organization - {flows.length > 0 ? ( -
+ {templates.length > 0 ? ( + ) : ( > = { gray: { "50": "#F9FAFB", @@ -38,10 +36,43 @@ export const colorOverrides: Record> = { }, }; -// 4. extend the theme +// extend the theme const theme = extendTheme({ config, colors: colorOverrides, + components: { + MultiSelect: { + ...MultiSelectTheme, + baseStyle: (props: Record) => { + const baseStyles = MultiSelectTheme.baseStyle(props); + return { + ...baseStyles, + input: { + ...baseStyles.input, + flexGrow: 1, + }, + defaultProps: { + size: "lg", + w: "100%", + }, + list: { + ...baseStyles.list, + borderRadius: "12px", + }, + control: { + ...baseStyles.control, + borderRadius: "12px", + height: "48px", + flexGrow: 0, + }, + actionGroup: { + ...baseStyles.actionGroup, + flexGrow: 0, + }, + }; + }, + }, + }, fonts: { body: "'DM Sans', 'sans-serif'", }, diff --git a/kontrol-frontend/src/types.d.ts b/kontrol-frontend/src/types.d.ts index 88d076e..941b57b 100644 --- a/kontrol-frontend/src/types.d.ts +++ b/kontrol-frontend/src/types.d.ts @@ -8,3 +8,7 @@ export interface ExtendedNode { data: Node; classes: string; } + +// Type aliases for ease of use +export type Template = components["schemas"]["Template"]; +export type Flow = components["schemas"]["Flow"]; From 882fb95f6cdf080f9b871e9c0e7fe64e54fdff8e Mon Sep 17 00:00:00 2001 From: Laurent Luce Date: Thu, 22 Aug 2024 16:42:37 -0400 Subject: [PATCH 3/7] fix: DB env vars validation + Tenant create only on deploy (#19) * chore(main): release 0.1.16 (#162) :robot: I have created a release *beep* *boop* --- ## [0.1.16](https://github.com/kurtosis-tech/kardinal-kontrol-private/compare/0.1.15...0.1.16) (2024-08-16) ### Features * allow for templates to work ([#160](https://github.com/kurtosis-tech/kardinal-kontrol-private/issues/160)) ([3f70e0a](https://github.com/kurtosis-tech/kardinal-kontrol-private/commit/3f70e0a001cc4027fb7e17d54c4529152cb491a9)) * RDS cloud formation and DB secrets exposed to kontrol service pods ([#147](https://github.com/kurtosis-tech/kardinal-kontrol-private/issues/147)) ([0457a89](https://github.com/kurtosis-tech/kardinal-kontrol-private/commit/0457a893fb3274e6f4dbd11e4e0786a1c7567035)) ### Bug Fixes * allow for job to run on kontrol private repo ([#170](https://github.com/kurtosis-tech/kardinal-kontrol-private/issues/170)) ([786e7be](https://github.com/kurtosis-tech/kardinal-kontrol-private/commit/786e7be2fb02b89ce296aecd393da81af38c8825)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). * Validate DB env vars * Only create tenant during deploy * Lint * Add DB info to the READMEs. --------- Co-authored-by: Edgar Gomes --- README.md | 4 +- kontrol-service/README.md | 4 +- kontrol-service/api/server.go | 6 ++- kontrol-service/database/tenant.go | 14 +++++++ kontrol-service/main.go | 59 +++++++++++++++--------------- 5 files changed, 54 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 7cdfc3f..5ef6707 100644 --- a/README.md +++ b/README.md @@ -49,10 +49,10 @@ eval $(minikube docker-env) docker load < $(nix build ./#kontrol-service-container --no-link --print-out-paths) ``` -To build and run the service directly in dev mode: +To build and run the service directly in dev mode (a locally running Postgres DB is required): ```bash -nix run ./#kontrol-service -- -dev-mode +DB_HOSTNAME=localhost DB_USERNAME=postgres DB_NAME=kardinal DB_PORT=5432 DB_PASSWORD= nix run ./#kontrol-service -- -dev-mode ``` ### Regenerate gomod2nix.toml diff --git a/kontrol-service/README.md b/kontrol-service/README.md index 95af8a1..96195b2 100644 --- a/kontrol-service/README.md +++ b/kontrol-service/README.md @@ -2,10 +2,12 @@ ## Development +A locally running Postgres DB is required. + Use the following command to start KK in dev mode (hot-reload): ```bash -./dev-start-kk.sh --apply-directly +DB_HOSTNAME=localhost DB_USERNAME=postgres DB_NAME=kardinal DB_PORT=5432 DB_PASSWORD= ./dev-start-kk.sh --apply-directly ``` ## Updating the API from the public repo diff --git a/kontrol-service/api/server.go b/kontrol-service/api/server.go index 6f7bcbc..b8849ca 100644 --- a/kontrol-service/api/server.go +++ b/kontrol-service/api/server.go @@ -408,12 +408,16 @@ func applyProdDevFlow(sv *Server, tenantUuidStr string, patches []flow_spec.Serv // - Base ingress configs // TOOD: Could return a struct if it becomes too heavy to manipulate the return values. func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTopology, map[string]resolved.ClusterTopology, map[string]templates.Template, []apitypes.ServiceConfig, []apitypes.IngressConfig, error) { - tenant, err := sv.db.GetOrCreateTenant(tenantUuidStr) + tenant, err := sv.db.GetTenant(tenantUuidStr) if err != nil { logrus.Errorf("an error occured while getting the tenant %s\n: '%v'", tenantUuidStr, err.Error()) return nil, nil, nil, nil, nil, err } + if tenant == nil { + return nil, nil, nil, nil, nil, fmt.Errorf("Cannot find tenant %s", tenantUuidStr) + } + var clusterTopology resolved.ClusterTopology err = json.Unmarshal(tenant.BaseClusterTopology, &clusterTopology) if err != nil { diff --git a/kontrol-service/database/tenant.go b/kontrol-service/database/tenant.go index 96573ae..f3b720d 100644 --- a/kontrol-service/database/tenant.go +++ b/kontrol-service/database/tenant.go @@ -41,3 +41,17 @@ func (db *Db) GetOrCreateTenant( return &tenant, nil } + +func (db *Db) GetTenant( + tenantId string, +) (*Tenant, error) { + var tenant Tenant + result := db.db.Where("tenant_id = ?", tenantId).First(&tenant) + if result.Error != nil { + if result.Error == gorm.ErrRecordNotFound { + return nil, nil + } + return nil, result.Error + } + return &tenant, nil +} diff --git a/kontrol-service/main.go b/kontrol-service/main.go index 7ab4f0e..25313e7 100644 --- a/kontrol-service/main.go +++ b/kontrol-service/main.go @@ -27,36 +27,37 @@ func main() { func startServer(isDevMode bool) { - var db *database.Db dbHostname := os.Getenv("DB_HOSTNAME") - if dbHostname != "" { - dbUsername := os.Getenv("DB_USERNAME") - dbPassword := os.Getenv("DB_PASSWORD") - dbName := os.Getenv("DB_NAME") - dbPort, err := strconv.Atoi(os.Getenv("DB_PORT")) - if err != nil { - logrus.Fatal("An error occurred parsing the DB port number", err) - } - dbConnectionInfo, err := database.NewDatabaseConnectionInfo( - dbUsername, - dbPassword, - dbHostname, - uint16(dbPort), - dbName, - ) - if err != nil { - logrus.Fatal("An error occurred creating a database connection configuration based on the input provided", err) - } - - db, err = database.NewDb(dbConnectionInfo) - if err != nil { - logrus.Fatal("An error occurred creating the db connection", err) - } - - err = db.Migrate() - if err != nil { - logrus.Fatal("An error occurred migrating the DB", err) - } + dbUsername := os.Getenv("DB_USERNAME") + dbPassword := os.Getenv("DB_PASSWORD") + dbName := os.Getenv("DB_NAME") + if dbHostname == "" || dbUsername == "" || dbPassword == "" || dbName == "" { + logrus.Fatal("One of the following environment variables is not set: DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_NAME") + } + dbPort, err := strconv.Atoi(os.Getenv("DB_PORT")) + if err != nil { + logrus.Fatal("An error occurred parsing the DB port number", err) + } + + dbConnectionInfo, err := database.NewDatabaseConnectionInfo( + dbUsername, + dbPassword, + dbHostname, + uint16(dbPort), + dbName, + ) + if err != nil { + logrus.Fatal("An error occurred creating a database connection configuration based on the input provided", err) + } + + db, err := database.NewDb(dbConnectionInfo) + if err != nil { + logrus.Fatal("An error occurred creating the db connection", err) + } + + err = db.Migrate() + if err != nil { + logrus.Fatal("An error occurred migrating the DB", err) } // Create a new Segment analytics client instance. From 3970965c11a821315dc79eb79730d6566ee1e1ba Mon Sep 17 00:00:00 2001 From: Skylar Date: Thu, 22 Aug 2024 15:32:10 -0700 Subject: [PATCH 4/7] feat: Templates UI part 4: delete and run templates (#24) * feat: dynamic modal contents * feat: delete and run modals * feat: complete modal implementation * chore: add storybook entries --- .../CreateFlowModal.stories.tsx | 18 ++++ .../src/components/CreateFlowModal/index.tsx | 81 ++++++++++++++++ .../DeleteTemplateModal.stories.tsx | 18 ++++ .../components/DeleteTemplateModal/index.tsx | 25 +++++ .../src/components/Input/TextInput.tsx | 14 ++- .../src/components/Modal/Modal.stories.tsx | 12 ++- .../src/components/Modal/index.tsx | 64 ++++++++++--- .../src/components/Sidebar/index.tsx | 2 +- .../src/components/TemplatesTable/Row.tsx | 55 ++++++----- .../TemplatesTable/TemplatesTable.stories.tsx | 20 +++- .../src/components/TemplatesTable/index.tsx | 5 + .../src/contexts/FlowsContext.tsx | 94 ------------------- kontrol-frontend/src/main.tsx | 5 +- 13 files changed, 267 insertions(+), 146 deletions(-) create mode 100644 kontrol-frontend/src/components/CreateFlowModal/CreateFlowModal.stories.tsx create mode 100644 kontrol-frontend/src/components/CreateFlowModal/index.tsx create mode 100644 kontrol-frontend/src/components/DeleteTemplateModal/DeleteTemplateModal.stories.tsx create mode 100644 kontrol-frontend/src/components/DeleteTemplateModal/index.tsx delete mode 100644 kontrol-frontend/src/contexts/FlowsContext.tsx diff --git a/kontrol-frontend/src/components/CreateFlowModal/CreateFlowModal.stories.tsx b/kontrol-frontend/src/components/CreateFlowModal/CreateFlowModal.stories.tsx new file mode 100644 index 0000000..9be5f9d --- /dev/null +++ b/kontrol-frontend/src/components/CreateFlowModal/CreateFlowModal.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Button } from "@chakra-ui/react"; + +import CreateFlowModal from "."; + +const meta: Meta = { + component: CreateFlowModal, +}; + +export default meta; +type Story = StoryObj; + +export const Example: Story = { + args: { + children: , + templateId: "example-123", + }, +}; diff --git a/kontrol-frontend/src/components/CreateFlowModal/index.tsx b/kontrol-frontend/src/components/CreateFlowModal/index.tsx new file mode 100644 index 0000000..b2fe78c --- /dev/null +++ b/kontrol-frontend/src/components/CreateFlowModal/index.tsx @@ -0,0 +1,81 @@ +import { Flex, Stack } from "@chakra-ui/react"; +import Modal from "@/components/Modal"; +import Input from "@/components/Input"; +import { ReactElement } from "react"; + +interface Props { + onConfirm: () => void; + children: ReactElement<{ onClick: () => void }>; + templateId: string; +} +const CreateFlowModal = ({ children, onConfirm, templateId }: Props) => { + return ( + + + + {}} + isDisabled + /> + {}} + /> + + + {}} + isDisabled + /> + {}} + /> + + + {}} + isDisabled + /> + {}} + /> + + + + ); +}; + +export default CreateFlowModal; diff --git a/kontrol-frontend/src/components/DeleteTemplateModal/DeleteTemplateModal.stories.tsx b/kontrol-frontend/src/components/DeleteTemplateModal/DeleteTemplateModal.stories.tsx new file mode 100644 index 0000000..cf50c36 --- /dev/null +++ b/kontrol-frontend/src/components/DeleteTemplateModal/DeleteTemplateModal.stories.tsx @@ -0,0 +1,18 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Button } from "@chakra-ui/react"; + +import DeleteTemplateModal from "."; + +const meta: Meta = { + component: DeleteTemplateModal, +}; + +export default meta; +type Story = StoryObj; + +export const Example: Story = { + args: { + children: , + templateId: "example-123", + }, +}; diff --git a/kontrol-frontend/src/components/DeleteTemplateModal/index.tsx b/kontrol-frontend/src/components/DeleteTemplateModal/index.tsx new file mode 100644 index 0000000..7ee0daf --- /dev/null +++ b/kontrol-frontend/src/components/DeleteTemplateModal/index.tsx @@ -0,0 +1,25 @@ +import Modal from "@/components/Modal"; +import { ReactElement } from "react"; + +interface Props { + onConfirm: () => void; + children: ReactElement<{ onClick: () => void }>; + templateId: string; +} + +const DeleteTemplateModal = ({ onConfirm, children, templateId }: Props) => { + return ( + + ); +}; + +export default DeleteTemplateModal; diff --git a/kontrol-frontend/src/components/Input/TextInput.tsx b/kontrol-frontend/src/components/Input/TextInput.tsx index c4fdf40..6a1a824 100644 --- a/kontrol-frontend/src/components/Input/TextInput.tsx +++ b/kontrol-frontend/src/components/Input/TextInput.tsx @@ -1,6 +1,6 @@ -import { Stack, Text, Input } from "@chakra-ui/react"; +import { Stack, Text, Input, InputProps } from "@chakra-ui/react"; -export interface Props { +export interface Props extends InputProps { id: string; label: string; placeholder?: string; @@ -8,7 +8,14 @@ export interface Props { onChange: (e: React.ChangeEvent) => void; } -const TextInput = ({ value, onChange, placeholder, id, label }: Props) => { +const TextInput = ({ + value, + onChange, + placeholder, + id, + label, + ...props +}: Props) => { return ( @@ -23,6 +30,7 @@ const TextInput = ({ value, onChange, placeholder, id, label }: Props) => { placeholder={placeholder} value={value} onChange={onChange} + {...props} /> ); diff --git a/kontrol-frontend/src/components/Modal/Modal.stories.tsx b/kontrol-frontend/src/components/Modal/Modal.stories.tsx index 6129f19..ade570e 100644 --- a/kontrol-frontend/src/components/Modal/Modal.stories.tsx +++ b/kontrol-frontend/src/components/Modal/Modal.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; +import { Button } from "@chakra-ui/react"; import Modal from "."; @@ -10,5 +11,14 @@ export default meta; type Story = StoryObj; export const Example: Story = { - args: {}, + args: { + header: "Delete this flow?", + bodyText: + "Are you sure you want to delete this flow? You cannot undo this action.", + onCancel: () => console.log("Cancelled"), + onCancelText: "Go back", + onConfirm: () => console.log("Confirmed"), + onConfirmText: "Delete Flow", + children: , + }, }; diff --git a/kontrol-frontend/src/components/Modal/index.tsx b/kontrol-frontend/src/components/Modal/index.tsx index 8147ad1..5dd29e4 100644 --- a/kontrol-frontend/src/components/Modal/index.tsx +++ b/kontrol-frontend/src/components/Modal/index.tsx @@ -10,35 +10,71 @@ import { Flex, ModalFooter, } from "@chakra-ui/react"; +import { cloneElement, ReactElement, ReactNode } from "react"; -const Modal = () => { +interface Props { + header: string; + bodyText?: string; + target: ReactElement<{ onClick: () => void }>; + children?: ReactNode; + onConfirm?: () => void; + onConfirmText?: string; + onCancel?: () => void; + onCancelText?: string; + wide?: boolean; +} + +const Modal = ({ + header, + bodyText, + children, + target, + onConfirm, + onConfirmText, + onCancel, + onCancelText, + wide, +}: Props) => { const { isOpen, onOpen, onClose } = useDisclosure(); return ( <> - - + {cloneElement(target, { onClick: onOpen })} - + - Delete this flow? + {header} - - Are you sure you want to delete this flow? -
- You cannot undo this action. -
+ {bodyText != null && {bodyText}} + {children}
- - diff --git a/kontrol-frontend/src/components/Sidebar/index.tsx b/kontrol-frontend/src/components/Sidebar/index.tsx index 8f616e9..85d7ba4 100644 --- a/kontrol-frontend/src/components/Sidebar/index.tsx +++ b/kontrol-frontend/src/components/Sidebar/index.tsx @@ -102,7 +102,7 @@ const Sidebar = () => { href="flows" isCollapsed={isSidebarCollapsed} > - Flows + Flow Templates void; + onDelete: (templateId: string) => void; } -const Row = ({ template, id, isExpanded, onExpandRow }: Props) => { - const { deleteExampleFlow } = useFlowsContext(); +const Row = ({ template, id, isExpanded, onExpandRow, onDelete }: Props) => { + const templateId = template["template-id"]; return (
- */} diff --git a/kontrol-frontend/src/components/TemplatesTable/TemplatesTable.stories.tsx b/kontrol-frontend/src/components/TemplatesTable/TemplatesTable.stories.tsx index 5b91911..ce5f015 100644 --- a/kontrol-frontend/src/components/TemplatesTable/TemplatesTable.stories.tsx +++ b/kontrol-frontend/src/components/TemplatesTable/TemplatesTable.stories.tsx @@ -10,5 +10,23 @@ export default meta; type Story = StoryObj; export const Example: Story = { - args: {}, + args: { + templates: [ + { + description: "asdfasdf", + name: "asdfasdf", + "template-id": "template-5nf8a4z5hv", + }, + { + description: "Cool", + name: "Hello demo", + "template-id": "template-dpotdpd9b6", + }, + { + description: "123123", + name: "123123", + "template-id": "template-s0muzww1lg", + }, + ], + }, }; diff --git a/kontrol-frontend/src/components/TemplatesTable/index.tsx b/kontrol-frontend/src/components/TemplatesTable/index.tsx index a9f8beb..26bef41 100644 --- a/kontrol-frontend/src/components/TemplatesTable/index.tsx +++ b/kontrol-frontend/src/components/TemplatesTable/index.tsx @@ -15,6 +15,10 @@ const FlowConfigurationTable = ({ templates }: Props) => { setExpandedRowId(rowId); }; + const handleDelete = (templateId: string) => { + console.log("DELETE TEMPLATE", templateId); + }; + return ( { id={t["template-id"]} isExpanded={expandedRowId === t["template-id"]} onExpandRow={handleExpandRow} + onDelete={handleDelete} /> ))} diff --git a/kontrol-frontend/src/contexts/FlowsContext.tsx b/kontrol-frontend/src/contexts/FlowsContext.tsx deleted file mode 100644 index 6139d55..0000000 --- a/kontrol-frontend/src/contexts/FlowsContext.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { createContext, useContext, useState, ReactNode } from "react"; - -type AccessMode = "empty-with-seed" | "empty" | "snapshot" | "proxy"; - -interface FlowConfiguration { - service: string; - image: string; - accessMode: AccessMode; - additionalFields?: Record; -} - -interface Flow { - id: string; - name: string; - configurations: FlowConfiguration[]; -} - -// Define the shape of your context -interface FlowsContextType { - createExampleFlow: () => void; - deleteExampleFlow: () => void; - flows: Flow[]; -} - -// Create the context with a default value -const FlowsContext = createContext(undefined); - -// Create a provider component -interface FlowsContextProviderProps { - children: ReactNode; -} - -const exampleFlow: Flow = { - id: crypto.randomUUID(), - name: "Early development flow", - configurations: [ - { - service: "awesome-kardinal-example", - image: "kurtosistech/awesome-kardinal-example", - accessMode: "empty-with-seed", - additionalFields: { - seedScriptUrl: - "https://github.com/kardinal/awesome-kardinal-example/tree/main/seed.sql", - }, - }, - { - service: "stripe", - image: "kurtosistech/stripe-proxy", - accessMode: "proxy", - }, - { - service: "postgres", - image: "kurtosistech/postgres-proxy", - accessMode: "proxy", - }, - ], -}; - -export const FlowsContextProvider = ({ - children, -}: FlowsContextProviderProps) => { - const [flows, setFlows] = useState([]); - - const createExampleFlow = () => { - setFlows((prevFlows) => [...prevFlows, exampleFlow]); - }; - - const deleteExampleFlow = () => { - setFlows([]); - }; - - return ( - - {children} - - ); -}; - -// Create a custom hook to use the context -export const useFlowsContext = (): FlowsContextType => { - const context = useContext(FlowsContext); - if (context === undefined) { - throw new Error( - "useFlowsContext must be used within a FlowsContextProvider", - ); - } - return context; -}; diff --git a/kontrol-frontend/src/main.tsx b/kontrol-frontend/src/main.tsx index 61d71d4..f923c38 100644 --- a/kontrol-frontend/src/main.tsx +++ b/kontrol-frontend/src/main.tsx @@ -15,7 +15,6 @@ import NotFound from "@/pages/NotFound"; import { ErrorBoundary } from "react-error-boundary"; import { NavigationContextProvider } from "@/contexts/NavigationContext"; -import { FlowsContextProvider } from "@/contexts/FlowsContext"; import { ApiContextProvider } from "@/contexts/ApiContext"; const router = createBrowserRouter([ @@ -73,9 +72,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render( - - - + From 93ff08aed00d06a51edec73b236f6b52c9b1bb4a Mon Sep 17 00:00:00 2001 From: leoporoli Date: Fri, 23 Aug 2024 14:26:01 -0300 Subject: [PATCH 5/7] feat: adding the cluster resources manifest endpoint (#23) * adding the cluster resources manifest endpoint * gomod2nix execution * swith the manifest endpoint from the manager api to cli api * ping dependencies from main branch * gomod2nix execution --- go.work.sum | 48 +++++++++- kontrol-service/api/server.go | 79 +++++++++++++++- kontrol-service/go.mod | 37 +++++--- kontrol-service/go.sum | 75 +++++++++------ kontrol-service/gomod2nix.toml | 168 +++++++++++++++++++++++---------- kontrol-service/types/k8s.go | 23 +++++ 6 files changed, 333 insertions(+), 97 deletions(-) diff --git a/go.work.sum b/go.work.sum index c30d86d..a613c81 100644 --- a/go.work.sum +++ b/go.work.sum @@ -25,6 +25,8 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= @@ -62,6 +64,10 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= @@ -75,6 +81,8 @@ github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+j github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= @@ -96,6 +104,10 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -129,6 +141,7 @@ github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA= github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= @@ -143,6 +156,8 @@ github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240814135254 github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240814135254-a0724da5a551/go.mod h1:lj6oLhpXgnc9ZaulV7jysgRaeZUDPK6XiM2TxpcGRqM= github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240814140453-975ebac24b93 h1:s5cXvxg52er5nMCy+9v9wR+4nv+CxHOzXwIf2q2vRA0= github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240814140453-975ebac24b93/go.mod h1:lj6oLhpXgnc9ZaulV7jysgRaeZUDPK6XiM2TxpcGRqM= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240819163834-75f64efda4b9 h1:sG3ZRzIVNMY/qrxgZjKlUDPTSBowwAdDXGhw0hbsoYU= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240819163834-75f64efda4b9/go.mod h1:lj6oLhpXgnc9ZaulV7jysgRaeZUDPK6XiM2TxpcGRqM= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= @@ -153,14 +168,22 @@ github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= @@ -178,6 +201,8 @@ github.com/segmentio/conf v1.2.0 h1:5OT9+6OyVHLsFLsiJa/2KlqiA1m7mpdUBlkB/qYTMts= github.com/segmentio/conf v1.2.0/go.mod h1:Y3B9O/PqqWqjyxyWWseyj/quPEtMu1zDp/kVbSWWaB0= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -191,18 +216,22 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9 github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA= github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -215,12 +244,16 @@ golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2 h1:IRJeR9r1pYWsHKTRe/IInb7lYvbBVIqOgsX/u0mbOWY= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= @@ -228,6 +261,8 @@ golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= @@ -243,6 +278,8 @@ google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDom google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs= @@ -259,13 +296,20 @@ k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70 h1:NGrVE502P0s0/1hudf8zjgwki1 k8s.io/gengo/v2 v2.0.0-20240228010128-51d4e06bde70/go.mod h1:VH3AT8AaQOqiGjMF9p0/IM1Dj+82ZwjfxUP1IxaHE+8= k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c= k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 h1:Q8Z7VlGhcJgBHJHYugJ/K/7iB8a2eSxCyxdVjJp+lLY= k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= nullprogram.com/x/optparse v1.0.0 h1:xGFgVi5ZaWOnYdac2foDT3vg0ZZC9ErXFV57mr4OHrI= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= sigs.k8s.io/controller-runtime v0.18.0 h1:Z7jKuX784TQSUL1TIyeuF7j8KXZ4RtSX0YgtjKcSTME= sigs.k8s.io/controller-runtime v0.18.0/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= sigs.k8s.io/controller-tools v0.15.0 h1:4dxdABXGDhIa68Fiwaif0vcu32xfwmgQ+w8p+5CxoAI= sigs.k8s.io/controller-tools v0.15.0/go.mod h1:8zUSS2T8Hx0APCNRhJWbS3CAQEbIxLa07khzh7pZmXM= +sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g= +sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0= +sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ= +sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= diff --git a/kontrol-service/api/server.go b/kontrol-service/api/server.go index b8849ca..58287a1 100644 --- a/kontrol-service/api/server.go +++ b/kontrol-service/api/server.go @@ -1,16 +1,18 @@ package api import ( + "bytes" "context" "encoding/json" "fmt" - api "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/server" apitypes "github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api/api/golang/types" managerapi "github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api/api/golang/server" managerapitypes "github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api/api/golang/types" + "github.com/kurtosis-tech/stacktrace" "github.com/samber/lo" "github.com/sirupsen/logrus" + "k8s.io/cli-runtime/pkg/printers" "kardinal.kontrol-service/database" "kardinal.kontrol-service/engine" "kardinal.kontrol-service/engine/flow" @@ -189,6 +191,80 @@ func (sv *Server) GetTenantUuidClusterResources(_ context.Context, request manag return managerapi.GetTenantUuidClusterResources200JSONResponse(managerAPIClusterResources), nil } +func (sv *Server) GetTenantUuidManifest(_ context.Context, request api.GetTenantUuidManifestRequestObject) (api.GetTenantUuidManifestResponseObject, error) { + + clusterTopology, allFlows, _, _, _, err := getTenantTopologies(sv, request.Uuid) + if err != nil { + return nil, nil + } + + if clusterTopology != nil { + namespaceName := clusterTopology.Namespace + if allFlows != nil { + finalTopology := flow.MergeClusterTopologies(*clusterTopology, lo.Values(allFlows)) + clusterResources := flow.RenderClusterResources(finalTopology, namespaceName) + + var yamlBuffer bytes.Buffer + yamlPrinter := printers.YAMLPrinter{} + + // Add namespace + newNamespace := types.NewNamespaceWithIstioEnabled(namespaceName) + + if err = yamlPrinter.PrintObj(newNamespace, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing the cluster topology namespace '%s' in the yaml buffer", namespaceName) + } + + for _, resource := range clusterResources.Deployments { + if err = yamlPrinter.PrintObj(&resource, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing deployment '%s' in the yaml buffer", resource.Name) + } + } + + for _, resource := range clusterResources.Services { + if err = yamlPrinter.PrintObj(&resource, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing service '%s' in the yaml buffer", resource.Name) + } + } + + for _, resource := range clusterResources.VirtualServices { + if err = yamlPrinter.PrintObj(&resource, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing virtual service '%s' in the yaml buffer", resource.Name) + } + } + + for _, resource := range clusterResources.DestinationRules { + if err = yamlPrinter.PrintObj(&resource, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing destination rule '%s' in the yaml buffer", resource.Name) + } + } + + for _, resource := range clusterResources.EnvoyFilters { + if err = yamlPrinter.PrintObj(&resource, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing envoy filter '%s' in the yaml buffer", resource.Name) + } + } + + for _, resource := range clusterResources.AuthorizationPolicies { + if err = yamlPrinter.PrintObj(&resource, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing authorization policy '%s' in the yaml buffer", resource.Name) + } + } + + if err := yamlPrinter.PrintObj(&clusterResources.Gateway, &yamlBuffer); err != nil { + return nil, stacktrace.Propagate(err, "an error occurred printing gateway '%s' in the yaml buffer", clusterResources.Gateway.Name) + } + + response := api.GetTenantUuidManifest200ApplicationxYamlResponse{ + Body: &yamlBuffer, + ContentLength: int64(yamlBuffer.Len()), + } + + return response, nil + } + } + return nil, nil +} + func (sv *Server) GetTenantUuidTemplates(ctx context.Context, request api.GetTenantUuidTemplatesRequestObject) (api.GetTenantUuidTemplatesResponseObject, error) { _, _, tenantTemplates, _, _, err := getTenantTopologies(sv, request.Uuid) if err != nil { @@ -419,6 +495,7 @@ func getTenantTopologies(sv *Server, tenantUuidStr string) (*resolved.ClusterTop } var clusterTopology resolved.ClusterTopology + //TODO fix it throws an error if tenant.BaseClusterTopology is nil, which is the case when there is no tenant saved in the dB yet err = json.Unmarshal(tenant.BaseClusterTopology, &clusterTopology) if err != nil { logrus.Errorf("An error occurred decoding the cluster topology for tenant '%v'", tenant.TenantId) diff --git a/kontrol-service/go.mod b/kontrol-service/go.mod index 6eeafa6..0c73c2d 100644 --- a/kontrol-service/go.mod +++ b/kontrol-service/go.mod @@ -7,8 +7,8 @@ toolchain go1.22.3 require ( github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/dominikbraun/graph v0.23.0 - github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240819163834-75f64efda4b9 - github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240819163834-75f64efda4b9 + github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240823131700-b4e7d7134bda + github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240823131700-b4e7d7134bda github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 github.com/labstack/echo/v4 v4.12.0 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 @@ -16,25 +16,28 @@ require ( github.com/segmentio/analytics-go/v3 v3.3.0 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.9.0 - google.golang.org/protobuf v1.34.1 + google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 - gorm.io/datatypes v1.2.1 + gorm.io/datatypes v1.2.0 gorm.io/driver/postgres v1.5.9 gorm.io/driver/sqlite v1.5.6 gorm.io/gorm v1.25.11 istio.io/api v1.22.1-0.20240524024004-b6815be0740d istio.io/client-go v1.22.1 - k8s.io/api v0.30.2 - k8s.io/apimachinery v0.30.2 + k8s.io/api v0.31.0 + k8s.io/apimachinery v0.31.0 + k8s.io/cli-runtime v0.31.0 ) require ( filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/getkin/kin-openapi v0.125.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect @@ -53,32 +56,36 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/labstack/gommon v0.4.2 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/oapi-codegen/runtime v1.1.1 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/segmentio/backo-go v1.0.0 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/crypto v0.23.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/crypto v0.24.0 // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/mysql v1.5.6 // indirect - k8s.io/klog/v2 v2.120.1 // indirect - k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 // indirect + k8s.io/client-go v0.31.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/kontrol-service/go.sum b/kontrol-service/go.sum index 359f22e..2090799 100644 --- a/kontrol-service/go.sum +++ b/kontrol-service/go.sum @@ -1,5 +1,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= @@ -8,15 +10,20 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dominikbraun/graph v0.23.0 h1:TdZB4pPqCLFxYhdyMFb1TBdFxp8XLcJfTTBQucVPgCo= github.com/dominikbraun/graph v0.23.0/go.mod h1:yOjYyogZLY1LSG9E33JWZJiq5k83Qy2C6POAuiViluc= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/getkin/kin-openapi v0.125.0 h1:jyQCyf2qXS1qvs2U00xQzkGCqYPhEhZDmSmVt65fXno= github.com/getkin/kin-openapi v0.125.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= @@ -70,16 +77,18 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240819163834-75f64efda4b9 h1:BcQDF3fHxJtcQ4xNHKYACUikWirqP56us93dLqg2gh4= -github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240819163834-75f64efda4b9/go.mod h1:Zlbpg7q5pTUaddoMN9zaraCNvvuD4KJNPPC8WyUF8DI= -github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240819163834-75f64efda4b9 h1:sG3ZRzIVNMY/qrxgZjKlUDPTSBowwAdDXGhw0hbsoYU= -github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240819163834-75f64efda4b9/go.mod h1:lj6oLhpXgnc9ZaulV7jysgRaeZUDPK6XiM2TxpcGRqM= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240823131700-b4e7d7134bda h1:lOK8sxDAeO23OwVKCCuSSxQf5LsZoXPy1IFHigi0aXU= +github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api v0.0.0-20240823131700-b4e7d7134bda/go.mod h1:yvON5b9BHp3yJ99+i+JUMGb985g3h6Eco+w9swS5rds= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240823131700-b4e7d7134bda h1:7mLaOF2HfGNKrSCXbz72yLE7YIN1eHg/qm4x42/i6dM= +github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api v0.0.0-20240823131700-b4e7d7134bda/go.mod h1:lj6oLhpXgnc9ZaulV7jysgRaeZUDPK6XiM2TxpcGRqM= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 h1:YQTATifMUwZEtZYb0LVA7DK2pj8s71iY8rzweuUQ5+g= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409/go.mod h1:y5weVs5d9wXXHcDA1awRxkIhhHC1xxYJN8a7aXnE6S8= github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -91,6 +100,8 @@ github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -102,8 +113,9 @@ github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmt github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= @@ -129,13 +141,15 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -144,8 +158,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -155,14 +169,15 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -175,8 +190,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -189,8 +204,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/datatypes v1.2.1 h1:r+g0bk4LPCW2v4+Ls7aeNgGme7JYdNDQ2VtvlNUfBh0= -gorm.io/datatypes v1.2.1/go.mod h1:hYK6OTb/1x+m96PgoZZq10UXJ6RvEBb9kRDQ2yyhzGs= +gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco= +gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04= gorm.io/driver/mysql v1.5.6 h1:Ld4mkIickM+EliaQZQx3uOJDJHtrd70MxAUqWqlx3Y8= gorm.io/driver/mysql v1.5.6/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8= @@ -206,14 +221,18 @@ istio.io/api v1.22.1-0.20240524024004-b6815be0740d h1:2GncSQ55NOr91NYPmi0jqhVM7z istio.io/api v1.22.1-0.20240524024004-b6815be0740d/go.mod h1:S3l8LWqNYS9yT+d4bH+jqzH2lMencPkW7SKM1Cu9EyM= istio.io/client-go v1.22.1 h1:78BUMxytD0muwpwHdcA9qTOTJXN0jib0mXmNLdXxj0c= istio.io/client-go v1.22.1/go.mod h1:Z2QE9uMt6tDVyrmiLfLVhutbqtfUkPJ7A5Uw/p6gNFo= -k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= -k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= -k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= -k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= -k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= +k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= +k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= +k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/cli-runtime v0.31.0 h1:V2Q1gj1u3/WfhD475HBQrIYsoryg/LrhhK4RwpN+DhA= +k8s.io/cli-runtime v0.31.0/go.mod h1:vg3H94wsubuvWfSmStDbekvbla5vFGC+zLWqcf+bGDw= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/kontrol-service/gomod2nix.toml b/kontrol-service/gomod2nix.toml index 3057bd4..46e81e1 100644 --- a/kontrol-service/gomod2nix.toml +++ b/kontrol-service/gomod2nix.toml @@ -4,6 +4,9 @@ schema = 3 [mod."filippo.io/edwards25519"] version = "v1.1.0" hash = "sha256-9ACANrgWZSd5HYPfDZHY8DVbPSC9LOMgy8deq3rDOoc=" + [mod."github.com/Azure/go-ansiterm"] + version = "v0.0.0-20210617225240-d185dfc1b5a1" + hash = "sha256-rOhb0GMLPdnh1302vaxFjO20fM69hCT29hQD1F1YpPg=" [mod."github.com/BurntSushi/toml"] version = "v1.3.2" hash = "sha256-FIwyH67KryRWI9Bk4R8s1zFP0IgKR4L66wNQJYQZLeg=" @@ -37,6 +40,9 @@ schema = 3 [mod."github.com/aymerick/douceur"] version = "v0.2.0" hash = "sha256-NiBX8EfOvLXNiK3pJaZX4N73YgfzdrzRXdiBFe3X3sE=" + [mod."github.com/blang/semver/v4"] + version = "v4.0.0" + hash = "sha256-dJC22MjnfT5WqJ7x7Tc3Bvpw9tFnBn9HqfWFiM57JVc=" [mod."github.com/bmatcuk/doublestar"] version = "v1.1.1" hash = "sha256-mcR+gZ11pja98RwW7eN6T6TwC07ujPmQ8CcyH45r//0=" @@ -52,9 +58,12 @@ schema = 3 [mod."github.com/chenzhuoyu/iasm"] version = "v0.9.0" hash = "sha256-xlZIAcRAD9dufk7JZfyKyiBzw6Gzfj4oKh2wbjKukQg=" + [mod."github.com/creack/pty"] + version = "v1.1.18" + hash = "sha256-xMpCnIDjIf1NpmuywaK6cRaYnQ4kXvXU5n57aQqY6S8=" [mod."github.com/davecgh/go-spew"] - version = "v1.1.1" - hash = "sha256-nhzSUrE1fCkN0+RL04N4h8jWmRFPPPWbCuDc7Ss0akI=" + version = "v1.1.2-0.20180830191138-d8f796af33cc" + hash = "sha256-fV9oI51xjHdOmEx6+dlq7Ku2Ag+m/bmbzPo6A4Y74qc=" [mod."github.com/dominikbraun/graph"] version = "v0.23.0" hash = "sha256-XKMKv/DdKUWbAOiTDLl+uMADOpkZ6UdVfDJMe+Ena18=" @@ -71,8 +80,8 @@ schema = 3 version = "v4.0.2" hash = "sha256-MQa2y64XpNPa3dKEerYJT5eFTrAk7flts9h2LG1QQQY=" [mod."github.com/fxamacker/cbor/v2"] - version = "v2.6.0" - hash = "sha256-8EMjmc2FYVb0OXuzU1FWkSqYEtJjYdIT2PWsChoiTyQ=" + version = "v2.7.0" + hash = "sha256-ln5ms4UxxQ563bZ2UaNLG/bNsmohlgK18K+UUOyZNA0=" [mod."github.com/gabriel-vasile/mimetype"] version = "v1.4.2" hash = "sha256-laV+IkgbnEG07h1eFfPISqp0ctnLXfzchz/CLR1lftk=" @@ -85,9 +94,12 @@ schema = 3 [mod."github.com/gin-gonic/gin"] version = "v1.9.1" hash = "sha256-3FHywH5QuhTeQcdF8v06jt9vIkH0ON6ydpMYciAc8xQ=" + [mod."github.com/go-errors/errors"] + version = "v1.4.2" + hash = "sha256-TkRLJlgaVlNxRD9c0ky+CN99tKL4Gx9W06H5a273gPM=" [mod."github.com/go-logr/logr"] - version = "v1.4.1" - hash = "sha256-WM4badoqxXlBmqCRrnmtNce63dLlr/FJav3BJSYHvaY=" + version = "v1.4.2" + hash = "sha256-/W6qGilFlZNTb9Uq48xGZ4IbsVeSwJiAMLw4wiNYHLI=" [mod."github.com/go-openapi/jsonpointer"] version = "v0.21.0" hash = "sha256-bB8XTzo4hzXemi8Ey3tIXia3mfn38bvwIzKYLJYC650=" @@ -109,9 +121,9 @@ schema = 3 [mod."github.com/go-sql-driver/mysql"] version = "v1.8.1" hash = "sha256-Vp/au38P1tf1jNTBW34rdb5mly0cde5IIXu+EMjDDUY=" - [mod."github.com/go-task/slim-sprig"] - version = "v0.0.0-20230315185526-52ccab3ef572" - hash = "sha256-D6NjCQbcYC53NdwzyAm4i9M1OjTJIVu4EIt3AD/Vxfg=" + [mod."github.com/go-task/slim-sprig/v3"] + version = "v3.0.0" + hash = "sha256-vCCw4MXVBm33VNLXcOBccVDD1CSnzDvDdWB6w5FN1cA=" [mod."github.com/go-test/deep"] version = "v1.0.8" hash = "sha256-AKOpW32qcq1BTVEPC6MshiFA3ROucnmlJMIfvwYXvNY=" @@ -130,6 +142,9 @@ schema = 3 [mod."github.com/golang-sql/sqlexp"] version = "v0.1.0" hash = "sha256-FhKWdt7vwzTbIsx2u+AzrKO1VFxTw/lbgD9/V5G76jw=" + [mod."github.com/golang/groupcache"] + version = "v0.0.0-20210331224755-41bb18bfe9da" + hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0=" [mod."github.com/golang/protobuf"] version = "v1.5.4" hash = "sha256-N3+Lv9lEZjrdOWdQhFj6Y3Iap4rVLEQeI8/eFFyAMZ0=" @@ -139,6 +154,9 @@ schema = 3 [mod."github.com/gomarkdown/markdown"] version = "v0.0.0-20230922112808-5421fefb8386" hash = "sha256-N3qjdMq0L4toiTu2rut9sSPR/cA7bEe/bZ1iEVNzXOE=" + [mod."github.com/google/btree"] + version = "v1.0.1" + hash = "sha256-1PIeFGgUL4BK/StL/D12pg9bEQ5HfMT/fMLdus4pZTs=" [mod."github.com/google/gnostic-models"] version = "v0.6.8" hash = "sha256-YzA/XpvPyfdplJtHmAUdQk9P+j0NBwHhW9nj1DaGaoQ=" @@ -149,8 +167,11 @@ schema = 3 version = "v1.2.0" hash = "sha256-T6Gz741l45L3F6Dt7fiAuQvQQg59Qtap3zG05M2cfqU=" [mod."github.com/google/pprof"] - version = "v0.0.0-20210720184732-4bb14d4b1be1" - hash = "sha256-m6l2Yay3iCu7Ses6nmwXifyztNqfP1B/MX81/tDK4Hw=" + version = "v0.0.0-20240525223248-4bfdf5a9a2af" + hash = "sha256-HqRtRspzvf5rDtr9PIrqVRyqVmWkiVp/1cwJmHPnDvY=" + [mod."github.com/google/shlex"] + version = "v0.0.0-20191202100458-e7afc7fbc510" + hash = "sha256-1f392pCmS7AXVKXIC1SvKlYtK/rvW47F5CCkGT2G6JM=" [mod."github.com/google/uuid"] version = "v1.6.0" hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw=" @@ -160,9 +181,18 @@ schema = 3 [mod."github.com/gorilla/mux"] version = "v1.8.1" hash = "sha256-nDABvAhlYgxUW2N/brrep7NkQXoSGcHhA+XI4+tK0F0=" + [mod."github.com/gorilla/websocket"] + version = "v1.5.0" + hash = "sha256-EYVgkSEMo4HaVrsWKqnsYRp8SSS8gNf7t+Elva02Ofc=" + [mod."github.com/gregjones/httpcache"] + version = "v0.0.0-20180305231024-9cad4c3443a7" + hash = "sha256-2ngFfFuSm8YSTNZWGQuN5yTpsXlwY2R8aaIzjDnjTXI=" [mod."github.com/imdario/mergo"] version = "v0.3.6" hash = "sha256-B4uSmAVWme2nDAqbW9XiwlEnCg7CAvewToNsji7yf9E=" + [mod."github.com/inconshreveable/mousetrap"] + version = "v1.1.0" + hash = "sha256-XWlYH0c8IcxAwQTnIi6WYqq44nOKUylSWxWO/vi+8pE=" [mod."github.com/invopop/yaml"] version = "v0.2.0" hash = "sha256-RxeDuvwOSWYaLc8Q7T39rfFT3bZX3g9Bu0RFwxH6sLw=" @@ -236,11 +266,11 @@ schema = 3 version = "v0.2.0" hash = "sha256-fadcWxZOORv44oak3jTxm6YcITcFxdGt4bpn869HxUE=" [mod."github.com/kurtosis-tech/kardinal/libs/cli-kontrol-api"] - version = "v0.0.0-20240819163834-75f64efda4b9" - hash = "sha256-3IjbpaLaWtj52ACSkheBIIryHRMffz6WU2TXSPh/ItY=" + version = "v0.0.0-20240823131700-b4e7d7134bda" + hash = "sha256-B6Vp8HQ5GSFstVkkSRll1c/9WJnSXtwAqSxLENdkoIE=" [mod."github.com/kurtosis-tech/kardinal/libs/manager-kontrol-api"] - version = "v0.0.0-20240819163834-75f64efda4b9" - hash = "sha256-Q1azNEVJegd1TAfACt9a9iVASqJbpUGsD5udq+DHtrI=" + version = "v0.0.0-20240823131700-b4e7d7134bda" + hash = "sha256-Y1vl6Cqpvc+b9+JPnajRGPeAXqA/XQEgcGBCXsiuTek=" [mod."github.com/kurtosis-tech/stacktrace"] version = "v0.0.0-20211028211901-1c67a77b5409" hash = "sha256-xm9l7tlCb0U25WJvByFikWxnAmOwTmOtlSDBdbyDMMY=" @@ -253,6 +283,9 @@ schema = 3 [mod."github.com/leodido/go-urn"] version = "v1.2.4" hash = "sha256-N2HO7ChScxI79KGvXI9LxoIlr+lkBNdDZP9OPGwPRK0=" + [mod."github.com/liggitt/tabwriter"] + version = "v0.0.0-20181228230101-89fcab3d43de" + hash = "sha256-b6pLitORwgfGpOHpe45ykj00P17utbDv8bv6MCVoCBM=" [mod."github.com/mailgun/raymond/v2"] version = "v2.0.48" hash = "sha256-HC2vbTL9eCgk1m00h6Mg6W/pu6n/Y7Qr4MJuVQIX4v0=" @@ -275,8 +308,11 @@ schema = 3 version = "v0.17.0" hash = "sha256-daMFlPIkRcfYqvL0erCp0CBPItGSRg7rTY2S7/cMjuw=" [mod."github.com/moby/spdystream"] - version = "v0.2.0" - hash = "sha256-Feme5UoWuBCvnLPKw1ozKkF3SM7PAjjPFQZ3TJhghR0=" + version = "v0.4.0" + hash = "sha256-SaJTp/3n8oqOgzRPzTbbQ1jqNA/Xmp+6wViRd935IwM=" + [mod."github.com/moby/term"] + version = "v0.5.0" + hash = "sha256-jy0kbkeUsr0KoiE33WLxNAgYXZIERKR2O5+saXBwdD8=" [mod."github.com/modern-go/concurrent"] version = "v0.0.0-20180306012644-bacd9c7ef1dd" hash = "sha256-OTySieAgPWR4oJnlohaFTeK1tRaVp/b0d1rYY8xKMzo=" @@ -286,6 +322,9 @@ schema = 3 [mod."github.com/mohae/deepcopy"] version = "v0.0.0-20170929034955-c48cc78d4826" hash = "sha256-TQMmKqIYwVhmMVh4RYQkAui97Eyj7poLmcAuDcHXsEk=" + [mod."github.com/monochromegane/go-gitignore"] + version = "v0.0.0-20200626010858-205db1a8cc00" + hash = "sha256-j1Mgb2TUUIiBcXB+slOkjtvcjmqSMEsG5RZYE7vGXOU=" [mod."github.com/munnerz/goautoneg"] version = "v0.0.0-20191010083416-a7dc8b61c822" hash = "sha256-79URDDFenmGc9JZu+5AXHToMrtTREHb3BC84b/gym9Q=" @@ -296,23 +335,26 @@ schema = 3 version = "v1.1.1" hash = "sha256-GRvzpQngQPAy59KvvcwhjYqjx4gttIhOtQKjqfQcNvI=" [mod."github.com/onsi/ginkgo/v2"] - version = "v2.15.0" - hash = "sha256-E+f2d0RZ6DSpdh4OasCbT1vGckXsziM3hFt4HkI5x1s=" + version = "v2.19.0" + hash = "sha256-el0o74ZgX/0wqCwK0zeFksv0Ja9lHKTgmCwuzQEWauo=" [mod."github.com/onsi/gomega"] - version = "v1.31.0" - hash = "sha256-a7Bmw1MpIgZNgWenBUEh/R/IpUFVUnDL4zaFznU0ILo=" + version = "v1.33.1" + hash = "sha256-oYfRaN1xqngIHQQxEEc+FQZ6UHC99VZQzAePT0Xkz8s=" [mod."github.com/pelletier/go-toml/v2"] version = "v2.0.9" hash = "sha256-mLpNBZOK72qPpForSmzQkDrqR5xzmpUdM/0XxB2AYFA=" [mod."github.com/perimeterx/marshmallow"] version = "v1.1.5" hash = "sha256-fFWjg0FNohDSV0/wUjQ8fBq1g8h6yIqTrHkxqL2Tt0s=" + [mod."github.com/peterbourgon/diskv"] + version = "v2.0.1+incompatible" + hash = "sha256-K4mEVjH0eyxyYHQRxdbmgJT0AJrfucUwGB2BplRRt9c=" [mod."github.com/pkg/errors"] version = "v0.9.1" hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw=" [mod."github.com/pmezard/go-difflib"] - version = "v1.0.0" - hash = "sha256-/FtmHnaGjdvEIKAJtrUfEhV7EVo5A/eYrtdnUkuxLDA=" + version = "v1.0.1-0.20181226105442-5d4384ee4fb2" + hash = "sha256-XA4Oj1gdmdV/F/+8kMI+DBxKPthZ768hbKsO3d9Gx90=" [mod."github.com/rogpeppe/go-internal"] version = "v1.12.0" hash = "sha256-qvDNCe3l84/LgrA8X4O15e1FeDcazyX91m9LmXGXX6M=" @@ -337,6 +379,9 @@ schema = 3 [mod."github.com/sirupsen/logrus"] version = "v1.8.1" hash = "sha256-vUIDlLXYBD74+JqdoSx+W3J6r5cOk63heo0ElsHizoM=" + [mod."github.com/spf13/cobra"] + version = "v1.8.1" + hash = "sha256-yDF6yAHycV1IZOrt3/hofR+QINe+B2yqkcIaVov3Ky8=" [mod."github.com/spf13/pflag"] version = "v1.0.5" hash = "sha256-w9LLYzxxP74WHT4ouBspH/iQZXjuAh2WQCHsuvyEjAw=" @@ -376,18 +421,27 @@ schema = 3 [mod."github.com/x448/float16"] version = "v0.8.4" hash = "sha256-VKzMTMS9pIB/cwe17xPftCSK9Mf4Y6EuBEJlB4by5mE=" + [mod."github.com/xlab/treeprint"] + version = "v1.2.0" + hash = "sha256-g85HyWGLZuD/TFXZzmXT+u9TA1xIT5escUVhnofsYQI=" [mod."github.com/yosssi/ace"] version = "v0.0.5" hash = "sha256-0HnNZUypGGoQxFX214/eF7RJ9KxYpb56Q5Rn2tryOLM=" [mod."github.com/yuin/goldmark"] version = "v1.2.1" hash = "sha256-vrL87IsRgYTTHvCH2fodVu+ECk9UCu4kuCy3Ypy2Oos=" + [mod."go.starlark.net"] + version = "v0.0.0-20230525235612-a134d8f9ddca" + hash = "sha256-lO0g2HMFn+ulv5r08coGIaxMdi5mTp1YNzl9nDraSjs=" + [mod."go.uber.org/goleak"] + version = "v1.3.0" + hash = "sha256-uuwtET8BZ4zjKgSV92DN47k/PM2zYdnWl+naP2CfO5M=" [mod."golang.org/x/arch"] version = "v0.4.0" hash = "sha256-jKi0m79VwPy8XxGh1e5YRZX5jfb2drWfmLWxNR3HvAU=" [mod."golang.org/x/crypto"] - version = "v0.23.0" - hash = "sha256-6hZjb/OazWFBef0C/aH63l49YQnzCh2vpIduzyfSSG8=" + version = "v0.24.0" + hash = "sha256-wpxJApwSmmn9meVdpFdOU0gzeJbIXcKuFfYUUVogSss=" [mod."golang.org/x/exp"] version = "v0.0.0-20240416160154-fe59bbe5cc7f" hash = "sha256-168CD9hlLJaQ7stQk/ztlP3zgaWXUMbIHa38gAeRRs4=" @@ -395,29 +449,29 @@ schema = 3 version = "v0.17.0" hash = "sha256-CLaPeF6uTFuRDv4oHwOQE6MCMvrzkUjWN3NuyywZjKU=" [mod."golang.org/x/net"] - version = "v0.25.0" - hash = "sha256-IjFfXLYNj27WLF7vpkZ6mfFXBnp+7QER3OQ0RgjxN54=" + version = "v0.26.0" + hash = "sha256-WfY33QERNbcIiDkH3+p2XGrAVqvWBQfc8neUt6TH6dQ=" [mod."golang.org/x/oauth2"] - version = "v0.10.0" - hash = "sha256-fKUwQ8HPEP4y6ZAtNHHHMDMYn2Fo6qTMcY45BbpE+Eg=" + version = "v0.21.0" + hash = "sha256-0xgi5k7fxMScMH+rDwXhDqe8raTFHh5ih727jGVS918=" [mod."golang.org/x/sync"] version = "v0.7.0" hash = "sha256-2ETllEu2GDWoOd/yMkOkLC2hWBpKzbVZ8LhjLu0d2A8=" [mod."golang.org/x/sys"] - version = "v0.20.0" - hash = "sha256-mowlaoG2k4n1c1rApWef5EMiXd3I77CsUi8jPh6pTYA=" + version = "v0.21.0" + hash = "sha256-gapzPWuEqY36V6W2YhIDYR49sEvjJRd7bSuf9K1f4JY=" [mod."golang.org/x/term"] - version = "v0.20.0" - hash = "sha256-kU+OVJbYktTIn4ZTAdomsOjL069Vj45sdroEMRKaRDI=" + version = "v0.21.0" + hash = "sha256-zRm7uPBM1+TJkODYHkk/BtN3la5QAaSgslE2hSTm27Y=" [mod."golang.org/x/text"] - version = "v0.15.0" - hash = "sha256-pBnj0AEkfkvZf+3bN7h6epCD2kurw59clDP7yWvxKlk=" + version = "v0.16.0" + hash = "sha256-hMTO45upjEuA4sJzGplJT+La2n3oAfHccfYWZuHcH+8=" [mod."golang.org/x/time"] version = "v0.5.0" hash = "sha256-W6RgwgdYTO3byIPOFxrP2IpAZdgaGowAaVfYby7AULU=" [mod."golang.org/x/tools"] - version = "v0.20.0" - hash = "sha256-g5T5FrNPO/cf2W1lc+/93FcFB3HftPjqI72FueD9Wt8=" + version = "v0.21.1-0.20240508182429-e35e4ccd0d2d" + hash = "sha256-KfnS+3fREPAWQUBoUedPupQp9yLrugxMmmEoHvyzKNE=" [mod."golang.org/x/xerrors"] version = "v0.0.0-20220411194840-2f41105eb62f" hash = "sha256-yZNeG+jcarcw/aOFhrhxWWE20r0P+/VJF4i/0JQfv1c=" @@ -434,11 +488,14 @@ schema = 3 version = "v1.62.1" hash = "sha256-1su6X0YT7MUflrTJijbq1CiisADZHudEx5sJq01TEaE=" [mod."google.golang.org/protobuf"] - version = "v1.34.1" - hash = "sha256-qnHqY6KLZiZDbTVTN6uzF4jedxROYlPCYHoiv6XI0sc=" + version = "v1.34.2" + hash = "sha256-nMTlrDEE2dbpWz50eQMPBQXCyQh4IdjrTIccaU0F3m0=" [mod."gopkg.in/check.v1"] version = "v1.0.0-20201130134442-10cb98267c6c" hash = "sha256-VlIpM2r/OD+kkyItn6vW35dyc0rtkJufA93rjFyzncs=" + [mod."gopkg.in/evanphx/json-patch.v4"] + version = "v4.12.0" + hash = "sha256-rUOokb3XW30ftpHp0fsF2WiJln1S0FSt2El7fTHq3CM=" [mod."gopkg.in/inf.v0"] version = "v0.9.1" hash = "sha256-z84XlyeWLcoYOvWLxPkPFgLkpjyb2Y4pdeGMyySOZQI=" @@ -452,8 +509,8 @@ schema = 3 version = "v3.0.1" hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU=" [mod."gorm.io/datatypes"] - version = "v1.2.1" - hash = "sha256-NMl32AlPlLBIoVFut3mF5e19flzyWiFPkpERW6FC9ag=" + version = "v1.2.0" + hash = "sha256-HtKC8GaVXMrKonledYFN3bCaTJ6YhC6CfrBPImem5lo=" [mod."gorm.io/driver/mysql"] version = "v1.5.6" hash = "sha256-eADqVVGImHD+N3CkffyJSVoPsZOFdi1l5ONGmGUyLpg=" @@ -476,26 +533,35 @@ schema = 3 version = "v1.22.1" hash = "sha256-yBen7y8xbvpgTzUYxEUOBqwkJGHfVjqxFUxKrxkHdls=" [mod."k8s.io/api"] - version = "v0.30.2" - hash = "sha256-sq8jdb0wnAIhTO/hactsJ34mRuUgEuUNOrKaQasbHpQ=" + version = "v0.31.0" + hash = "sha256-ObkU1VOM3tgfS3CetL71nxaagYLmpFWpQct2OLG6etg=" [mod."k8s.io/apimachinery"] - version = "v0.30.2" - hash = "sha256-EBWG9PlSfRwMed/u6oF8ME8n44/U5HGBCacH+Mns2UI=" + version = "v0.31.0" + hash = "sha256-yj8N0Y4OkmdiidrEq76ysqZoYyKTnB4WmfcZp4uR8gY=" + [mod."k8s.io/cli-runtime"] + version = "v0.31.0" + hash = "sha256-jhREJfP44j6UKGBHC8eFanKXTQwghWAV7XgDI4FBE0M=" [mod."k8s.io/client-go"] - version = "v0.29.0" - hash = "sha256-GuY06sFi5YaQ4h925hCgdzfIMUjTcKxupKP6h7RWI78=" + version = "v0.31.0" + hash = "sha256-lUFbTH7JKchPGfr83YXjoeBUIUTTCrzt8esTKRM0D1k=" [mod."k8s.io/klog/v2"] - version = "v2.120.1" - hash = "sha256-PU3q5ODCHEO8z//zUKsCq2tky6ZNx4xFl3nHSPJpuW8=" + version = "v2.130.1" + hash = "sha256-n5vls1o1a0V0KYv+3SULq4q3R2Is15K8iDHhFlsSH4o=" [mod."k8s.io/kube-openapi"] version = "v0.0.0-20240228011516-70dd3763d340" hash = "sha256-2BUbi2eNJFSTcmLyVYBYBe9Lhi0TVJoH2zVQlQ9eZIA=" [mod."k8s.io/utils"] - version = "v0.0.0-20240423183400-0849a56e8f22" - hash = "sha256-4CiDxKJMHKJ173hu3KsVBD4XdAfGZRMiHIFeqW3AwYs=" + version = "v0.0.0-20240711033017-18e509b52bc8" + hash = "sha256-asDLYotyW+oWIsCmiu9fLuLk77mAsKBkG6QnAbRsyoE=" [mod."sigs.k8s.io/json"] version = "v0.0.0-20221116044647-bc3834ca7abd" hash = "sha256-XDBMN2o450IHiAwEpBVsvo9e7tYZa+EXWrifUNTdNMU=" + [mod."sigs.k8s.io/kustomize/api"] + version = "v0.17.2" + hash = "sha256-N3iJRWt9hUoL6J9WPIZuie8L70FGImBDXy2QfQVJ3lU=" + [mod."sigs.k8s.io/kustomize/kyaml"] + version = "v0.17.1" + hash = "sha256-2uEboEJxxI8EITYO3E/JB2raQnZ7GMG9J4vwL+ILqjU=" [mod."sigs.k8s.io/structured-merge-diff/v4"] version = "v4.4.1" hash = "sha256-FcZHHZCKNNZW6/s1T1sKiS5Vj1TpHPmxVWr6YlL60xA=" diff --git a/kontrol-service/types/k8s.go b/kontrol-service/types/k8s.go index 834e3c8..ef138c6 100644 --- a/kontrol-service/types/k8s.go +++ b/kontrol-service/types/k8s.go @@ -5,6 +5,14 @@ import ( securityv1beta1 "istio.io/client-go/pkg/apis/security/v1beta1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + namespaceApiVersion = "v1" + namespaceKind = "Namespace" + istioLabel = "istio-injection" + enabledIstioValue = "enabled" ) type ClusterResources struct { @@ -16,3 +24,18 @@ type ClusterResources struct { EnvoyFilters []v1alpha3.EnvoyFilter `json:"envoy_filters"` AuthorizationPolicies []securityv1beta1.AuthorizationPolicy `json:"authorization_policies"` } + +func NewNamespaceWithIstioEnabled(namespaceName string) *corev1.Namespace { + return &corev1.Namespace{ + TypeMeta: metav1.TypeMeta{ + APIVersion: namespaceApiVersion, + Kind: namespaceKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: namespaceName, + Labels: map[string]string{ + istioLabel: enabledIstioValue, + }, + }, + } +} From bb7e3e36a9d6864e32b77a3588feea6293a08ea2 Mon Sep 17 00:00:00 2001 From: Skylar Date: Fri, 23 Aug 2024 14:00:42 -0700 Subject: [PATCH 6/7] feat: add build mode banner (#25) * feat: add build mode banner * fix: ts import --- .../src/components/Banner/Banner.stories.tsx | 14 ++++ .../src/components/Banner/index.tsx | 68 +++++++++++++++++++ .../src/components/Layout/index.tsx | 41 ++++++----- .../src/contexts/NavigationContext.tsx | 16 +++-- kontrol-frontend/src/pages/FlowsCreate.tsx | 2 +- kontrol-frontend/src/theme.ts | 1 + 6 files changed, 118 insertions(+), 24 deletions(-) create mode 100644 kontrol-frontend/src/components/Banner/Banner.stories.tsx create mode 100644 kontrol-frontend/src/components/Banner/index.tsx diff --git a/kontrol-frontend/src/components/Banner/Banner.stories.tsx b/kontrol-frontend/src/components/Banner/Banner.stories.tsx new file mode 100644 index 0000000..7488154 --- /dev/null +++ b/kontrol-frontend/src/components/Banner/Banner.stories.tsx @@ -0,0 +1,14 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import Banner from "."; + +const meta: Meta = { + component: Banner, +}; + +export default meta; +type Story = StoryObj; + +export const Example: Story = { + args: {}, +}; diff --git a/kontrol-frontend/src/components/Banner/index.tsx b/kontrol-frontend/src/components/Banner/index.tsx new file mode 100644 index 0000000..b509952 --- /dev/null +++ b/kontrol-frontend/src/components/Banner/index.tsx @@ -0,0 +1,68 @@ +import { useNavigationContext } from "@/contexts/NavigationContext"; +import { Box, Flex, Text, CloseButton } from "@chakra-ui/react"; + +const Banner = () => { + const { isBannerVisible, setIsBannerVisible } = useNavigationContext(); + + if (!isBannerVisible) { + return null; + } + + return ( + + + + + 🚧 + + + + WELCOME! KARDINAL IS STILL IN BUILD MODE + + + The features you see in the UI might differ from the CLI, we're + currently working towards feature parity.
If you have + comments or suggestions, please{" "} + + open a github issue + {" "} + or{" "} + + reach out via email + {" "} + and help us shape the product! +
+
+
+ { + setIsBannerVisible(false); + }} + color="orange.500" + /> +
+
+ ); +}; + +export default Banner; diff --git a/kontrol-frontend/src/components/Layout/index.tsx b/kontrol-frontend/src/components/Layout/index.tsx index c1e8728..5c72707 100644 --- a/kontrol-frontend/src/components/Layout/index.tsx +++ b/kontrol-frontend/src/components/Layout/index.tsx @@ -1,35 +1,40 @@ import { GridItem, Grid } from "@chakra-ui/react"; import { ReactNode } from "react"; +import Banner from "@/components/Banner"; interface Props { children: ReactNode[]; + showBanner?: boolean; } -const Layout = ({ children }: Props) => { +const Layout = ({ children, showBanner }: Props) => { return ( - + {showBanner && } + - {["title", "a", "b", "c", "d", "footer"].map((area, i) => ( - - {children[i]} - - ))} - + gridTemplateRows={"64px auto auto auto 40px"} + gridTemplateColumns={"1fr 1fr"} + h="100%" + rowGap={8} + columnGap={4} + color="blackAlpha.700" + fontWeight="bold" + > + {["title", "a", "b", "c", "d", "footer"].map((area, i) => ( + + {children[i]} + + ))} + + ); }; diff --git a/kontrol-frontend/src/contexts/NavigationContext.tsx b/kontrol-frontend/src/contexts/NavigationContext.tsx index 43964a9..d69e08e 100644 --- a/kontrol-frontend/src/contexts/NavigationContext.tsx +++ b/kontrol-frontend/src/contexts/NavigationContext.tsx @@ -1,16 +1,19 @@ import { createContext, useContext, useState, ReactNode } from "react"; -// Define the shape of your context interface NavigationContextType { - // Add your context properties here isSidebarCollapsed: boolean; setIsSidebarCollapsed: (c: boolean) => void; + isBannerVisible: boolean; + setIsBannerVisible: (c: boolean) => void; } // Create the context with a default value -const NavigationContext = createContext( - undefined, -); +const NavigationContext = createContext({ + isSidebarCollapsed: false, + setIsSidebarCollapsed: () => {}, + isBannerVisible: true, + setIsBannerVisible: () => {}, +}); // Create a provider component interface NavigationContextProviderProps { @@ -21,12 +24,15 @@ export const NavigationContextProvider = ({ children, }: NavigationContextProviderProps) => { const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false); + const [isBannerVisible, setIsBannerVisible] = useState(true); return ( {children} diff --git a/kontrol-frontend/src/pages/FlowsCreate.tsx b/kontrol-frontend/src/pages/FlowsCreate.tsx index 026195a..4f0983d 100644 --- a/kontrol-frontend/src/pages/FlowsCreate.tsx +++ b/kontrol-frontend/src/pages/FlowsCreate.tsx @@ -125,7 +125,7 @@ const Page = () => { const formIsValid = formState.name.length > 0 && formState.service.length > 0; return ( - + Update traffic control and data isolation details below diff --git a/kontrol-frontend/src/theme.ts b/kontrol-frontend/src/theme.ts index 9a0db8c..3e37a5b 100644 --- a/kontrol-frontend/src/theme.ts +++ b/kontrol-frontend/src/theme.ts @@ -23,6 +23,7 @@ export const colorOverrides: Record> = { }, orange: { "500": "#FF602C", + "100": "#FCA0610D", }, blue: { "50": "#F6FAFF", From 8cc0fe030b839bdb1b3b52c5c587454ea9f922ab Mon Sep 17 00:00:00 2001 From: Edgar Gomes Date: Fri, 23 Aug 2024 18:20:42 -0300 Subject: [PATCH 7/7] chore(main): release 0.1.19 (#16) --- CHANGELOG.md | 18 ++++++++++++++++++ version.txt | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f127811..3c95c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## [0.1.19](https://github.com/kurtosis-tech/kardinal-kontrol/compare/0.1.18...0.1.19) (2024-08-23) + + +### Features + +* add build mode banner ([#25](https://github.com/kurtosis-tech/kardinal-kontrol/issues/25)) ([bb7e3e3](https://github.com/kurtosis-tech/kardinal-kontrol/commit/bb7e3e36a9d6864e32b77a3588feea6293a08ea2)) +* adding the cluster resources manifest endpoint ([#23](https://github.com/kurtosis-tech/kardinal-kontrol/issues/23)) ([93ff08a](https://github.com/kurtosis-tech/kardinal-kontrol/commit/93ff08aed00d06a51edec73b236f6b52c9b1bb4a)) +* Frontend for templates creation part 2 ([#13](https://github.com/kurtosis-tech/kardinal-kontrol/issues/13)) ([7a4e678](https://github.com/kurtosis-tech/kardinal-kontrol/commit/7a4e67806f16f48c45122dd610192bec5c62a2eb)) +* Templates UI part 3 ([#18](https://github.com/kurtosis-tech/kardinal-kontrol/issues/18)) ([daeb553](https://github.com/kurtosis-tech/kardinal-kontrol/commit/daeb5538b92e7f657d1365b321228f12acdeb973)) +* Templates UI part 4: delete and run templates ([#24](https://github.com/kurtosis-tech/kardinal-kontrol/issues/24)) ([3970965](https://github.com/kurtosis-tech/kardinal-kontrol/commit/3970965c11a821315dc79eb79730d6566ee1e1ba)) + + +### Bug Fixes + +* DB env vars validation + Tenant create only on deploy ([#19](https://github.com/kurtosis-tech/kardinal-kontrol/issues/19)) ([882fb95](https://github.com/kurtosis-tech/kardinal-kontrol/commit/882fb95f6cdf080f9b871e9c0e7fe64e54fdff8e)) +* disable arm64 builds in ci temporarily ([#15](https://github.com/kurtosis-tech/kardinal-kontrol/issues/15)) ([59aa3ba](https://github.com/kurtosis-tech/kardinal-kontrol/commit/59aa3ba6d7c7d0f56f2333d8c6d63b5fb9917971)) +* re-enable sandbox ([#17](https://github.com/kurtosis-tech/kardinal-kontrol/issues/17)) ([fac285f](https://github.com/kurtosis-tech/kardinal-kontrol/commit/fac285fccc5f5c98483fe7356535026ee63b7c81)) + ## [0.1.18](https://github.com/kurtosis-tech/kardinal-kontrol/compare/0.1.17...0.1.18) (2024-08-21) diff --git a/version.txt b/version.txt index f8bc4c6..d8a023e 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.1.18 +0.1.19
@@ -72,10 +74,10 @@ const Row = ({ template, id, isExpanded, onExpandRow }: Props) => { expandedContent={ <> - Base image tag + Services - RC-1.0.0 + TODO } @@ -91,37 +93,34 @@ const Row = ({ template, id, isExpanded, onExpandRow }: Props) => { Status - Running + Not running } > - {template["template-id"]} + {templateId} - {/* - - - - Stripe - - - Amazon RDS - - - - } aria-label="Play" variant="ghost" /> + onDelete(templateId)} + templateId={templateId} + > + } aria-label="Play" variant="ghost" /> + } aria-label="Edit" variant="ghost" /> - } - color={"red"} - aria-label="Delete" - variant="ghost" - onClick={() => deleteExampleFlow()} - /> + onDelete(templateId)} + templateId={templateId} + > + } + color={"red"} + aria-label="Delete" + variant="ghost" + /> +