github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/create/create_etc_hosts.go (about)

     1  package create
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/url"
     7  	"strings"
     8  
     9  	"github.com/olli-ai/jx/v2/pkg/cmd/create/options"
    10  
    11  	"github.com/olli-ai/jx/v2/pkg/cmd/helper"
    12  
    13  	"github.com/olli-ai/jx/v2/pkg/kube/services"
    14  
    15  	"github.com/jenkins-x/jx-logging/pkg/log"
    16  	"github.com/olli-ai/jx/v2/pkg/cmd/opts"
    17  	"github.com/olli-ai/jx/v2/pkg/cmd/templates"
    18  	"github.com/olli-ai/jx/v2/pkg/util"
    19  	"github.com/spf13/cobra"
    20  )
    21  
    22  const (
    23  	optionName = "name"
    24  )
    25  
    26  var (
    27  	create_etc_hosts_long = templates.LongDesc(`
    28  		Creates /etc/hosts entries for all current exposed services
    29  `)
    30  
    31  	create_etc_hosts_example = templates.Examples(`
    32  		# Creates /etc/hosts entries for all current exposed services
    33  		sudo jx create etc-hosts
    34  	`)
    35  )
    36  
    37  // CreateEtcHostsOptions the options for the create spring command
    38  type CreateEtcHostsOptions struct {
    39  	options.CreateOptions
    40  
    41  	Name string
    42  	IP   string
    43  }
    44  
    45  // NewCmdCreateEtcHosts creates a command object for the "create" command
    46  func NewCmdCreateEtcHosts(commonOpts *opts.CommonOptions) *cobra.Command {
    47  	options := &CreateEtcHostsOptions{
    48  		CreateOptions: options.CreateOptions{
    49  			CommonOptions: commonOpts,
    50  		},
    51  	}
    52  
    53  	cmd := &cobra.Command{
    54  		Use:     "etc-hosts kind [url]",
    55  		Short:   "Creates a new Git server URL",
    56  		Aliases: []string{"etchosts", "etc_hosts"},
    57  		Long:    create_etc_hosts_long,
    58  		Example: create_etc_hosts_example,
    59  		Run: func(cmd *cobra.Command, args []string) {
    60  			options.Cmd = cmd
    61  			options.Args = args
    62  			err := options.Run()
    63  			helper.CheckErr(err)
    64  		},
    65  	}
    66  
    67  	cmd.Flags().StringVarP(&options.Name, optionName, "n", "/etc/hosts", "The etc hosts file to edit")
    68  	cmd.Flags().StringVarP(&options.IP, "ip", "i", "", "The IP address of the node to point the host entries to")
    69  	return cmd
    70  }
    71  
    72  // Run implements the command
    73  func (o *CreateEtcHostsOptions) Run() error {
    74  	name := o.Name
    75  	if name == "" {
    76  		return util.MissingOption(name)
    77  	}
    78  	client, ns, err := o.KubeClientAndNamespace()
    79  	if err != nil {
    80  		return err
    81  	}
    82  	urls, err := services.FindServiceURLs(client, ns)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	exists, err := util.FileExists(name)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	if !exists {
    91  		return fmt.Errorf("hosts file %s does not exist!", name)
    92  	}
    93  	data, err := ioutil.ReadFile(name)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	text := string(data)
    98  	lines := strings.Split(text, "\n")
    99  	idx, ipLine := o.findIPLine(&lines)
   100  	for _, u := range urls {
   101  		ipLine = o.addUrl(u, ipLine)
   102  	}
   103  	lines[idx] = ipLine
   104  	newText := strings.Join(lines, "\n")
   105  	if newText != text {
   106  		err = ioutil.WriteFile(name, []byte(newText), util.DefaultWritePermissions)
   107  		if err != nil {
   108  			return err
   109  		}
   110  		log.Logger().Infof("Updated file %s", util.ColorInfo(name))
   111  	}
   112  	return nil
   113  }
   114  
   115  func (o *CreateEtcHostsOptions) addUrl(serviceUrl services.ServiceURL, ipLine string) string {
   116  	text := serviceUrl.URL
   117  	u, err := url.Parse(text)
   118  	if err != nil {
   119  		log.Logger().Warnf("Ignored invalid URL %s %s", text, err)
   120  		return ipLine
   121  	}
   122  	host := u.Host
   123  	fields := strings.Fields(ipLine)
   124  	for i := 1; i < len(fields); i++ {
   125  		if fields[i] == host {
   126  			return ipLine
   127  		}
   128  	}
   129  	if !strings.HasSuffix(ipLine, " ") {
   130  		ipLine += " "
   131  	}
   132  	return ipLine + host
   133  }
   134  
   135  func (o *CreateEtcHostsOptions) findIPLine(lines *[]string) (int, string) {
   136  	prefix := o.IP + " "
   137  	for i, line := range *lines {
   138  		if strings.HasPrefix(line, prefix) {
   139  			return i, line
   140  		}
   141  	}
   142  
   143  	idx := len(*lines) + 2
   144  	*lines = append(*lines, "", "# jx added services entries", prefix)
   145  	return idx, prefix
   146  
   147  }