Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/pipecd/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ go_library(
"//pkg/app/ops/insightcollector:go_default_library",
"//pkg/app/ops/mysqlensurer:go_default_library",
"//pkg/app/ops/orphancommandcleaner:go_default_library",
"//pkg/app/ops/pipedstatsbuilder:go_default_library",
"//pkg/cache/cachemetrics:go_default_library",
"//pkg/cache/rediscache:go_default_library",
"//pkg/cli:go_default_library",
Expand Down
18 changes: 14 additions & 4 deletions cmd/pipecd/ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ import (
"github.com/pipe-cd/pipe/pkg/app/ops/insightcollector"
"github.com/pipe-cd/pipe/pkg/app/ops/mysqlensurer"
"github.com/pipe-cd/pipe/pkg/app/ops/orphancommandcleaner"
"github.com/pipe-cd/pipe/pkg/app/ops/pipedstatsbuilder"
"github.com/pipe-cd/pipe/pkg/cache/rediscache"
"github.com/pipe-cd/pipe/pkg/cli"
"github.com/pipe-cd/pipe/pkg/config"
"github.com/pipe-cd/pipe/pkg/datastore"
"github.com/pipe-cd/pipe/pkg/insight/insightstore"
"github.com/pipe-cd/pipe/pkg/model"
"github.com/pipe-cd/pipe/pkg/redis"
"github.com/pipe-cd/pipe/pkg/version"
)

Expand All @@ -44,13 +47,15 @@ type ops struct {
enableInsightCollector bool
configFile string
gcloudPath string
cacheAddress string
}

func NewOpsCommand() *cobra.Command {
s := &ops{
httpPort: 9082,
adminPort: 9085,
gracePeriod: 15 * time.Second,
httpPort: 9082,
adminPort: 9085,
cacheAddress: "cache:6379",
gracePeriod: 15 * time.Second,
}
cmd := &cobra.Command{
Use: "ops",
Expand All @@ -62,6 +67,7 @@ func NewOpsCommand() *cobra.Command {
cmd.Flags().DurationVar(&s.gracePeriod, "grace-period", s.gracePeriod, "How long to wait for graceful shutdown.")
cmd.Flags().StringVar(&s.configFile, "config-file", s.configFile, "The path to the configuration file.")
cmd.Flags().StringVar(&s.gcloudPath, "gcloud-path", s.gcloudPath, "The path to the gcloud command executable.")
cmd.Flags().StringVar(&s.cacheAddress, "cache-address", s.cacheAddress, "The address to cache service.")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch 👍
Address by b967765 🙏

return cmd
}

Expand Down Expand Up @@ -144,6 +150,10 @@ func (s *ops) run(ctx context.Context, t cli.Telemetry) error {
})
}

rd := redis.NewRedis(s.cacheAddress, "")
statCache := rediscache.NewTTLHashCache(rd, cfg.Cache.TTLDuration(), defaultPipedStatHashKey)
psb := pipedstatsbuilder.NewPipedStatsBuilder(statCache, t.Logger)

// Start running admin server.
{
var (
Expand All @@ -157,7 +167,7 @@ func (s *ops) run(ctx context.Context, t cli.Telemetry) error {
admin.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})
admin.Handle("/metrics", t.PrometheusMetricsHandler())
admin.Handle("/metrics", t.CustomedMetricsHandlerFor(psb))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with this customed metrics handler, we ignore all other metrics exposed to the current ops metrics registry ( which currently is zero ). Will carefully handle those ops's metrics later 🙏

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I feel the name should be -> CustomMetricsHandlerFor


group.Go(func() error {
return admin.Run(ctx)
Expand Down
1 change: 1 addition & 0 deletions manifests/pipecd/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ spec:
imagePullPolicy: IfNotPresent
args:
- ops
- --cache-address={{ .Values.ops.args.cacheAddress | default (printf "%s-cache:6379" (include "pipecd.fullname" .)) }}
- --config-file=/etc/pipecd-config/{{ .Values.config.fileName }}
- --log-encoding={{ .Values.ops.args.logEncoding }}
ports:
Expand Down
1 change: 1 addition & 0 deletions manifests/pipecd/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ops:
image:
repository: gcr.io/pipecd/pipecd
args:
cacheAddress: ""
logEncoding: humanize
resources: {}

Expand Down
12 changes: 12 additions & 0 deletions pkg/app/ops/pipedstatsbuilder/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["builder.go"],
importpath = "github.com/pipe-cd/pipe/pkg/app/ops/pipedstatsbuilder",
visibility = ["//visibility:public"],
deps = [
"//pkg/cache:go_default_library",
"@org_uber_go_zap//:go_default_library",
],
)
57 changes: 57 additions & 0 deletions pkg/app/ops/pipedstatsbuilder/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2021 The PipeCD Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pipedstatsbuilder

import (
"bytes"
"errors"
"io"
"io/ioutil"

"go.uber.org/zap"

"github.com/pipe-cd/pipe/pkg/cache"
)

type PipedStatsBuilder struct {
backend cache.Cache
logger *zap.Logger
}

func NewPipedStatsBuilder(c cache.Cache, logger *zap.Logger) *PipedStatsBuilder {
return &PipedStatsBuilder{
backend: c,
logger: logger.Named("piped-metrics-builder"),
}
}

func (b *PipedStatsBuilder) Build() (io.ReadCloser, error) {
res, err := b.backend.GetAll()
if err != nil {
b.logger.Error("failed to fetch piped stats from cache", zap.Error(err))
return nil, err
}
data := make([][]byte, 0, len(res))
for _, v := range res {
value, okValue := v.([]byte)
if !okValue {
err = errors.New("error value not a bulk of string value")
b.logger.Error("failed to marshal piped stat data", zap.Error(err))
return nil, err
}
data = append(data, value)
}
return ioutil.NopCloser(bytes.NewReader(bytes.Join(data, []byte("\n")))), nil

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iouti.NopClose is deprecated. Instead using io.NopCloser is preferable.
https://golang.org/pkg/io/ioutil/#NopCloser

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, why does it need to be an io.ReadCloser? Seems like io.Reader is enough.

@khanhtc1202 khanhtc1202 Jul 8, 2021

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀 Just want to carefully close the []byte stream on the hander side. Or is it unnecessary? 🤔
ref: https://github.com/pipe-cd/pipe/pull/2202/files#diff-c9b9fc9a691a60f03cc1d752ce9fac11e932d6a2867c984bd26923131704fdeaR152

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, NopCloser.Close does nothing.

And with the current implementation of PipedStatsBuilder.Build(), all byte sequences are on the heap. So no need to do close operations at all.

@nakabonne nakabonne Jul 8, 2021

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're planning to directly read from any kinds of stream like Redis in the future, then you will have to add the close operation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see 👍 Since we will keep the GetAll interface which returns data ( not the reader or else to direct stream data ), it's safe to remove this unnecessary closer as you mentioned 🙏 Lets me address it here 🙆‍♀️

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed on d448919 🙏

}
26 changes: 26 additions & 0 deletions pkg/cli/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package cli

import (
"context"
"io"
"net/http"
"os"
"os/signal"
Expand Down Expand Up @@ -137,6 +138,31 @@ func (t Telemetry) PrometheusMetricsHandlerFor(r *prometheus.Registry) http.Hand
return empty
}

type MetricsBuilder interface {
Build() (io.ReadCloser, error)
}

func (t Telemetry) CustomedMetricsHandlerFor(mb MetricsBuilder) http.Handler {
if t.Flags.Metrics {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rc, err := mb.Build()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
defer rc.Close()

_, err = io.Copy(w, rc)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}
var empty http.HandlerFunc = func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(""))
}
return empty
}

func extractServiceName(cmd *cobra.Command) string {
return strings.Replace(cmd.CommandPath(), " ", ".", -1)
}