Beispiel #1
0
func hostAdd(cmd *cli.Command, args []string) error {
	if len(args) < 2 || len(args) > 4 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected 2, 3 or 4 arguments, saw %d: %s", len(args), args))
	}

	hostname := args[0]
	hostip := args[1]
	var romanacidr string
	if len(args) >= 3 {
		romanacidr = args[2]
	}
	var agentport uint64
	if len(args) == 4 {
		var err error
		agentPortInt, err := strconv.Atoi(args[3])
		if err != nil {
			return util.UsageError(cmd,
				fmt.Sprintf("Agent Port number error, saw %s", args[3]))
		}
		agentport = uint64(agentPortInt)
	}

	client, err := getRestClient()
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl("topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	host := common.Host{
		Name:      hostname,
		Ip:        hostip,
		RomanaIp:  romanacidr,
		AgentPort: agentport,
	}
	fmt.Printf("Host (%v) added successfully.\n", host)

	data := common.Host{}
	err = client.Post(topologyURL+"/hosts", host, &data)
	if err != nil {
		fmt.Printf("Error adding host (%s).\n", hostname)
		return err
	}

	fmt.Printf("Host (%s) added successfully.\n", hostname)
	return nil
}
Beispiel #2
0
// policyList lists policies in tabular or json format.
func policyList(cmd *cli.Command, args []string) error {
	if len(args) > 0 || policyID != 0 {
		return util.UsageError(cmd,
			"Policy listing takes no arguments.")
	}
	return policyListShow(true, nil)
}
Beispiel #3
0
func segmentList(cmd *cli.Command, args []string) error {
	if len(args) < 1 {
		return util.UsageError(cmd, "TENANT name should be provided.")
	}

	tenantShow(cmd, args)
	return nil
}
Beispiel #4
0
// policyRemove removes policy using the policy name provided
// as argument through args. It returns error if policy is not
// found, or returns a list of policy ID's if multiple policies
// with same name are found.
func policyRemove(cmd *cli.Command, args []string) error {
	var policyName string
	policyIDPresent := false

	if policyID != 0 && len(args) == 0 {
		policyIDPresent = true
	} else if policyID == 0 && len(args) == 1 {
		policyName = args[0]
	} else {
		return util.UsageError(cmd,
			"POLICY_NAME (or --policyid <id> ) should be provided.")
	}

	client, err := getRestClient()
	if err != nil {
		return err
	}

	policyURL, err := client.GetServiceUrl("policy")
	if err != nil {
		return err
	}

	policyResp := common.Policy{}

	if !policyIDPresent {
		var err error

		policyID, err = getPolicyID(policyName)
		if err != nil {
			return err
		}
	}

	policyURL += fmt.Sprintf("/policies/%d", policyID)
	err = client.Delete(policyURL, nil, &policyResp)
	if err != nil {
		return err
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(policyResp, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		if policyIDPresent {
			fmt.Printf("Policy (ID: %d) deleted successfully.\n", policyID)
		} else {
			fmt.Printf("Policy (%s) deleted successfully.\n", policyName)
		}
	}

	return nil
}
Beispiel #5
0
func hostShow(cmd *cli.Command, args []string) error {
	if len(args) < 1 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected at-least 1 argument, saw none"))
	}

	client, err := getRestClient()
	if err != nil {
		return err
	}

	topologyURL, err := client.GetServiceUrl("topology")
	if err != nil {
		return err
	}

	index := common.IndexResponse{}
	err = client.Get(topologyURL, &index)
	if err != nil {
		return err
	}

	hostURL := index.Links.FindByRel("host-list")
	data := []common.Host{}
	hosts := []common.Host{}
	err = client.Get(hostURL, &data)
	if err != nil {
		return err
	}

	for _, h := range data {
		for _, n := range args {
			if h.Name == n {
				hosts = append(hosts, h)
			}
		}
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(hosts, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Println("Host List")
		fmt.Fprintln(w, "Id\t",
			"Host Name\t",
			"Host IP\t",
			"Romana CIDR\t",
			"Agent Port\t")
		for _, host := range hosts {
			fmt.Fprintln(w, host.ID, "\t",
				host.Name, "\t",
				host.Ip, "\t",
				host.RomanaIp, "\t",
				host.AgentPort, "\t")
		}
		w.Flush()
	}

	return nil
}
Beispiel #6
0
func segmentAdd(cmd *cli.Command, args []string) error {
	if len(args) != 2 {
		return util.UsageError(cmd, "TENANT and SEGMENT name should be provided.")
	}

	tnt := args[0]
	seg := args[1]

	client, err := getRestClient()
	if err != nil {
		return err
	}

	romanaID, err := romana.GetTenantID(client, tnt)
	if err != nil {
		return errors.New("Romana Tenant doesn't exists: " + tnt)
	}
	romanaIDStr := strconv.FormatUint(romanaID, 10)

	tenantURL, err := client.GetServiceUrl("tenant")
	if err != nil {
		return err
	}

	data := tenant.Segment{Name: seg, ExternalID: externalID}
	var result map[string]interface{}
	err = client.Post(tenantURL+"/tenants/"+romanaIDStr+"/segments",
		data, &result)
	if err != nil {
		return err
	}

	_, tFound := result["name"]
	if !tFound {
		var h common.HttpError
		dc := &ms.DecoderConfig{TagName: "json", Result: &h}
		decoder, err := ms.NewDecoder(dc)
		if err != nil {
			return err
		}
		err = decoder.Decode(result)
		if err != nil {
			return err
		}
		if config.GetString("Format") == "json" {
			status, _ := json.MarshalIndent(h, "", "\t")
			fmt.Println(string(status))
			return fmt.Errorf("HTTP Error")
		}
		return fmt.Errorf(h.Error())
	}

	if config.GetString("Format") == "json" {
		segment := tenant.Segment{}
		dc := &ms.DecoderConfig{TagName: "json", Result: &segment}
		decoder, err := ms.NewDecoder(dc)
		if err != nil {
			return err
		}
		err = decoder.Decode(result)
		if err != nil {
			return err
		}
		body, err := json.MarshalIndent(segment, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		fmt.Printf("Tenant Segment (%s) added successfully.\n", seg)
	}
	return nil
}
Beispiel #7
0
// tenantShow displays tenant details using tenant name
// or tenant external id as input.
func tenantShow(cmd *cli.Command, args []string) error {
	if len(args) < 1 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected at-least 1 argument, saw none"))
	}

	client, err := getRestClient()
	if err != nil {
		return err
	}

	tenantURL, err := client.GetServiceUrl("tenant")
	if err != nil {
		return err
	}

	data := []tenant.Tenant{}
	tenants := []tenantData{}
	err = client.Get(tenantURL+"/tenants", &data)
	if err != nil {
		httpErr, ok := err.(common.HttpError)
		// A 404 here means that no tenants have been defined, yet. That's not
		// an error.
		if ok && httpErr.StatusCode == http.StatusNotFound {
			fmt.Println("No tenants are currently defined")
		}
		return err
	}

	for _, t := range data {
		for _, n := range args {
			if t.Name == n || t.ExternalID == n {
				seg := []tenant.Segment{}
				err = client.Get(tenantURL+"/tenants/"+t.ExternalID+"/segments", &seg)
				if err != nil {
					httpErr, ok := err.(common.HttpError)
					// A 404 just means that there are no segments defined yet.
					// That's not an error. That's why we only return an error
					// here if it's a non-HTTP error or the HTTP status code is
					// something besides 404.
					if !ok || httpErr.StatusCode != http.StatusNotFound {
						return err
					}
				}
				tenants = append(tenants, tenantData{t, seg})
			}
		}
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(tenants, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Fprintln(w, "ID\t",
			"Tenant Name\t",
			"External ID\t",
			"Segments", "\t",
		)
		for _, t := range tenants {
			fmt.Fprintf(w, "%d \t %s \t %s \t", t.Tenant.ID,
				t.Tenant.Name, t.Tenant.ExternalID)
			if len(t.Segments) > 0 {
				for _, s := range t.Segments {
					fmt.Fprintf(w, "%s, ", s.Name)
				}
			} else {
				fmt.Fprintf(w, "(no segments defined)")
			}
			fmt.Fprintf(w, "\n")
		}
		w.Flush()
	}

	return nil
}
Beispiel #8
0
// tenantCreate accepts tenant names as arguments for
// creating new tenants for platform being set in
// config file (~/.romana.yaml) or via command line
// flags.
func tenantCreate(cmd *cli.Command, args []string) error {
	if len(args) < 1 {
		return util.UsageError(cmd,
			fmt.Sprintf("expected at-least 1 argument, saw none"))
	}

	client, err := getRestClient()
	if err != nil {
		return err
	}

	tenantURL, err := client.GetServiceUrl("tenant")
	if err != nil {
		return err
	}

	tenants := []tenant.Tenant{}
	for _, tnt := range args {
		var tntUUID string

		// uncomment this once creating tenant for all
		// platforms are ready. Till then tenants needs
		// to be manually created for every platform and
		// then created using romana command line tools.
		// if adaptor.CreateTenant(tnt) != nil {
		// 	return err
		// }
		// adaptor.GetTenantUUID below wouldn't be needed once
		// adaptor.CreateTenant is supported because CreateTenant
		// will create a new tenant for a specific platform
		// instead of polling for an already created one using
		// GetTenantUUID.
		if externalID == "" {
			tntUUID, err = adaptor.GetTenantUUID(tnt)
			if err != nil {
				switch err {
				case util.ErrUnimplementedFeature:
					return util.UsageError(cmd,
						"[tenantname] --externalid <externalid> should be provided.")
				default:
					return err
				}
			}
		} else {
			if len(args) > 1 {
				return util.UsageError(cmd,
					"[tenantname] --externalid <externalid> should be provided.\n"+
						"Multiple tenants can't be created with same external ID.",
				)
			}
			tntUUID = externalID
		}

		data := tenant.Tenant{Name: tnt, ExternalID: tntUUID}
		var result map[string]interface{}
		err = client.Post(tenantURL+"/tenants", data, &result)
		if err != nil {
			return err
		}
		_, tFound := result["name"]
		if tFound {
			var t tenant.Tenant
			dc := &ms.DecoderConfig{TagName: "json", Result: &t}
			decoder, err := ms.NewDecoder(dc)
			if err != nil {
				return err
			}
			err = decoder.Decode(result)
			if err != nil {
				return err
			}
			tenants = append(tenants, t)
		} else {
			var h common.HttpError
			dc := &ms.DecoderConfig{TagName: "json", Result: &h}
			decoder, err := ms.NewDecoder(dc)
			if err != nil {
				return err
			}
			err = decoder.Decode(result)
			if err != nil {
				return err
			}
			if config.GetString("Format") == "json" {
				status, _ := json.MarshalIndent(h, "", "\t")
				fmt.Println(string(status))
				return fmt.Errorf("HTTP Error")
			}
			return fmt.Errorf(h.Error())
		}
	}

	if config.GetString("Format") == "json" {
		body, err := json.MarshalIndent(tenants, "", "\t")
		if err != nil {
			return err
		}
		fmt.Println(string(body))
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Println("New Tenant(s) Added:")
		fmt.Fprintln(w, "Id\t",
			"Tenant Name\t",
			"External ID\t",
		)
		for _, t := range tenants {
			fmt.Fprintf(w, "%d \t %s \t %s \t", t.ID,
				t.Name, t.ExternalID)
			fmt.Fprintf(w, "\n")
		}
		w.Flush()
	}

	return nil
}
Beispiel #9
0
// policyAdd adds romana policy for a specific tenant
// using the policyFile provided or through input pipe.
// The features supported are:
//  * Policy addition through file with single policy in it
//  * Policy addition through file with multiple policies
//    in it supporting the SecurityPolicies construct as
//    shown in policy/policy.sample.json
//  * Both the above formats but taking input from standard
//    input (STDIN) instead of a file
//  * Tabular and json output for indication of policy
//    addition
func policyAdd(cmd *cli.Command, args []string) error {
	var buf []byte
	var policyFile string
	var err error
	isFile := true
	isJSON := config.GetString("Format") == "json"

	if len(args) == 0 {
		isFile = false
		buf, err = ioutil.ReadAll(os.Stdin)
		if err != nil {
			util.UsageError(cmd,
				"POLICY FILE name or piped input from 'STDIN' expected.")
			return fmt.Errorf("Cannot read 'STDIN': %s\n", err)
		}
	} else if len(args) != 1 {
		return util.UsageError(cmd,
			"POLICY FILE name or piped input from 'STDIN' expected.")
	}

	if isFile {
		policyFile = args[0]
	}

	client, err := getRestClient()
	if err != nil {
		return err
	}

	policyURL, err := client.GetServiceUrl("policy")
	if err != nil {
		return err
	}

	reqPolicies := Policies{}
	if isFile {
		pBuf, err := ioutil.ReadFile(policyFile)
		if err != nil {
			return fmt.Errorf("File error: %s\n", err)
		}
		err = json.Unmarshal(pBuf, &reqPolicies)
		if err != nil || len(reqPolicies.SecurityPolicies) == 0 {
			reqPolicies.SecurityPolicies = make([]common.Policy, 1)
			err = json.Unmarshal(pBuf, &reqPolicies.SecurityPolicies[0])
			if err != nil {
				return err
			}
		}
	} else {
		err = json.Unmarshal(buf, &reqPolicies)
		if err != nil || len(reqPolicies.SecurityPolicies) == 0 {
			reqPolicies.SecurityPolicies = make([]common.Policy, 1)
			err = json.Unmarshal(buf, &reqPolicies.SecurityPolicies[0])
			if err != nil {
				return err
			}
		}
	}

	result := make([]map[string]interface{}, len(reqPolicies.SecurityPolicies))
	reqPolicies.AppliedSuccessfully = make([]bool, len(reqPolicies.SecurityPolicies))
	for i, pol := range reqPolicies.SecurityPolicies {
		reqPolicies.AppliedSuccessfully[i] = false
		err = client.Post(policyURL+"/policies", pol, &result[i])
		if err != nil {
			log.Printf("Error in client.Post(): %v", err)
			continue
		}
		reqPolicies.AppliedSuccessfully[i] = true
	}

	if isJSON {
		for i := range reqPolicies.SecurityPolicies {
			// check if any of policy markers are present in the map.
			_, exOk := result[i]["external_id"]
			_, idOk := result[i]["id"]
			_, nmOk := result[i]["name"]
			if exOk || idOk || nmOk {
				var p common.Policy
				dc := &ms.DecoderConfig{TagName: "json", Result: &p}
				decoder, err := ms.NewDecoder(dc)
				if err != nil {
					continue
				}
				err = decoder.Decode(result[i])
				if err != nil {
					continue
				}
				body, err := json.MarshalIndent(p, "", "\t")
				if err != nil {
					continue
				}
				fmt.Println(string(body))
			} else {
				var h common.HttpError
				dc := &ms.DecoderConfig{TagName: "json", Result: &h}
				decoder, err := ms.NewDecoder(dc)
				if err != nil {
					continue
				}
				err = decoder.Decode(result[i])
				if err != nil {
					continue
				}
				status, _ := json.MarshalIndent(h, "", "\t")
				fmt.Println(string(status))
			}
		}
	} else {
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 8, 0, '\t', 0)
		fmt.Println("New Policies Processed:")
		fmt.Fprintln(w, "Id\t",
			"Policy Name\t",
			"Direction\t",
			"Successful Applied?\t",
		)
		for i, pol := range reqPolicies.SecurityPolicies {
			// check if any of policy markers are present in the map.
			_, exOk := result[i]["external_id"]
			_, idOk := result[i]["id"]
			_, nmOk := result[i]["name"]
			if exOk || idOk || nmOk {
				var p common.Policy
				dc := &ms.DecoderConfig{TagName: "json", Result: &p}
				decoder, err := ms.NewDecoder(dc)
				if err != nil {
					continue
				}
				err = decoder.Decode(result[i])
				if err != nil {
					continue
				}
				fmt.Fprintf(w, "%d \t %s \t %s \t %t \n", p.ID,
					p.Name, p.Direction, reqPolicies.AppliedSuccessfully[i])
			} else {
				fmt.Fprintf(w, "%d \t %s \t %s \t %t \n", pol.ID,
					pol.Name, pol.Direction, false)
			}
		}
		w.Flush()
	}

	return nil
}