github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/ci/check/check.go (about)

     1  /*
     2   * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package check
    19  
    20  import (
    21  	"errors"
    22  	"fmt"
    23  	"net"
    24  	"strings"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/magefile/mage/mg"
    29  	"github.com/magefile/mage/sh"
    30  
    31  	"github.com/mysteriumnetwork/go-ci/commands"
    32  	"github.com/mysteriumnetwork/go-ci/util"
    33  	"github.com/mysteriumnetwork/node/ci/packages"
    34  	"github.com/mysteriumnetwork/node/core/ip"
    35  	"github.com/mysteriumnetwork/node/metadata"
    36  	"github.com/mysteriumnetwork/node/requests"
    37  )
    38  
    39  // Check performs commons checks.
    40  func Check() {
    41  	mg.Deps(CheckGenerate)
    42  	mg.Deps(CheckSwagger)
    43  	mg.Deps(CheckGoImports, CheckDNSMaps, CheckGoLint, CheckGoVet, CheckCopyright)
    44  }
    45  
    46  // CheckCopyright checks for copyright headers in files.
    47  func CheckCopyright() error {
    48  	return commands.CopyrightD(".", "pb", "tequilapi/endpoints/assets", "supervisor/daemon/wireguard/wginterface/firewall")
    49  }
    50  
    51  // CheckGoLint reports linting errors in the solution.
    52  func CheckGoLint() error {
    53  	return commands.GoLintD(".", "docs", "services/wireguard/endpoint/netstack")
    54  }
    55  
    56  // CheckGoVet checks that the source is compliant with go vet.
    57  func CheckGoVet() error {
    58  	return commands.GoVet("./...")
    59  }
    60  
    61  // CheckGoImports checks for issues with go imports.
    62  func CheckGoImports() error {
    63  	return commands.GoImportsD(".", "pb", "tequilapi/endpoints/assets")
    64  }
    65  
    66  // CheckSwagger checks whether swagger spec at "tequilapi/docs/swagger.json" is valid against swagger specification 2.0.
    67  func CheckSwagger() error {
    68  	if err := sh.RunV("swagger", "validate", "tequilapi/docs/swagger.json"); err != nil {
    69  		return fmt.Errorf("could not validate swagger spec: %w", err)
    70  	}
    71  	return nil
    72  }
    73  
    74  // CheckDNSMaps checks if the given dns maps in the metadata configuration actually point to the given IPS.
    75  func CheckDNSMaps() error {
    76  	ipMissmatches := make([]string, 0)
    77  
    78  	valuesToCheck := make(map[string][]string, 0)
    79  	for k, v := range metadata.MainnetDefinition.DNSMap {
    80  		valuesToCheck[k] = v
    81  	}
    82  
    83  	for k, v := range valuesToCheck {
    84  		ips, err := net.LookupIP(k)
    85  		if err != nil {
    86  			return err
    87  		}
    88  
    89  		found := false
    90  
    91  		for _, ip := range v {
    92  			for i := range ips {
    93  				if ips[i].String() == ip {
    94  					found = true
    95  					break
    96  				}
    97  			}
    98  
    99  			if found {
   100  				break
   101  			}
   102  		}
   103  
   104  		if !found {
   105  			ipMissmatches = append(ipMissmatches, fmt.Sprintf("ip: %v, host: %v", ips, k))
   106  		}
   107  
   108  	}
   109  
   110  	if len(ipMissmatches) > 0 {
   111  		for _, v := range ipMissmatches {
   112  			fmt.Println(v)
   113  		}
   114  		return errors.New("IP missmatches found in DNS hosts")
   115  	}
   116  
   117  	return nil
   118  }
   119  
   120  var checkGenerateExcludes = []string{
   121  	"tequilapi/endpoints/assets/docs.go",
   122  }
   123  
   124  // CheckGenerate checks whether dynamic project parts are updated properly.
   125  func CheckGenerate() error {
   126  	filesBefore, err := getUncommittedFiles()
   127  	if err != nil {
   128  		return fmt.Errorf("could retrieve uncommitted files: %w", err)
   129  	}
   130  	fmt.Println("Uncommitted files (before):")
   131  	fmt.Println(filesBefore)
   132  	fmt.Println()
   133  
   134  	mg.Deps(packages.Generate)
   135  
   136  	filesAfter, err := getUncommittedFiles()
   137  	if err != nil {
   138  		return fmt.Errorf("could retrieve changed files: %w", err)
   139  	}
   140  	fmt.Println("Uncommitted files (after):")
   141  	fmt.Println(filesAfter)
   142  	fmt.Println()
   143  
   144  	if len(filesBefore) != len(filesAfter) {
   145  		fmt.Println(`Files below needs review with "mage generate"`)
   146  		return errors.New("not all dynamic files are up-to-date")
   147  	}
   148  
   149  	fmt.Println("Dynamic files are up-to-date")
   150  	return nil
   151  }
   152  
   153  func getUncommittedFiles() ([]string, error) {
   154  	filesAll, err := sh.Output("git", "diff", "HEAD", "--name-only")
   155  	if err != nil {
   156  		return nil, fmt.Errorf("could not retrieve changed files: %w", err)
   157  	}
   158  
   159  	files := make([]string, 0)
   160  	for _, file := range strings.Split(filesAll, "\n") {
   161  		if file == "" {
   162  			continue
   163  		}
   164  		if util.IsPathExcluded(checkGenerateExcludes, file) {
   165  			continue
   166  		}
   167  		files = append(files, file)
   168  	}
   169  
   170  	return files, nil
   171  }
   172  
   173  // CheckIPFallbacks checks if all the IP fallbacks are working correctly.
   174  func CheckIPFallbacks() error {
   175  	c := requests.NewHTTPClient("0.0.0.0", time.Second*30)
   176  	wg := sync.WaitGroup{}
   177  	wg.Add(len(ip.IPFallbackAddresses))
   178  
   179  	res := make([]fallbackResult, len(ip.IPFallbackAddresses))
   180  	for i, v := range ip.IPFallbackAddresses {
   181  		go func(idx int, url string) {
   182  			defer wg.Done()
   183  
   184  			r, err := ip.RequestAndParsePlainIPResponse(c, url)
   185  			res[idx] = fallbackResult{
   186  				url:      url,
   187  				response: r,
   188  				err:      err,
   189  			}
   190  		}(i, v)
   191  	}
   192  	wg.Wait()
   193  
   194  	// check that no errors are present
   195  	var errorsPresent bool
   196  	for i := range res {
   197  		if res[i].err != nil {
   198  			fmt.Printf("Unexpected error for %v: %v\n", res[i].url, res[i].err.Error())
   199  			errorsPresent = true
   200  		}
   201  	}
   202  
   203  	if errorsPresent {
   204  		return errors.New("unexpected errors present")
   205  	}
   206  
   207  	initialResult := res[0].response
   208  	for i := range res {
   209  		if res[i].response != initialResult {
   210  			fmt.Println("Missmatch for ips!")
   211  
   212  			// print all results
   213  			for j := range res {
   214  				fmt.Printf("%v: %v\n", res[j].url, res[j].response)
   215  			}
   216  
   217  			return errors.New("ip missmatches found")
   218  		}
   219  	}
   220  
   221  	fmt.Println("All IPS are in order")
   222  	return nil
   223  }
   224  
   225  type fallbackResult struct {
   226  	url      string
   227  	response string
   228  	err      error
   229  }