diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 69e09a9..ce2fcab 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: echo "REPO=theliv" >> $GITHUB_ENV echo "using ${{ env.VERSION }} as the release version" - name: Login to GitHub Container Registry - if: github.event_name == 'push' + if: github.event_name == 'pull_request' uses: docker/login-action@v2 with: registry: ${{ env.REGISTRY }} @@ -41,5 +41,5 @@ jobs: with: context: . file: ./build/Dockerfile - push: ${{ github.event_name == 'push' }} + push: ${{ github.event_name == 'pull_request' }} tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} diff --git a/go.mod b/go.mod index 6ffc51c..3609ba3 100644 --- a/go.mod +++ b/go.mod @@ -1,20 +1,22 @@ module github.com/fidelity/theliv -go 1.17 +go 1.20 require ( - github.com/aws/aws-sdk-go-v2 v1.21.0 - github.com/aws/aws-sdk-go-v2/credentials v1.13.40 - github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.16.0 - github.com/go-chi/chi/v5 v5.0.10 + github.com/aws/aws-sdk-go-v2 v1.25.0 + github.com/aws/aws-sdk-go-v2/credentials v1.17.1 + github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.20.2 + github.com/go-chi/chi/v5 v5.0.12 github.com/go-chi/render v1.0.3 github.com/go-ldap/ldap/v3 v3.4.6 - github.com/prometheus/client_golang v1.17.0 - github.com/prometheus/common v0.44.0 + github.com/go-resty/resty/v2 v2.11.0 + github.com/prometheus/client_golang v1.18.0 + github.com/prometheus/common v0.45.0 + github.com/sashabaranov/go-openai v1.19.4 github.com/stretchr/testify v1.8.4 github.com/wangli1030/saml v0.4.7 go.etcd.io/etcd/client/v3 v3.5.9 - go.uber.org/zap v1.26.0 + go.uber.org/zap v1.27.0 k8s.io/api v0.27.4 k8s.io/apimachinery v0.27.4 k8s.io/client-go v0.27.4 @@ -34,9 +36,9 @@ require ( require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/ajg/form v1.5.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect - github.com/aws/smithy-go v1.14.2 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 // indirect + github.com/aws/smithy-go v1.20.0 // indirect github.com/beevik/etree v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -53,35 +55,35 @@ require ( github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.5.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/russellhaering/goxmldsig v1.1.1 // indirect github.com/spf13/pflag v1.0.5 // indirect go.etcd.io/etcd/api/v3 v3.5.9 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/oauth2 v0.8.0 // indirect - golang.org/x/sys v0.12.0 // indirect - golang.org/x/term v0.12.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/crypto v0.17.0 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect - google.golang.org/grpc v1.53.0 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/grpc v1.56.3 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index e7e30b9..cf748db 100644 --- a/go.sum +++ b/go.sum @@ -6,23 +6,18 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc= -github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= -github.com/aws/aws-sdk-go-v2/credentials v1.13.40 h1:s8yOkDh+5b1jUDhMBtngF6zKWLDs84chUk2Vk0c38Og= -github.com/aws/aws-sdk-go-v2/credentials v1.13.40/go.mod h1:VtEHVAAqDWASwdOqj/1huyT6uHbs5s8FUHfDQdky/Rs= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= -github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.16.0 h1:IyOnIqfZCieDU/QXUTZ4K1wNgFQo0n8sKQvuYtl1E3Q= -github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.16.0/go.mod h1:Lh/6ABs1m80bEB36fAW9gEPW5kSsAr7Mdn8dGyWRLp0= -github.com/aws/aws-sdk-go-v2/service/sso v1.14.1/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= -github.com/aws/aws-sdk-go-v2/service/sts v1.22.0/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= -github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= -github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/aws-sdk-go-v2 v1.25.0 h1:sv7+1JVJxOu/dD/sz/csHX7jFqmP001TIY7aytBWDSQ= +github.com/aws/aws-sdk-go-v2 v1.25.0/go.mod h1:G104G1Aho5WqF+SR3mDIobTABQzpYV0WxMsKxlMggOA= +github.com/aws/aws-sdk-go-v2/credentials v1.17.1 h1:H4WlK2OnVotRmbVgS8Ww2Z4B3/dDHxDS7cW6EiCECN4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.1/go.mod h1:qTfT/OIE9RAVirZDq0PcEYOOM4Pkmf1Hrk1iInKRS4k= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0 h1:NPs/EqVO+ajwOoq56EfcGKa3L3ruWuazkIw1BqxwOPw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.0/go.mod h1:D+duLy2ylgatV+yTlQ8JTuLfDD0BnFvnQRc+o6tbZ4M= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0 h1:ks7KGMVUMoDzcxNWUlEdI+/lokMFD136EL6DWmUOV80= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.0/go.mod h1:hL6BWM/d/qz113fVitZjbXR0E+RCTU1+x+1Idyn5NgE= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.20.2 h1:TAKRHjyAtRMUeqsPnjzI4EXz3WtIo3IXRhJiIPa4MFo= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.20.2/go.mod h1:BRuiq4shgrokCvNWSXVHz1hhH5sNSLW0ZruTV0jiNMQ= +github.com/aws/smithy-go v1.20.0 h1:6+kZsCXZwKxZS9RfISnPc4EXlHoyAkm2hPuM8X2BrrQ= +github.com/aws/smithy-go v1.20.0/go.mod h1:uo5RKksAl4PzhqaAbjd4rLgFoq5koTsQKYuGe7dklGc= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -54,8 +49,8 @@ github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNy github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= -github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s= +github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= @@ -70,6 +65,8 @@ github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTr github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= +github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -96,19 +93,17 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= @@ -133,8 +128,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= 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= @@ -152,21 +147,23 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/russellhaering/goxmldsig v1.1.0/go.mod h1:QK8GhXPB3+AfuCrfo0oRISa9NfzeCpWmxeGnqEpDF9o= github.com/russellhaering/goxmldsig v1.1.1 h1:vI0r2osGF1A9PLvsGdPUAGwEIrKa4Pj5sesSBsebIxM= github.com/russellhaering/goxmldsig v1.1.1/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= +github.com/sashabaranov/go-openai v1.19.4 h1:GbaDiqvgYCabyqzuIbcEeT6/ZX1nVfur+++oTBfOgks= +github.com/sashabaranov/go-openai v1.19.4/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= @@ -194,18 +191,20 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2I go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 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.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -226,14 +225,15 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= -golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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= @@ -249,22 +249,27 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -290,13 +295,13 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= +google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/investigators/common.go b/internal/investigators/common.go index d2edd69..9bbc1a4 100644 --- a/internal/investigators/common.go +++ b/internal/investigators/common.go @@ -8,6 +8,7 @@ package investigators import ( "bytes" "context" + "fmt" "regexp" "strings" "sync" @@ -16,6 +17,7 @@ import ( "go.uber.org/zap" + "github.com/fidelity/theliv/pkg/ai" log "github.com/fidelity/theliv/pkg/log" "github.com/fidelity/theliv/pkg/observability" v1 "k8s.io/api/core/v1" @@ -154,3 +156,34 @@ func appendSolution(problem *problem.Problem, solutions interface{}, commands in } } } + +func callAiKnowledge(ctx context.Context, wg *sync.WaitGroup, problem *problem.Problem, + input *problem.DetectorCreationInput, prompt string) { + defer wg.Done() + knowledge, err := input.AiClient.GetCompletion(ctx, fmt.Sprintf(ai.KnowledgePrompt, prompt)) + if err != nil { + return + } + problem.AiKnowledge.Append(strings.Split(knowledge, "\n\n")...) +} + +func callAiSuggestion(ctx context.Context, wg *sync.WaitGroup, problem *problem.Problem, + input *problem.DetectorCreationInput, prompt string) { + defer wg.Done() + suggestions, err := input.AiClient.GetCompletion(ctx, fmt.Sprintf(ai.DefaultPrompt, prompt)) + if err != nil { + return + } + problem.AiSuggestions.Append(strings.Split(suggestions, "\n")...) +} + +func getAiResults(ctx context.Context, problem *problem.Problem, + input *problem.DetectorCreationInput, issue string, knowledge string) { + var wg sync.WaitGroup + t1 := time.Now() + wg.Add(2) + go callAiSuggestion(ctx, &wg, problem, input, issue) + go callAiKnowledge(ctx, &wg, problem, input, knowledge) + wg.Wait() + log.SWithContext(ctx).Infof("Calling OpenAi for %v.", time.Since(t1)) +} diff --git a/internal/investigators/pod_pending_investigator.go b/internal/investigators/pod_pending_investigator.go index e03cdc4..14e83b5 100644 --- a/internal/investigators/pod_pending_investigator.go +++ b/internal/investigators/pod_pending_investigator.go @@ -122,6 +122,7 @@ func PodNotRunningInvestigator(ctx context.Context, wg *sync.WaitGroup, problem } else { solutions, commands = getPendingPodUnknownSolution(ctx, pod) } + getAiResults(ctx, problem, input, "PodFailedScheduled, "+failSchedule, "PodFailedScheduled") } else if len(failMount) > 0 { commands = appendSeq(commands, GetSolutionsByTemplate(ctx, KubeDescribePoCmd, pod, true)[0]) commands = appendSeq(commands, GetSolutionsByTemplate(ctx, GetEventsCmd, pod, true)[0]) diff --git a/internal/problem/aggregate.go b/internal/problem/aggregate.go index 6692068..08b8817 100644 --- a/internal/problem/aggregate.go +++ b/internal/problem/aggregate.go @@ -152,6 +152,8 @@ func getReportCardResource(ctx context.Context, p *Problem, resource ResourceDet cr := createReportCardResource(ctx, p, resource.Resource.(metav1.Object), resource.ResourceKind) cr.Issue.Solutions = append(cr.Issue.Solutions, p.SolutionDetails.GetStore()...) cr.Issue.Commands = append(cr.Issue.Commands, p.UsefulCommands.GetStore()...) + cr.Issue.AiKnowledge = append(cr.Issue.AiKnowledge, p.AiKnowledge.GetStore()...) + cr.Issue.AiSuggestions = append(cr.Issue.AiSuggestions, p.AiSuggestions.GetStore()...) // cr.Issue.Documents = urlToStr(p.Docs) // if resource.Deeplink != nil { diff --git a/internal/problem/input.go b/internal/problem/input.go index 2e1b1a4..4fa3046 100644 --- a/internal/problem/input.go +++ b/internal/problem/input.go @@ -9,6 +9,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/fidelity/theliv/pkg/ai" "github.com/fidelity/theliv/pkg/kubeclient" "github.com/fidelity/theliv/pkg/observability" "k8s.io/client-go/rest" @@ -28,4 +29,5 @@ type DetectorCreationInput struct { AwsConfig aws.Config KubeClient *kubeclient.KubeClient EventRetriever observability.EventRetriever + AiClient ai.AzureAIClient } diff --git a/internal/problem/problem.go b/internal/problem/problem.go index 8f245bb..91bdcee 100644 --- a/internal/problem/problem.go +++ b/internal/problem/problem.go @@ -39,7 +39,9 @@ type Problem struct { CauseLevel int SolutionDetails *common.LockedSlice // output field after detetor. It contains solutions details to show in UI. UsefulCommands *common.LockedSlice // output field after detetor. It contains solutions details to show in UI. - AffectedResources ResourceDetails // output field after detetor. It contains the resources affected by this problem that to show in UI. + AiSuggestions *common.LockedSlice + AiKnowledge *common.LockedSlice + AffectedResources ResourceDetails // output field after detetor. It contains the resources affected by this problem that to show in UI. } type ResourceDetails struct { diff --git a/internal/problem/types.go b/internal/problem/types.go index e64a089..ac37625 100644 --- a/internal/problem/types.go +++ b/internal/problem/types.go @@ -15,13 +15,15 @@ type ReportCard struct { } type ReportCardIssue struct { - Name string `json:"name"` - Description string `json:"description"` - Solutions []string `json:"solutions,omitempty"` - Commands []string `json:"commands,omitempty"` - CreatedTime string `json:"createdTime,omitempty"` - Tags map[string]string `json:"tags,omitempty"` - DomainName DomainName `json:"domainName,omitempty"` + Name string `json:"name"` + Description string `json:"description"` + Solutions []string `json:"solutions,omitempty"` + Commands []string `json:"commands,omitempty"` + AiSuggestions []string + AiKnowledge []string + CreatedTime string `json:"createdTime,omitempty"` + Tags map[string]string `json:"tags,omitempty"` + DomainName DomainName `json:"domainName,omitempty"` // Documents []string `json:"documents,omitempty"` CauseLevel int `json:"causelevel,omitempty"` } diff --git a/main.go b/main.go index 2a0314e..9635071 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "net/http" "strings" + "github.com/fidelity/theliv/pkg/ai" "github.com/fidelity/theliv/pkg/auth/samlmethod" "github.com/fidelity/theliv/pkg/config" log "github.com/fidelity/theliv/pkg/log" @@ -43,6 +44,7 @@ func main() { conf.LoadConfigs() samlmethod.Init() + ai.Init() r := router.NewRouter() diff --git a/pkg/ai/azureopenai.go b/pkg/ai/azureopenai.go new file mode 100644 index 0000000..e5af1a0 --- /dev/null +++ b/pkg/ai/azureopenai.go @@ -0,0 +1,129 @@ +/* + * Copyright FMR LLC + * + * SPDX-License-Identifier: Apache + */ +package ai + +import ( + "context" + "errors" + "net/http" + "time" + + "github.com/fidelity/theliv/pkg/config" + rest "github.com/fidelity/theliv/pkg/http" + log "github.com/fidelity/theliv/pkg/log" + openai "github.com/sashabaranov/go-openai" +) + +const ( + azureAIClientName = "azureopenai" +) + +type AzureAIClient struct { + nopCloser + client *openai.Client + model string + temperature float32 +} + +type Token struct { + TokenType string `json:"token_type,omitempty"` + Scope string `json:"scope,omitempty"` + AccessToken string `json:"access_token,omitempty"` + ExpiresIn int `json:"expires_in,omitempty"` + ExtExpiresIn int `json:"ext_expires_in,omitempty"` + Create time.Time +} + +var AzureConfig config.AzureConfig +var AiConfig config.AiConfig +var cachedToken Token + +func (c *AzureAIClient) Configure(config IAIConfig) error { + token := config.GetPassword() + baseURL := config.GetBaseURL() + engine := config.GetEngine() + defaultConfig := openai.DefaultAzureConfig(token, baseURL) + + defaultConfig.AzureModelMapperFunc = func(model string) string { + azureModelMapping := map[string]string{ + model: engine, + } + return azureModelMapping[model] + } + defaultConfig.APIType = openai.APIType(AiConfig.ApiType) + defaultConfig.APIVersion = AiConfig.ApiVersion + + client := openai.NewClientWithConfig(defaultConfig) + if client == nil { + return errors.New("error creating Azure OpenAI client") + } + c.client = client + c.model = config.GetModel() + c.temperature = config.GetTemperature() + return nil +} + +func (c *AzureAIClient) GetCompletion(ctx context.Context, prompt string) (string, error) { + // Create a completion request + resp, err := c.client.CreateChatCompletion(ctx, openai.ChatCompletionRequest{ + Model: c.model, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleUser, + Content: prompt, + }, + }, + Temperature: c.temperature, + }) + if err != nil { + log.SWithContext(ctx).Errorf("Failed to get openai response, error is %s.", err) + return "", err + } + return resp.Choices[0].Message.Content, nil +} + +func (c *AzureAIClient) GetName() string { + return azureAIClientName +} + +func GetToken(ctx context.Context) (Token, error) { + if cachedToken.AccessToken != "" && + time.Now().Before( + cachedToken.Create.Add(time.Duration(cachedToken.ExpiresIn)*time.Second)) { + return cachedToken, nil + } else { + return RefreshToken(ctx) + } +} + +func RefreshToken(ctx context.Context) (Token, error) { + var token Token + + req := rest.NewRetryReq(10, 2, 10, 30) + resp, err := req. + SetFormData(map[string]string{ + "client_id": AzureConfig.ClientID, + "scope": AzureConfig.Scope, + "username": AzureConfig.UserName, + "password": AzureConfig.Password, + "grant_type": AzureConfig.GrantType, + }). + SetResult(&token). + Post(AzureConfig.Endpoint) + + if err != nil || resp.StatusCode() != http.StatusOK { + log.SWithContext(ctx).Errorf("Failed to get token, error is %s.", err) + return cachedToken, err + } + token.Create = time.Now().Add(time.Second * 120) + cachedToken = token + return cachedToken, nil +} + +func Init() { + AiConfig = *config.GetThelivConfig().Ai + AzureConfig = *config.GetThelivConfig().Azure +} diff --git a/pkg/ai/iai.go b/pkg/ai/iai.go new file mode 100644 index 0000000..dd2cc0a --- /dev/null +++ b/pkg/ai/iai.go @@ -0,0 +1,81 @@ +/* + * Copyright FMR LLC + * + * SPDX-License-Identifier: Apache + */ +package ai + +import ( + "context" +) + +type IAI interface { + Configure(config IAIConfig) error + GetCompletion(ctx context.Context, prompt string) (string, error) + GetName() string + Close() +} + +type nopCloser struct{} + +func (nopCloser) Close() {} + +type IAIConfig interface { + GetPassword() string + GetModel() string + GetBaseURL() string + GetEndpointName() string + GetEngine() string + GetTemperature() float32 + GetProviderRegion() string + GetTopP() float32 + GetMaxTokens() int +} + +type AIProvider struct { + Name string + Model string + Password string + BaseURL string + EndpointName string + Engine string + Temperature float32 + ProviderRegion string + TopP float32 + MaxTokens int +} + +func (p *AIProvider) GetBaseURL() string { + return p.BaseURL +} + +func (p *AIProvider) GetEndpointName() string { + return p.EndpointName +} + +func (p *AIProvider) GetTopP() float32 { + return p.TopP +} + +func (p *AIProvider) GetMaxTokens() int { + return p.MaxTokens +} + +func (p *AIProvider) GetPassword() string { + return p.Password +} + +func (p *AIProvider) GetModel() string { + return p.Model +} + +func (p *AIProvider) GetEngine() string { + return p.Engine +} +func (p *AIProvider) GetTemperature() float32 { + return p.Temperature +} + +func (p *AIProvider) GetProviderRegion() string { + return p.ProviderRegion +} diff --git a/pkg/ai/prompts.go b/pkg/ai/prompts.go new file mode 100644 index 0000000..2743756 --- /dev/null +++ b/pkg/ai/prompts.go @@ -0,0 +1,15 @@ +/* + * Copyright FMR LLC + * + * SPDX-License-Identifier: Apache + */ +package ai + +const ( + DefaultPrompt = `Simplify the following Kubernetes error message delimited by triple dashes written in English language; --- %s ---. + Provide the most possible solution in a step by step style in no more than 560 characters. Write the output in the following format: + Error: {Explain error here} + Solution: {Step by step solution here} + ` + KnowledgePrompt = "In kubernetes, what can cause %s?" +) diff --git a/pkg/config/config.go b/pkg/config/config.go index 0dcbb5c..661c447 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -61,11 +61,13 @@ type ThelivConfig struct { Auth *AuthConfig `json:"auth,omitempty"` Prometheus *PrometheusConfig `json:"prometheus,omitempty"` ProblemLevel *ProblemLevelConfig `json:"problemlevel,omitempty"` - Ldap *LdapConfig - LogDriver LogDriverType `json:"logDriver,omitempty"` - EventDriver LogDriverType `json:"eventDriver,omitempty"` - LogDeeplinkDriver LogDriverType `json:"logDeeplinkDriver,omitempty"` - EventDeeplinkDriver LogDriverType `json:"eventDeeplinkDriver,omitempty"` + Ldap *LdapConfig `json:"ldap,omitempty"` + Azure *AzureConfig `json:"azure,omitempty"` + Ai *AiConfig `json:"ai,omitempty"` + LogDriver LogDriverType `json:"logDriver,omitempty"` + EventDriver LogDriverType `json:"eventDriver,omitempty"` + LogDeeplinkDriver LogDriverType `json:"logDeeplinkDriver,omitempty"` + EventDeeplinkDriver LogDriverType `json:"eventDeeplinkDriver,omitempty"` // Only for UI usage EmailAddr string `json:"emailAddr,omitempty"` DevelopedByTeam string `json:"developedByTeam,omitempty"` @@ -73,6 +75,29 @@ type ThelivConfig struct { TeamName string `json:"teamName,omitempty"` } +type AzureConfig struct { + Endpoint string `json:"endpoint,omitempty"` + ClientID string `json:"clientid,omitempty"` + Scope string `json:"scope,omitempty"` + UserName string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + GrantType string `json:"granttype,omitempty"` +} + +type AiConfig struct { + Name string `json:"name,omitempty"` + Model string `json:"model,omitempty"` + ApiType string `json:"apitype,omitempty"` + ApiVersion string `json:"apiversion,omitempty"` + BaseURL string `json:"baseurl,omitempty"` + EndpointName string `json:"endpointname,omitempty"` + Engine string `json:"engine,omitempty"` + Temperature float32 `json:"temperature,omitempty"` + ProviderRegion string `json:"providerregion,omitempty"` + TopP float32 `json:"topp,omitempty"` + MaxTokens int `json:"maxtokens,omitempty"` +} + func (c *ThelivConfig) ToMaskString() string { return fmt.Sprintf("TheliBasicConfig: Port: %v\n", c.Port) } diff --git a/pkg/config/etcd.go b/pkg/config/etcd.go index 6f7ea2d..ef8657c 100644 --- a/pkg/config/etcd.go +++ b/pkg/config/etcd.go @@ -50,6 +50,14 @@ func (ecl *EtcdConfigLoader) LoadConfigs() { if err := ecl.loadLdapConfig(); err != nil { log.S().Errorf("Failed to load ldap config, error is %v\n", err) } + + if err := ecl.loadAzureConfig(); err != nil { + log.S().Errorf("Failed to load azure config, error is %v\n", err) + } + + if err := ecl.loadAiConfig(); err != nil { + log.S().Errorf("Failed to load ai config, error is %v\n", err) + } } func (ecl *EtcdConfigLoader) GetKubernetesConfig(ctx context.Context, name string) (*KubernetesCluster, error) { @@ -186,3 +194,25 @@ func (ecl *EtcdConfigLoader) loadLdapConfig() error { log.S().Infof("Successfully load ldap config") return nil } + +func (ecl *EtcdConfigLoader) loadAzureConfig() error { + conf := &AzureConfig{} + err := driver.GetObjectWithSub(context.Background(), driver.AZURE_CONFIG_KEY, conf) + if err != nil { + return err + } + thelivConfig.Azure = conf + log.S().Infof("Successfully load azure config") + return nil +} + +func (ecl *EtcdConfigLoader) loadAiConfig() error { + conf := &AiConfig{} + err := driver.GetObjectWithSub(context.Background(), driver.AI_CONFIG_KEY, conf) + if err != nil { + return err + } + thelivConfig.Ai = conf + log.S().Infof("Successfully load Ai config") + return nil +} diff --git a/pkg/database/etcd/client.go b/pkg/database/etcd/client.go index d146296..401b64d 100644 --- a/pkg/database/etcd/client.go +++ b/pkg/database/etcd/client.go @@ -34,6 +34,8 @@ const ( PROMETHEUS_GLOBAL_CONFIG_KEY string = "/theliv/config/prometheus" THELIV_LEVEL_CONFIG_KEY string = "/theliv/config/levelconf" LDAP_CONFIG_KEY string = "/theliv/config/ldap" + AZURE_CONFIG_KEY string = "/theliv/config/azure" + AI_CONFIG_KEY string = "/theliv/config/ai" ) // Init client config, could be called only once, before any other functions diff --git a/pkg/http/http.go b/pkg/http/http.go new file mode 100644 index 0000000..61edbe7 --- /dev/null +++ b/pkg/http/http.go @@ -0,0 +1,28 @@ +/* + * Copyright FMR LLC + * + * SPDX-License-Identifier: Apache + */ +package http + +import ( + "time" + + resty "github.com/go-resty/resty/v2" +) + +func NewRetryClient(timeOut int, retryCount int, waitTime int, totalWaitTime int) *resty.Client { + return newClient(timeOut). + SetRetryCount(retryCount). + SetRetryWaitTime(time.Duration(waitTime) * time.Second). + SetRetryMaxWaitTime(time.Duration(totalWaitTime) * time.Second) +} + +func NewRetryReq(timeOut int, retryCount int, waitTime int, totalWaitTime int) *resty.Request { + return NewRetryClient(timeOut, retryCount, waitTime, totalWaitTime). + R() +} + +func newClient(timeout int) *resty.Client { + return resty.New().SetTimeout(time.Second * time.Duration(timeout)) +} diff --git a/pkg/router/ai.go b/pkg/router/ai.go new file mode 100644 index 0000000..cecce16 --- /dev/null +++ b/pkg/router/ai.go @@ -0,0 +1,38 @@ +/* + * Copyright FMR LLC + * + * SPDX-License-Identifier: Apache + */ +package router + +import ( + "net/http" + + "github.com/fidelity/theliv/pkg/service" + "github.com/go-chi/chi/v5" + "github.com/go-chi/render" +) + +type Prompt struct { + Prompt string `json:"prompt,omitempty"` +} + +func Ai(r chi.Router) { + r.Post("/", completion) +} + +func completion(w http.ResponseWriter, r *http.Request) { + + var prompt Prompt + + if err := decodeBody(r.Body, &prompt); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + resp, err := service.Completion(r.Context(), prompt.Prompt) + if err != nil { + processError(w, r, err) + } else if empty := processEmpty(w, r, resp); !empty { + render.Respond(w, r, resp) + } +} diff --git a/pkg/router/router.go b/pkg/router/router.go index e9ae153..1a7a7c9 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -76,6 +76,9 @@ func Route(r chi.Router) { // config for UI r.Route("/configinfo", ConfigInfo) + // export ai + r.Route("/ai", Ai) + // export prometheus metrics r.Handle("/metrics", promhttp.Handler()) diff --git a/pkg/service/ai.go b/pkg/service/ai.go new file mode 100644 index 0000000..1686820 --- /dev/null +++ b/pkg/service/ai.go @@ -0,0 +1,38 @@ +/* + * Copyright FMR LLC + * + * SPDX-License-Identifier: Apache + */ +package service + +import ( + "context" + + "github.com/fidelity/theliv/pkg/ai" +) + +func Completion(ctx context.Context, prompt string) (interface{}, error) { + token, err := ai.GetToken(ctx) + if err != nil { + return nil, err + } + aiConfig := GetAiConfig(token.AccessToken) + var azClient = ai.AzureAIClient{} + azClient.Configure(&aiConfig) + return azClient.GetCompletion(ctx, prompt) +} + +func GetAiConfig(token string) ai.AIProvider { + return ai.AIProvider{ + Name: ai.AiConfig.Name, + Model: ai.AiConfig.Model, + Password: token, + BaseURL: ai.AiConfig.BaseURL, + EndpointName: ai.AiConfig.EndpointName, + Engine: ai.AiConfig.Engine, + Temperature: ai.AiConfig.Temperature, + ProviderRegion: ai.AiConfig.ProviderRegion, + TopP: ai.AiConfig.TopP, + MaxTokens: ai.AiConfig.MaxTokens, + } +} diff --git a/pkg/service/detector.go b/pkg/service/detector.go index d41dc06..ca7bbdd 100644 --- a/pkg/service/detector.go +++ b/pkg/service/detector.go @@ -13,6 +13,7 @@ import ( "github.com/fidelity/theliv/internal/investigators" in "github.com/fidelity/theliv/internal/investigators" "github.com/fidelity/theliv/internal/problem" + "github.com/fidelity/theliv/pkg/ai" "github.com/fidelity/theliv/pkg/common" com "github.com/fidelity/theliv/pkg/common" "github.com/fidelity/theliv/pkg/config" @@ -72,6 +73,15 @@ func DetectAlerts(ctx context.Context) (interface{}, error) { eventRetriever := k8s.NewK8sEventRetriever(client) input.EventRetriever = eventRetriever + token, err := ai.GetToken(ctx) + if err != nil { + return nil, err + } + aiConfig := GetAiConfig(token.AccessToken) + var azClient = ai.AzureAIClient{} + azClient.Configure(&aiConfig) + input.AiClient = azClient + alerts, err := prometheus.GetAlerts(ctx, input) if err != nil { return nil, theErr.NewCommonError(ctx, 6, com.PrometheusNotAvailable+contact) @@ -121,6 +131,8 @@ func buildProblemsFromAlerts(alerts []v1.Alert) []*problem.Problem { CauseLevel: 0, SolutionDetails: common.InitLockedSlice(), UsefulCommands: common.InitLockedSlice(), + AiSuggestions: common.InitLockedSlice(), + AiKnowledge: common.InitLockedSlice(), AffectedResources: problem.ResourceDetails{}, } p.Name = string(alert.Labels[model.LabelName("alertname")]) diff --git a/website/src/app/components/resource-group-content/resource-group-content.component.html b/website/src/app/components/resource-group-content/resource-group-content.component.html index d39d66d..6ccd9d5 100644 --- a/website/src/app/components/resource-group-content/resource-group-content.component.html +++ b/website/src/app/components/resource-group-content/resource-group-content.component.html @@ -169,6 +169,24 @@

{{popupResource}}.yaml
  • {{solution}}
  • +
    +
    + AI Suggestions: +
    +

    No AI Suggestions

    +
      +
    • {{solution}}
    • +
    +
    +
    +
    + AI knowledge: +
    +

    No AI knowledge

    +
      +
    • {{solution}}
    • +
    +
    Useful Commands: diff --git a/website/src/app/components/resource-group-content/resource-group-content.component.scss b/website/src/app/components/resource-group-content/resource-group-content.component.scss index 24486c5..10a9810 100644 --- a/website/src/app/components/resource-group-content/resource-group-content.component.scss +++ b/website/src/app/components/resource-group-content/resource-group-content.component.scss @@ -361,6 +361,38 @@ li { // flex-shrink: 0; // } } + &-suggestion { + div { + font-weight: 600; + color: var(--alter); + } + li { + white-space: pre-line; + list-style: none; + color: var(--subtitle-color); + margin-top: -0.5em; + } + p { + margin-top: 0.2em; + margin-bottom: 1.2em; + } + } + &-knowledge { + div { + font-weight: 600; + color: var(--color-summary-3-highlight); + } + li { + white-space: pre-line; + list-style: none; + color: var(--subtitle-color); + margin-top: -0.5em; + } + p { + margin-top: 0.2em; + margin-bottom: 1.2em; + } + } &-commands { div { font-weight: 600; diff --git a/website/src/app/components/resource-group-content/resource-group-content.component.ts b/website/src/app/components/resource-group-content/resource-group-content.component.ts index df734ef..b2c61f4 100644 --- a/website/src/app/components/resource-group-content/resource-group-content.component.ts +++ b/website/src/app/components/resource-group-content/resource-group-content.component.ts @@ -5,7 +5,7 @@ */ import { Component, OnInit } from '@angular/core'; import { faExclamationTriangle, faLightbulb, faTimes, faThumbsUp, faExternalLinkAlt, - faClipboard, faShareAlt, faCopy, faDownload, faBookReader, faArrowLeft, faEdit } from '@fortawesome/free-solid-svg-icons'; + faClipboard, faShareAlt, faCopy, faDownload, faBookReader, faArrowLeft, faEdit, faEnvelope, faComment } from '@fortawesome/free-solid-svg-icons'; import { ActivatedRoute } from '@angular/router'; import { KubernetesService } from 'src/app/services/kubernetes.service'; import { SocialUtil } from '../../shared/util/social-util'; @@ -42,6 +42,8 @@ export class ResourceGroupContentComponent implements OnInit { faClipboard = faClipboard; faBookReader = faBookReader; faArrowLeft = faArrowLeft; + faEnvelope = faEnvelope; + faComment = faComment; ns: any; cluster: any;