blob: 2af36a38855e0bf6ebb59f2e97b94c46d49f31c0 [file] [log] [blame]
//
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 trigger
import (
"context"
"fmt"
"net/http"
"os"
"strings"
"time"
"github.com/apache/skywalking-infra-e2e/internal/logger"
)
type httpAction struct {
interval time.Duration
times int
url string
method string
executedCount int
}
func NewHTTPAction(intervalStr string, times int, url, method string) Action {
interval, err := time.ParseDuration(intervalStr)
if err != nil {
logger.Log.Errorf("interval [%s] parse error: %s.", intervalStr, err)
return nil
}
if interval <= 0 {
logger.Log.Errorf("interval [%s] is not positive", interval)
return nil
}
// there can be env variables in url, say, "http://${GATEWAY_HOST}:${GATEWAY_PORT}/test"
url = os.ExpandEnv(url)
return &httpAction{
interval: interval,
times: times,
url: url,
method: strings.ToUpper(method),
executedCount: 0,
}
}
func (h *httpAction) Do() error {
ctx := context.Background()
t := time.NewTicker(h.interval)
h.executedCount = 0
client := &http.Client{}
request, err := http.NewRequest(h.method, h.url, nil)
if err != nil {
logger.Log.Errorf("new request error %v", err)
return err
}
logger.Log.Infof("Trigger will request URL %s %d times, %s seconds apart each time.", h.url, h.times, h.interval)
// execute until success
for range t.C {
err = h.executeOnce(client, request)
if err == nil {
break
}
if !h.couldContinue() {
logger.Log.Errorf("do request %d times, but still failed", h.times)
return err
}
}
// background interval trigger
go func() {
for {
select {
case <-t.C:
err = h.executeOnce(client, request)
if !h.couldContinue() {
return
}
case <-ctx.Done():
t.Stop()
return
}
}
}()
return nil
}
// execute http request once time
func (h *httpAction) executeOnce(client *http.Client, req *http.Request) error {
logger.Log.Debugf("request URL %s the %d time.", h.url, h.executedCount)
response, err := client.Do(req)
h.executedCount++
if err != nil {
logger.Log.Errorf("do request error %v", err)
return err
}
_ = response.Body.Close()
logger.Log.Debugf("do request %v response http code %v", h.url, response.StatusCode)
if response.StatusCode == http.StatusOK {
logger.Log.Debugf("do http action %+v success.", *h)
return nil
}
return fmt.Errorf("do request failed, response status code: %d", response.StatusCode)
}
// verify http action could continue
func (h *httpAction) couldContinue() bool {
if h.times > 0 && h.times <= h.executedCount {
return false
}
return true
}