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 }
// 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) }
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 }
// 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 }
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 }
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 }
// 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 }
// 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 }
// 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 }