github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/bench/tpch.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package bench
    21  
    22  import (
    23  	"context"
    24  	"fmt"
    25  	"strings"
    26  
    27  	"github.com/spf13/cobra"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    30  	"k8s.io/apimachinery/pkg/runtime"
    31  	"k8s.io/cli-runtime/pkg/genericiooptions"
    32  	cmdutil "k8s.io/kubectl/pkg/cmd/util"
    33  	"k8s.io/kubectl/pkg/util/templates"
    34  
    35  	"github.com/apecloud/kubebench/api/v1alpha1"
    36  
    37  	"github.com/1aal/kubeblocks/pkg/cli/cluster"
    38  	"github.com/1aal/kubeblocks/pkg/cli/types"
    39  )
    40  
    41  var (
    42  	tpchDriverMap = map[string]string{
    43  		"mysql": "mysql",
    44  	}
    45  	tpchSupportedDrivers = []string{"mysql"}
    46  )
    47  
    48  var tpchExample = templates.Examples(`
    49  	# tpch on a cluster, that will exec for all steps, cleanup, prepare and run
    50  	kbcli bench tpch mytest --cluster mycluster --user xxx --password xxx --database mydb
    51  
    52  	# tpch on a cluster with run, just run by running the test
    53  	kbcli bench tpch run mytest --cluster mycluster --user xxx --password xxx --database mydb
    54  `)
    55  
    56  type TpchOptions struct {
    57  	BenchBaseOptions
    58  }
    59  
    60  func NewTpchCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
    61  	o := &TpchOptions{
    62  		BenchBaseOptions: BenchBaseOptions{
    63  			IOStreams: streams,
    64  			factory:   f,
    65  		},
    66  	}
    67  	cmd := &cobra.Command{
    68  		Use:     "tpch [Step] [BenchmarkName]",
    69  		Short:   "Run tpch benchmark",
    70  		Example: tpchExample,
    71  		Run: func(cmd *cobra.Command, args []string) {
    72  			cmdutil.CheckErr(o.Complete(args))
    73  			cmdutil.CheckErr(o.Validate())
    74  			cmdutil.CheckErr(o.Run())
    75  		},
    76  	}
    77  
    78  	o.AddFlags(cmd)
    79  
    80  	return cmd
    81  }
    82  
    83  func (o *TpchOptions) Complete(args []string) error {
    84  	var err error
    85  	var driver string
    86  	var host string
    87  	var port int
    88  
    89  	if err = o.BenchBaseOptions.BaseComplete(); err != nil {
    90  		return err
    91  	}
    92  
    93  	o.Step, o.name = parseStepAndName(args, "tpch")
    94  
    95  	o.namespace, _, err = o.factory.ToRawKubeConfigLoader().Namespace()
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	if o.dynamic, err = o.factory.DynamicClient(); err != nil {
   101  		return err
   102  	}
   103  
   104  	if o.client, err = o.factory.KubernetesClientSet(); err != nil {
   105  		return err
   106  	}
   107  
   108  	if o.ClusterName != "" {
   109  		clusterGetter := cluster.ObjectsGetter{
   110  			Client:    o.client,
   111  			Dynamic:   o.dynamic,
   112  			Name:      o.ClusterName,
   113  			Namespace: o.namespace,
   114  			GetOptions: cluster.GetOptions{
   115  				WithClusterDef:     true,
   116  				WithService:        true,
   117  				WithPod:            true,
   118  				WithEvent:          true,
   119  				WithPVC:            true,
   120  				WithDataProtection: true,
   121  			},
   122  		}
   123  		if o.ClusterObjects, err = clusterGetter.Get(); err != nil {
   124  			return err
   125  		}
   126  		driver, host, port, err = getDriverAndHostAndPort(o.Cluster, o.Services)
   127  		if err != nil {
   128  			return err
   129  		}
   130  	}
   131  
   132  	// don't overwrite the driver if it's already set
   133  	if v, ok := tpchDriverMap[driver]; ok && o.Driver == "" {
   134  		o.Driver = v
   135  	}
   136  
   137  	// don't overwrite the host and port if they are already set
   138  	if o.Host == "" && o.Port == 0 {
   139  		o.Host = host
   140  		o.Port = port
   141  	}
   142  
   143  	return nil
   144  }
   145  
   146  func (o *TpchOptions) Validate() error {
   147  	if err := o.BenchBaseOptions.BaseValidate(); err != nil {
   148  		return err
   149  	}
   150  
   151  	var supported bool
   152  	for _, v := range tpchDriverMap {
   153  		if o.Driver == v {
   154  			supported = true
   155  			break
   156  		}
   157  	}
   158  	if !supported {
   159  		return fmt.Errorf("tpch now only supports drivers in [%s], current cluster driver is %s",
   160  			strings.Join(tpchSupportedDrivers, ", "), o.Driver)
   161  	}
   162  
   163  	if o.User == "" {
   164  		return fmt.Errorf("user is required")
   165  	}
   166  
   167  	if o.Database == "" {
   168  		return fmt.Errorf("database is required")
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  func (o *TpchOptions) Run() error {
   175  	tpch := v1alpha1.Tpch{
   176  		TypeMeta: metav1.TypeMeta{
   177  			Kind:       "Tpch",
   178  			APIVersion: types.TpchGVR().GroupVersion().String(),
   179  		},
   180  		ObjectMeta: metav1.ObjectMeta{
   181  			Name:      o.name,
   182  			Namespace: o.namespace,
   183  		},
   184  		Spec: v1alpha1.TpchSpec{
   185  			BenchCommon: v1alpha1.BenchCommon{
   186  				ExtraArgs:   o.ExtraArgs,
   187  				Step:        o.Step,
   188  				Tolerations: o.Tolerations,
   189  				Target: v1alpha1.Target{
   190  					Driver:   o.Driver,
   191  					Host:     o.Host,
   192  					Port:     o.Port,
   193  					User:     o.User,
   194  					Password: o.Password,
   195  					Database: o.Database,
   196  				},
   197  			},
   198  		},
   199  	}
   200  
   201  	obj := &unstructured.Unstructured{
   202  		Object: map[string]interface{}{},
   203  	}
   204  	data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tpch)
   205  	if err != nil {
   206  		return err
   207  	}
   208  	obj.SetUnstructuredContent(data)
   209  
   210  	obj, err = o.dynamic.Resource(types.TpchGVR()).Namespace(o.namespace).Create(context.TODO(), obj, metav1.CreateOptions{})
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	fmt.Fprintf(o.Out, "%s %s created\n", obj.GetKind(), obj.GetName())
   216  	return nil
   217  }