mirror of
https://github.com/k8sgpt-ai/k8sgpt.git
synced 2026-03-19 03:23:47 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a236cc4f28 | ||
|
|
6eac58d4b0 | ||
|
|
2994c1c5a7 | ||
|
|
fa4a0757b8 | ||
|
|
49e120c28e |
@@ -1 +1 @@
|
||||
{".":"0.3.4"}
|
||||
{".":"0.3.5"}
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## [0.3.5](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.4...v0.3.5) (2023-05-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add configuration api route ([#459](https://github.com/k8sgpt-ai/k8sgpt/issues/459)) ([fa4a075](https://github.com/k8sgpt-ai/k8sgpt/commit/fa4a0757b83f8ec00df951d49316f10961daa0e0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.267 ([#451](https://github.com/k8sgpt-ai/k8sgpt/issues/451)) ([49e120c](https://github.com/k8sgpt-ai/k8sgpt/commit/49e120c28e8b5ce5a8f7255ebc0f1b1b5c423f95))
|
||||
* **deps:** update module github.com/aws/aws-sdk-go to v1.44.269 ([#458](https://github.com/k8sgpt-ai/k8sgpt/issues/458)) ([2994c1c](https://github.com/k8sgpt-ai/k8sgpt/commit/2994c1c5a77ce6ebe6e59d6edc9647c02f06f261))
|
||||
* updated list.go to handle k8sgpt cache list crashing issue ([#455](https://github.com/k8sgpt-ai/k8sgpt/issues/455)) ([6eac58d](https://github.com/k8sgpt-ai/k8sgpt/commit/6eac58d4b03169356d3f06674ef206472e149fde))
|
||||
|
||||
## [0.3.4](https://github.com/k8sgpt-ai/k8sgpt/compare/v0.3.3...v0.3.4) (2023-05-22)
|
||||
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -34,7 +34,7 @@ brew install k8sgpt
|
||||
**32 bit:**
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.4/k8sgpt_386.rpm
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.5/k8sgpt_386.rpm
|
||||
sudo rpm -ivh k8sgpt_386.rpm
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -43,7 +43,7 @@ brew install k8sgpt
|
||||
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.4/k8sgpt_amd64.rpm
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.5/k8sgpt_amd64.rpm
|
||||
sudo rpm -ivh -i k8sgpt_amd64.rpm
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -55,7 +55,7 @@ brew install k8sgpt
|
||||
**32 bit:**
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.4/k8sgpt_386.deb
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.5/k8sgpt_386.deb
|
||||
sudo dpkg -i k8sgpt_386.deb
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -63,7 +63,7 @@ brew install k8sgpt
|
||||
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.4/k8sgpt_amd64.deb
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.5/k8sgpt_amd64.deb
|
||||
sudo dpkg -i k8sgpt_amd64.deb
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
@@ -76,14 +76,14 @@ brew install k8sgpt
|
||||
**32 bit:**
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.4/k8sgpt_386.apk
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.5/k8sgpt_386.apk
|
||||
apk add k8sgpt_386.apk
|
||||
```
|
||||
<!---x-release-please-end-->
|
||||
**64 bit:**
|
||||
<!---x-release-please-start-version-->
|
||||
```
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.4/k8sgpt_amd64.apk
|
||||
curl -LO https://github.com/k8sgpt-ai/k8sgpt/releases/download/v0.3.5/k8sgpt_amd64.apk
|
||||
apk add k8sgpt_amd64.apk
|
||||
```
|
||||
<!---x-release-please-end-->x
|
||||
|
||||
20
cmd/cache/add.go
vendored
20
cmd/cache/add.go
vendored
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -37,24 +36,7 @@ var addCmd = &cobra.Command{
|
||||
- S3`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(color.YellowString("Adding remote S3 based cache"))
|
||||
|
||||
// Check to see whether there is cache information already
|
||||
var cacheInfo cache.CacheProvider
|
||||
err := viper.UnmarshalKey("cache", &cacheInfo)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if cacheInfo.BucketName != "" {
|
||||
color.Yellow("Error: a cache is already configured, please remove it first")
|
||||
os.Exit(1)
|
||||
}
|
||||
cacheInfo.BucketName = bucketname
|
||||
cacheInfo.Region = region
|
||||
|
||||
// Save the cache information
|
||||
viper.Set("cache", cacheInfo)
|
||||
err = viper.WriteConfig()
|
||||
err := cache.AddRemoteCache(bucketname, region)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
|
||||
4
cmd/cache/list.go
vendored
4
cmd/cache/list.go
vendored
@@ -39,8 +39,10 @@ var listCmd = &cobra.Command{
|
||||
// list the contents of the cache
|
||||
names, err := c.List()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
println(name)
|
||||
}
|
||||
|
||||
19
cmd/cache/remove.go
vendored
19
cmd/cache/remove.go
vendored
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// removeCmd represents the remove command
|
||||
@@ -30,27 +29,11 @@ var removeCmd = &cobra.Command{
|
||||
Long: `This command allows you to remove the remote cache and use the default filecache.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
// Remove the remote cache
|
||||
var cacheInfo cache.CacheProvider
|
||||
err := viper.UnmarshalKey("cache", &cacheInfo)
|
||||
err := cache.RemoveRemoteCache(bucketname)
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if cacheInfo.BucketName == "" {
|
||||
color.Yellow("Error: no cache is configured")
|
||||
os.Exit(1)
|
||||
}
|
||||
// Warn user this will delete the S3 bucket and prompt them to continue
|
||||
color.Yellow("Warning: this will not delete the S3 bucket %s", cacheInfo.BucketName)
|
||||
cacheInfo = cache.CacheProvider{}
|
||||
viper.Set("cache", cacheInfo)
|
||||
err = viper.WriteConfig()
|
||||
if err != nil {
|
||||
color.Red("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
color.Green("Successfully removed the remote cache")
|
||||
},
|
||||
}
|
||||
|
||||
6
go.mod
6
go.mod
@@ -24,9 +24,9 @@ require (
|
||||
require github.com/adrg/xdg v0.4.0
|
||||
|
||||
require (
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230515081240-6b5b845c638e.1
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230514071713-3d78cb8bbc06.1
|
||||
github.com/aws/aws-sdk-go v1.44.266
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230524215339-41d88e13ab7e.1
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230524215339-41d88e13ab7e.1
|
||||
github.com/aws/aws-sdk-go v1.44.269
|
||||
)
|
||||
|
||||
require github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
|
||||
14
go.sum
14
go.sum
@@ -1,8 +1,8 @@
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230515081240-6b5b845c638e.1 h1:u8CQODmTW0EYjXKt0ZSbA/FGuOkA+zRNicNCs97Ud/A=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230515081240-6b5b845c638e.1/go.mod h1:EB1h/5OvQWTeT9JJ2x0NLaboeFOOm3fqkYWKp5ojO7o=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230515081240-6b5b845c638e.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230514071713-3d78cb8bbc06.1 h1:V43+hDZXo4WaGqGZjNfaL8ZcAEvhusckIC/JBD/msz0=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230514071713-3d78cb8bbc06.1/go.mod h1:karV92RruD5davytOQq20lDyAqBnai8ajNolo98nu94=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230524215339-41d88e13ab7e.1 h1:lvzkvTlk64ZKgqBlyI6wTkRcOCRwERbgvNNC739L2uw=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go v1.3.0-20230524215339-41d88e13ab7e.1/go.mod h1:gVjoI6SASls1kiAjJWFIYrT6midpN8pAT82q2EEVbGY=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.28.1-20230524215339-41d88e13ab7e.4/go.mod h1:i/s4ALHwKvjA1oGNKpoHg0FpEOTbufoOm/NdTE6YQAE=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230524215339-41d88e13ab7e.1 h1:Mx0Z+cXHStOU4lkemYYGhvNd40aU9g52sfS2W7D/gzA=
|
||||
buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go v1.30.0-20230524215339-41d88e13ab7e.1/go.mod h1:karV92RruD5davytOQq20lDyAqBnai8ajNolo98nu94=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
@@ -450,8 +450,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
||||
github.com/aws/aws-sdk-go v1.44.266 h1:MWd775dcYf7NrwgcHLtlsIbWoWkX8p4vomfNHr88zH0=
|
||||
github.com/aws/aws-sdk-go v1.44.266/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.269 h1:NUNq++KMjhWUVVUIx7HYLgBpX16bWfTY1EdQRraLALo=
|
||||
github.com/aws/aws-sdk-go v1.44.269/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
|
||||
42
pkg/cache/cache.go
vendored
42
pkg/cache/cache.go
vendored
@@ -1,6 +1,8 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
@@ -39,3 +41,43 @@ func RemoteCacheEnabled() (bool, error) {
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func AddRemoteCache(bucketName string, region string) error {
|
||||
var cacheInfo CacheProvider
|
||||
err := viper.UnmarshalKey("cache", &cacheInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cacheInfo.BucketName != "" {
|
||||
return errors.New("Error: a cache is already configured, please remove it first")
|
||||
}
|
||||
cacheInfo.BucketName = bucketName
|
||||
cacheInfo.Region = region
|
||||
viper.Set("cache", cacheInfo)
|
||||
err = viper.WriteConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveRemoteCache(bucketName string) error {
|
||||
var cacheInfo CacheProvider
|
||||
err := viper.UnmarshalKey("cache", &cacheInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cacheInfo.BucketName == "" {
|
||||
return errors.New("Error: no cache is configured")
|
||||
}
|
||||
|
||||
cacheInfo = CacheProvider{}
|
||||
viper.Set("cache", cacheInfo)
|
||||
err = viper.WriteConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
60
pkg/server/analyze.go
Normal file
60
pkg/server/analyze.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
json "encoding/json"
|
||||
|
||||
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
|
||||
)
|
||||
|
||||
func (h *handler) Analyze(ctx context.Context, i *schemav1.AnalyzeRequest) (
|
||||
*schemav1.AnalyzeResponse,
|
||||
error,
|
||||
) {
|
||||
if i.Output == "" {
|
||||
i.Output = "json"
|
||||
}
|
||||
|
||||
if i.Backend == "" {
|
||||
i.Backend = "openai"
|
||||
}
|
||||
|
||||
if int(i.MaxConcurrency) == 0 {
|
||||
i.MaxConcurrency = 10
|
||||
}
|
||||
|
||||
config, err := analysis.NewAnalysis(
|
||||
i.Backend,
|
||||
i.Language,
|
||||
i.Filters,
|
||||
i.Namespace,
|
||||
i.Nocache,
|
||||
i.Explain,
|
||||
int(i.MaxConcurrency),
|
||||
)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
config.RunAnalysis()
|
||||
|
||||
if i.Explain {
|
||||
err := config.GetAIResults(i.Output, i.Anonymize)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
}
|
||||
|
||||
out, err := config.PrintOutput(i.Output)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
var obj schemav1.AnalyzeResponse
|
||||
|
||||
err = json.Unmarshal(out, &obj)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
}
|
||||
37
pkg/server/config.go
Normal file
37
pkg/server/config.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/cache"
|
||||
)
|
||||
|
||||
func (h *handler) AddConfig(ctx context.Context, i *schemav1.AddConfigRequest) (*schemav1.AddConfigResponse, error,
|
||||
) {
|
||||
if i.Cache.BucketName == "" || i.Cache.Region == "" {
|
||||
return nil, errors.New("BucketName & Region are required")
|
||||
}
|
||||
|
||||
err := cache.AddRemoteCache(i.Cache.BucketName, i.Cache.Region)
|
||||
if err != nil {
|
||||
return &schemav1.AddConfigResponse{}, err
|
||||
}
|
||||
|
||||
return &schemav1.AddConfigResponse{
|
||||
Status: "Configuration updated.",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *handler) RemoveConfig(ctx context.Context, i *schemav1.RemoveConfigRequest) (*schemav1.RemoveConfigResponse, error,
|
||||
) {
|
||||
err := cache.RemoveRemoteCache(i.Cache.BucketName)
|
||||
if err != nil {
|
||||
return &schemav1.RemoveConfigResponse{}, err
|
||||
}
|
||||
|
||||
return &schemav1.RemoveConfigResponse{
|
||||
Status: "Successfully removed the remote cache",
|
||||
}, nil
|
||||
}
|
||||
@@ -1,65 +1,9 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
json "encoding/json"
|
||||
|
||||
rpc "buf.build/gen/go/k8sgpt-ai/k8sgpt/grpc/go/schema/v1/schemav1grpc"
|
||||
schemav1 "buf.build/gen/go/k8sgpt-ai/k8sgpt/protocolbuffers/go/schema/v1"
|
||||
"github.com/k8sgpt-ai/k8sgpt/pkg/analysis"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
rpc.UnimplementedServerServer
|
||||
}
|
||||
|
||||
func (h *handler) Analyze(ctx context.Context, i *schemav1.AnalyzeRequest) (
|
||||
*schemav1.AnalyzeResponse,
|
||||
error,
|
||||
) {
|
||||
if i.Output == "" {
|
||||
i.Output = "json"
|
||||
}
|
||||
|
||||
if i.Backend == "" {
|
||||
i.Backend = "openai"
|
||||
}
|
||||
|
||||
if int(i.MaxConcurrency) == 0 {
|
||||
i.MaxConcurrency = 10
|
||||
}
|
||||
|
||||
config, err := analysis.NewAnalysis(
|
||||
i.Backend,
|
||||
i.Language,
|
||||
i.Filters,
|
||||
i.Namespace,
|
||||
i.Nocache,
|
||||
i.Explain,
|
||||
int(i.MaxConcurrency),
|
||||
)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
config.RunAnalysis()
|
||||
|
||||
if i.Explain {
|
||||
err := config.GetAIResults(i.Output, i.Anonymize)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
}
|
||||
|
||||
out, err := config.PrintOutput(i.Output)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
var obj schemav1.AnalyzeResponse
|
||||
|
||||
err = json.Unmarshal(out, &obj)
|
||||
if err != nil {
|
||||
return &schemav1.AnalyzeResponse{}, err
|
||||
}
|
||||
|
||||
return &obj, nil
|
||||
rpc.UnimplementedServerServiceServer
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func (s *Config) Serve() error {
|
||||
grpcServerUnaryInterceptor := grpc.UnaryInterceptor(logInterceptor(s.Logger))
|
||||
grpcServer := grpc.NewServer(grpcServerUnaryInterceptor)
|
||||
reflection.Register(grpcServer)
|
||||
rpc.RegisterServerServer(grpcServer, s.Handler)
|
||||
rpc.RegisterServerServiceServer(grpcServer, s.Handler)
|
||||
if err := grpcServer.Serve(
|
||||
lis,
|
||||
); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
|
||||
Reference in New Issue
Block a user