VOL-1305 Separation of DHCP/AAA emulation part from OLT/ONUs emulation part

Change-Id: Idd2c6fb9bee7b7dca967b9bd49f6189343d1357f
diff --git a/core/tester.go b/core/tester.go
new file mode 100644
index 0000000..ba4792b
--- /dev/null
+++ b/core/tester.go
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * 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 core
+
+import (
+	"context"
+	"gerrit.opencord.org/voltha-bbsim/common"
+	"golang.org/x/sync/errgroup"
+	"log"
+	"os/exec"
+	"time"
+	"sync"
+)
+
+const (
+	DEFAULT Mode = iota
+	AAA
+	BOTH
+)
+
+type Mode int
+
+type Tester struct {
+	Mode         Mode
+	AAAWait      int
+	DhcpWait     int
+	DhcpServerIP string
+	Processes    []string
+	Intvl        int
+	cancel       context.CancelFunc
+}
+
+func NewTester(opt *option) *Tester{
+	t := new(Tester)
+	t.AAAWait = opt.aaawait
+	t.DhcpWait = opt.dhcpwait
+	t.DhcpServerIP = opt.dhcpservip
+	t.Intvl = opt.intvl_test
+	t.Mode = opt.Mode
+	return t
+}
+
+//Blocking
+func (t *Tester) Start (s *Server) error {
+	ctx := context.Background()
+	ctx, cancel := context.WithCancel(ctx)
+	t.cancel = cancel
+	defer func(){
+		cancel()
+		t.Initialize()
+		logger.Debug("Tester Done")
+	}()
+	logger.Info("Tester Run() start")
+	if t.Mode == DEFAULT {
+		//Empty
+	} else if t.Mode == AAA || t.Mode == BOTH {
+		eg, child := errgroup.WithContext(ctx)
+		child, cancel := context.WithCancel(child)
+		eg.Go(func() error {
+			defer func() {
+				logger.Debug("exeAAATest Done")
+			}()
+			err := t.exeAAATest(child, s, t.AAAWait)
+			return err
+		})
+
+		if t.Mode == BOTH {
+			eg.Go(func() error {
+				defer func() {
+					logger.Debug("exeDHCPTest Done")
+				}()
+
+				err := t.exeDHCPTest(ctx, s, t.DhcpWait)
+				return err
+			})
+		}
+		if err := eg.Wait(); err != nil {
+			logger.Error("Error happened in tester: %s", err)
+			cancel()
+			return err
+		} else {
+			logger.Debug("Test successfully finished")
+		}
+	}
+	return nil
+}
+
+func (t *Tester) Stop(s *Server) error {
+	if t.cancel != nil {
+		t.cancel()
+	}
+	return nil
+}
+
+func (t *Tester) Initialize (){
+	logger.Info("Tester Initialize () called")
+	processes := t.Processes
+	logger.Debug("Runnig Process: %s", processes)
+	KillProcesses(processes)
+	exec.Command("rm", "/var/run/dhcpd.pid").Run()	//This is for DHCP server activation
+	exec.Command("touch", "/var/run/dhcpd.pid").Run()	//This is for DHCP server activation
+}
+
+
+func (t *Tester) exeAAATest(ctx context.Context, s *Server, wait int) error {
+	tick := time.NewTicker(time.Second)
+	defer tick.Stop()
+	logger.Info("exeAAATest stands by....")
+	infos, err := s.GetUniIoinfos("outside")
+	if err != nil {
+		return err
+	}
+
+	univeths := []string{}
+	for _, info := range infos {
+		univeths = append(univeths, info.Name)
+	}
+
+	for sec := 1; sec <= wait; sec ++ {
+		select {
+		case <-ctx.Done():
+			logger.Debug("exeAAATest thread receives close ")
+			return nil
+		case <-tick.C:
+			logger.Info("exeAAATest stands by ... %dsec\n", wait - sec)
+			if sec == wait {
+				wg := sync.WaitGroup{}
+				wg.Add(1)
+				go func() error{
+					defer wg.Done()
+					err = activateWPASups(ctx, univeths, t.Intvl)
+					if err != nil {
+						return err
+					}
+					logger.Info("WPA supplicants are successfully activated ")
+					t.Processes = append(t.Processes, "wpa_supplicant")
+					logger.Debug("Running Process:%s", t.Processes)
+					return nil
+				}()
+				wg.Wait()
+			}
+		}
+	}
+	return nil
+}
+
+func (t *Tester) exeDHCPTest(ctx context.Context, s *Server, wait int) error {
+	tick := time.NewTicker(time.Second)
+	defer tick.Stop()
+	logger.Info("exeDHCPTest stands by....")
+	info, err := s.IdentifyNniIoinfo("outside")
+	if err != nil {
+		return err
+	}
+
+	err = activateDHCPServer(info.Name, t.DhcpServerIP)
+	if err != nil {
+		return err
+	}
+	t.Processes = append(t.Processes, "dhcpd")
+	logger.Debug("Running Process:%s", t.Processes)
+
+	infos, err := s.GetUniIoinfos("outside")
+	if err != nil {
+		return err
+	}
+
+	univeths := []string{}
+	for _, info := range infos {
+		univeths = append(univeths, info.Name)
+	}
+
+	for sec := 1; sec <= wait; sec ++ {
+		select {
+		case <- ctx.Done():
+			logger.Debug("exeDHCPTest thread receives close ")
+			return nil
+		case <- tick.C:
+			logger.Info("exeDHCPTest stands by ... %dsec\n", wait- sec)
+			if sec == wait {
+				wg := sync.WaitGroup{}
+				wg.Add(1)
+				go func() error{
+					defer wg.Done()
+					err = activateDHCPClients(ctx, univeths, t.Intvl)
+					if err != nil {
+						return err
+					}
+					logger.Info("DHCP clients are successfully activated ")
+					t.Processes = append(t.Processes, "dhclient")
+					logger.Debug("Running Process:%s", t.Processes)
+					return nil
+				}()
+				wg.Wait()
+			}
+		}
+	}
+	return nil
+}
+
+func KillProcesses(pnames []string) error {
+	for _, pname := range pnames {
+		killProcess(pname)
+	}
+	return nil
+}
+
+func activateWPASups(ctx context.Context, vethnames []string, intvl int) error {
+	tick := time.NewTicker(time.Duration(intvl) * time.Second)
+	defer tick.Stop()
+	i := 0
+	for {
+		select{
+		case <- tick.C:
+			if i < len(vethnames) {
+				vethname := vethnames[i]
+				if err := activateWPASupplicant(vethname); err != nil {
+					return err
+				}
+				logger.Debug("activateWPASupplicant for interface %v\n", vethname)
+				i ++
+			}
+		case <- ctx.Done():
+			logger.Debug("activateWPASups was canceled by context.")
+			return nil
+		}
+	}
+	return nil
+}
+
+func activateDHCPClients(ctx context.Context, vethnames []string, intvl int) error {
+	tick := time.NewTicker(time.Duration(intvl) * time.Second)
+	defer tick.Stop()
+	i := 0
+	for {
+		select{
+		case <- tick.C:
+			if i < len(vethnames){
+				vethname := vethnames[i]
+				if err := activateDHCPClient(vethname); err != nil {
+					return err
+				}
+				logger.Debug("activateDHCPClient for interface %v\n", vethname)
+				i ++
+			}
+		case <- ctx.Done():
+			logger.Debug("activateDHCPClients was canceled by context.")
+			return nil
+		}
+	}
+	return nil
+}
+
+func killProcess(name string) error {
+	err := exec.Command("pkill", name).Run()
+	if err != nil {
+		logger.Error("Fail to pkill %s: %v\n", name, err)
+		return err
+	}
+	logger.Info("Successfully killed %s\n", name)
+	return nil
+}
+
+func activateWPASupplicant(vethname string) (err error) {
+	cmd := "/sbin/wpa_supplicant"
+	conf := "/etc/wpa_supplicant/wpa_supplicant.conf"
+	err = exec.Command(cmd, "-D", "wired", "-i", vethname, "-c", conf).Start()
+	if err != nil {
+		logger.Error("Fail to activateWPASupplicant() for :%s %v\n", vethname, err)
+		return
+	}
+	logger.Info("activateWPASupplicant() for :%s\n", vethname)
+	return
+}
+
+func activateDHCPClient(vethname string) (err error) {
+	logger.Debug("activateDHCPClient() start for: %s\n", vethname)
+	cmd := exec.Command("/usr/local/bin/dhclient", vethname)
+	// if err := cmd.Run(); err != nil {
+	if err := cmd.Start(); err != nil {
+		logger.Error("Fail to activateDHCPClient() for: %s", vethname)
+		log.Panic(err)
+	}
+	logger.Debug("activateDHCPClient() done for: %s\n", vethname)
+	return
+}
+
+func activateDHCPServer(veth string, serverip string) error {
+	err := exec.Command("ip", "addr", "add", serverip, "dev", veth).Run()
+	if err != nil {
+		logger.Error("Fail to add ip to %s address: %s\n", veth, err)
+		return err
+	}
+	err = exec.Command("ip", "link", "set", veth, "up").Run()
+	if err != nil {
+		logger.Error("Fail to set %s up: %s\n", veth, err)
+		return err
+	}
+	cmd := "/usr/local/bin/dhcpd"
+	conf := "/etc/dhcp/dhcpd.conf"
+	err = exec.Command(cmd, "-cf", conf, veth).Run()
+	if err != nil {
+		logger.Error("Fail to activateDHCP Server (): %s\n", err)
+		return err
+	}
+	logger.Info("DHCP Server is successfully activated !\n")
+	return err
+}