// process is a goroutine that consumes resource update events coming from // Kubernetes and: // 1. On receiving an added or deleted event: // i. add it to the queue // ii. on a timer event, send the events to handleNetworkPolicyEvents and empty the queue // 2. On receiving a done event, exit the goroutine func (l *KubeListener) process(in <-chan Event, done chan struct{}) { log.Infof("KubeListener: process(): Entered with in %v, done %v", in, done) timer := time.Tick(processorTickTime * time.Second) var networkPolicyEvents []Event go func() { for { select { case <-timer: if len(networkPolicyEvents) > 0 { log.Infof("Calling network policy handler for scheduled %d events", len(networkPolicyEvents)) handleNetworkPolicyEvents(networkPolicyEvents, l) networkPolicyEvents = nil } case e := <-in: log.Infof("KubeListener: process(): Got %v", e) switch obj := e.Object.(type) { case *v1beta1.NetworkPolicy: log.Tracef(trace.Inside, "Scheduing network policy action, now scheduled %d actions", len(networkPolicyEvents)) networkPolicyEvents = append(networkPolicyEvents, e) case *v1.Namespace: log.Tracef(trace.Inside, "Processor received namespace") handleNamespaceEvent(e, l) default: log.Errorf("Processor received an event of unkonwn type %s, ignoring object %s", reflect.TypeOf(obj), obj) } case <-done: log.Infof("KubeListener: process(): Got done") return } } }() return }
// Init implements Firewall interface func (i *IPTsaveFirewall) Init(exec utilexec.Executable, store FirewallStore, nc NetConfig) error { log.Infof("In Init()") fwstore := firewallStore{} fwstore.DbStore = store.GetDb() fwstore.mu = store.GetMutex() i.Store = fwstore i.os = exec i.networkConfig = nc // Read current iptables config. output, err := i.os.Exec(iptablesSaveBin, []string{}) if err != nil { log.Infof("In Init(), failed to call iptables-save, %s", err) return err } // Parse iptables-save output. i.CurrentState = &iptsave.IPtables{} i.CurrentState.Parse(bytes.NewReader(output)) // Inirialize desired state filter table. i.DesiredState = &iptsave.IPtables{} i.DesiredState.Tables = append(i.DesiredState.Tables, &iptsave.IPtable{Name: "filter"}) log.Tracef(trace.Inside, "In Init(), iptables rules loaded\n, %s", i.CurrentState.Render()) return nil }
// HandleDefaultPolicy handles isolation flag on a namespace by creating/deleting // default network policy. See http://kubernetes.io/docs/user-guide/networkpolicies/ func HandleDefaultPolicy(o *v1.Namespace, l *KubeListener) { var defaultDeny bool annotationKey := "net.beta.kubernetes.io/networkpolicy" if np, ok := o.ObjectMeta.Annotations[annotationKey]; ok { log.Infof("Handling default policy on a namespace %s, policy is now %s \n", o.ObjectMeta.Name, np) // Annotations are stored in the Annotations map as raw JSON. // So we need to parse it. isolationPolicy := struct { Ingress struct { Isolation string `json:"isolation"` } `json:"ingress"` }{} // TODO change to json.Unmarshal. Stas err := json.NewDecoder(strings.NewReader(np)).Decode(&isolationPolicy) if err != nil { log.Errorf("In HandleDefaultPolicy :: Error decoding annotation %s: %s", annotationKey, err) return } log.Debugf("Decoded to policy: %v", isolationPolicy) defaultDeny = isolationPolicy.Ingress.Isolation == "DefaultDeny" } else { log.Infof("Handling default policy on a namespace, no annotation detected assuming non isolated namespace\n") defaultDeny = false } if defaultDeny { deleteDefaultPolicy(o, l) } else { addDefaultPolicy(o, l) } }
// getConnStrings returns the appropriate GORM connection string for // the given DB. func (dbStore *DbStore) getConnStrings() []string { var connStr []string info := dbStore.Config switch info.Type { case "sqlite3": connStr = append(connStr, info.Database) log.Infof("DB: Connection string: %s", info.Database) default: portStr := fmt.Sprintf(":%d", info.Port) if info.Port == 0 { portStr = ":3306" } connStr = append(connStr, fmt.Sprintf("%s:%s@tcp(%s%s)/%s?parseTime=true", info.Username, info.Password, info.Host, portStr, info.Database)) log.Infof("DB: Connection string: ****:****@tcp(%s%s)/%s?parseTime=true", info.Host, portStr, info.Database) connStr = append(connStr, fmt.Sprintf("%s:%s@unix(/var/run/mysqld/mysqld.sock)/%s?parseTime=true", info.Username, info.Password, info.Database)) log.Infof("DB: Connection string: ****:****@unix(/var/run/mysqld/mysqld.sock))/%s?parseTime=true", info.Database) connStr = append(connStr, fmt.Sprintf("%s:%s@unix(/tmp/mysqld.sock)/%s?parseTime=true", info.Username, info.Password, info.Database)) log.Infof("DB: Connection string: ****:****@unix(/tmp/mysqld.sock))/%s?parseTime=true", info.Database) } return connStr }
// addDefaultPolicy adds the default policy which is to allow // all ingres. func addDefaultPolicy(o *v1.Namespace, l *KubeListener) { var err error // TODO this should be ExternalID, not Name... policyName := getDefaultPolicyName(o) // Before adding the default policy, see if it may already exist. policy := common.Policy{Name: policyName} policyURL, err := l.restClient.GetServiceUrl("policy") if err != nil { log.Errorf("In addDefaultPolicy :: Failed to find policy service: %s\n", err) log.Errorf("In addDefaultPolicy :: Failed to add default policy: %s\n", policyName) return } policyURL = fmt.Sprintf("%s/find/policies/%s", policyURL, policy.Name) err = l.restClient.Get(policyURL, &policy) if err == nil { // An annotation to set isolation off may be issued multiple // times and we already have the default policy caused by that in place. // So we just do not do anything. log.Infof("In addDefaultPolicy :: Policy %s (%d) already exists, ignoring\n", policy.Name, policy.ID) return } // Find tenant, to properly set up policy // TODO This really should be by external ID... tnt, err := l.resolveTenantByName(o.ObjectMeta.Name) if err != nil { log.Infof("In addDefaultPolicy :: Error :: failed to resolve tenant %s \n", err) return } romanaPolicy := &common.Policy{ Direction: common.PolicyDirectionIngress, Name: policyName, // ExternalID: externalID, AppliedTo: []common.Endpoint{{TenantNetworkID: &tnt.NetworkID}}, Ingress: []common.RomanaIngress{ common.RomanaIngress{ Peers: []common.Endpoint{{Peer: common.Wildcard}}, Rules: []common.Rule{{Protocol: common.Wildcard}}, }, }, } err = l.addNetworkPolicy(*romanaPolicy) switch err := err.(type) { default: log.Errorf("In addDefaultPolicy :: Error :: failed to create policy %s: %s\n", policyName, err) case nil: log.Debugf("In addDefaultPolicy: Succesfully created policy %s\n", policyName) case common.HttpError: if err.StatusCode == http.StatusConflict { log.Infof("In addDefaultPolicy ::Policy %s already exists.\n", policyName) } else { log.Errorf("In addDefaultPolicy :: Error :: failed to create policy %s: %s\n", policyName, err) } } }
func (j formMarshaller) Marshal(v interface{}) ([]byte, error) { retval := "" vPtr := reflect.ValueOf(v) vVal := vPtr.Elem() vType := reflect.TypeOf(vVal.Interface()) for i := 0; i < vVal.NumField(); i++ { metaField := vType.Field(i) field := vVal.Field(i) formKey := metaField.Tag.Get("form") if len(retval) > 0 { retval += "&" } retval += formKey + "=" log.Infof("form key of %s is %s\n", metaField.Name, formKey) str := "" if metaField.Type == stringType { str = field.Interface().(string) } else { toString := field.MethodByName("String") log.Infof("Looking for method String on %s: %s\n", field, toString) if reflect.Zero(reflect.TypeOf(toString)) != toString { toStringResult := toString.Call(nil) str = toStringResult[0].String() } else { log.Infof("Ignoring field %s of %s\n", metaField.Name, v) continue } } str = strings.TrimSpace(str) retval += str } return []byte(retval), nil }
func (l *KubeListener) Initialize(client *common.RestClient) error { l.restClient = client // TODO, find a better place to initialize // the translator. Stas. PTranslator.Init(l.restClient, l.segmentLabelName, l.tenantLabelName) tc := PTranslator.GetClient() if tc == nil { log.Critical("Failed to initialize rest client for policy translator.") os.Exit(255) } l.lastEventPerNamespace = make(map[string]uint64) log.Infof("%s: Starting server", l.Name()) nsURL, err := common.CleanURL(fmt.Sprintf("%s/%s/?%s", l.kubeURL, l.namespaceNotificationPath, HttpGetParamWatch)) if err != nil { return err } log.Infof("Starting to listen on %s", nsURL) done := make(chan struct{}) eventc, err := l.nsWatch(done, nsURL) if err != nil { log.Critical("Namespace watcher failed to start", err) os.Exit(255) } // events := l.conductor(nsEvents, done) l.process(eventc, done) ProduceNewPolicyEvents(eventc, done, l) log.Info("All routines started") return nil }
// EnsureRule implements Firewall interface. It schedules given rule for // transition in given state and stores it in firewall store. func (i *IPTsaveFirewall) EnsureRule(rule FirewallRule, opType RuleState) error { log.Infof("In EnsureRule() with firewall rule %s %s", opType.String(), rule.GetBody()) var ruleExists bool // This firewall only manages filtering rules so it only operates // on `filter` table. table := i.DesiredState.TableByName("filter") if table == nil { return fmt.Errorf("In EnsureRule() firewall doesn't have filter table") } // Convert iptables rule from Firewall interface into iptsave.IPrule. tempChain := iptsave.ParseRule(bytes.NewReader([]byte(rule.GetBody()))) ipRule := tempChain.Rules[0] // Ensure that base chain of the rule is defined in desired state. chain := table.ChainByName(tempChain.Name) if chain == nil { table.Chains = append(table.Chains, tempChain) chain = tempChain // we just added a chain with our rule // into the filter table so we know that // target rule is in the table. ruleExists = true } // If we didn't put that rule in the table ourselves yet then // try to find it in existing table. if !ruleExists { ruleExists = chain.RuleInChain(ipRule) } if ruleExists { switch opType { case EnsureAbsent: log.Infof("In EnsureRule - rule %s exists in current state, removing", rule.GetBody()) chain.DeleteRule(ipRule) default: log.Infof("In EnsureRule - nothing to do %s", rule.GetBody()) } } else { log.Infof("In EnsureRule - rule %s doesn't exist is current state, %s", rule.GetBody(), opType.String()) switch opType { case EnsureLast: chain.AppendRule(ipRule) case EnsureFirst: chain.InsertRule(0, ipRule) default: log.Infof("In EnsureRule - nothing to do %s", rule.GetBody()) } } return nil }
// isChainExistByName verifies if given iptables chain exists. // Returns true if chain exists. func (fw *IPtables) isChainExistByName(chainName string) bool { args := []string{"-w", "-L", chainName} output, err := fw.os.Exec(iptablesCmd, args) if err != nil { log.Infof("isChainExist(): iptables -L %s returned %s", chainName, err) return false } log.Infof("isChainExist(): iptables -L %s returned %s", chainName, string(output)) return true }
// syncNetworkPolicies compares a list of kubernetes network policies with romana network policies, // it returns a list of kubernetes policies that don't have corresponding kubernetes network policy for them, // and a list of romana policies that used to represent kubernetes policy but corresponding kubernetes policy is gone. func (l *KubeListener) syncNetworkPolicies(kubePolicies []v1beta1.NetworkPolicy) (kubernetesEvents []Event, romanaPolicies []common.Policy, err error) { log.Infof("In syncNetworkPolicies with %v", kubePolicies) policies, err := getAllPoliciesFunc(l.restClient) if err != nil { return } log.Infof("In syncNetworkPolicies fetched %d romana policies", len(policies)) // Compare kubernetes policies and all romana policies by name. // TODO Coparing by name is fragile should be `external_id == UID`. Stas. // Prepare a list of kubernetes policies that don't have corresponding // romana policy. var found bool accountedRomanaPolicies := make(map[int]bool) for kn, kubePolicy := range kubePolicies { namespacePolicyNamePrefix := fmt.Sprintf("kube.default.") found = false for pn, policy := range policies { fullPolicyName := fmt.Sprintf("%s%s", namespacePolicyNamePrefix, kubePolicy.ObjectMeta.Name) if fullPolicyName == policy.Name { found = true accountedRomanaPolicies[pn] = true break } } if !found { log.Tracef(trace.Inside, "Sync policies detected new kube policy %v", kubePolicies[kn]) kubernetesEvents = append(kubernetesEvents, Event{KubeEventAdded, kubePolicies[kn]}) } } // Delete romana policies that don't have corresponding // kubernetes policy. // Ignore policies that don't have "kube." prefix in the name. for k, _ := range policies { if !strings.HasPrefix(policies[k].Name, "kube.") { log.Tracef(trace.Inside, "Sync policies skipping policy %s since it doesn't match the prefix `kube.`", policies[k].Name) continue } if !accountedRomanaPolicies[k] { log.Infof("Sync policies detected that romana policy %d is obsolete - scheduling for deletion", policies[k].ID) log.Tracef(trace.Inside, "Sync policies detected that romana policy %d is obsolete - scheduling for deletion", policies[k].ID) romanaPolicies = append(romanaPolicies, policies[k]) } } return }
// SetEndpoint implements Firewall interface. It initializes // endpoint dependend values of firewall. func (i *IPTsaveFirewall) SetEndpoint(netif FirewallEndpoint) error { log.Infof("In SetEndpoint() with endpoint <iface=%s, ip=%s, mac=%s>", netif.GetName(), netif.GetIP(), netif.GetMac()) var err error i.interfaceName = netif.GetName() i.u32filter, i.chainPrefix, err = prepareU32Rules(netif.GetIP(), i.networkConfig) if err != nil { return err } // Assemble firewall rules needed to divert traffic // to/from the endpoint. divertFilter := makeDivertRules(netif) log.Tracef(trace.Inside, "In SetEndpoint() after divertFilter with\n%s", divertFilter.RenderFooter()) // compare list of divert rules and list of current rules // make a list of chains filled with divert rules that need // to be created to match current rules. backendFilter := i.CurrentState.TableByName("filter") newChains := iptsave.MergeTables(backendFilter, divertFilter) // schedule divert rules that don't exist yet for installation. newFilter := i.DesiredState.TableByName("filter") newFilter.Chains = append(newFilter.Chains, newChains...) log.Tracef(trace.Inside, "In SetEndpoint after merge\n%s", i.CurrentState.Render()) return err }
// Init calls flag.Parse() and, for now, sets up the // credentials. func (cs *CliState) Init() error { cs.flagSet.Parse(os.Args[1:]) config.SetConfigName(".romana") // name of config file (without extension) config.SetConfigType("yaml") config.AddConfigPath("$HOME") // adding home directory as first search path config.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. err := config.ReadInConfig() if err != nil { switch err := err.(type) { case config.ConfigFileNotFoundError: // For now do nothing case *os.PathError: if err.Error() != "open : no such file or directory" { return err } default: return err } } log.Infof("Using config file: %s", config.ConfigFileUsed()) err = cs.credential.Initialize() return err }
func (n notFoundHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { // TODO answer with a 406 here? accept := request.Header.Get("accept") // Default to JSON. contentType := "application/json" if accept == "*/*" || accept == "" { // Force json if it can take anything. accept = "application/json" } format, err := negotiation.NegotiateAccept(accept, SupportedContentTypes) var marshaller Marshaller defaultMarshaller := ContentTypeMarshallers["application/json"] if err == nil { contentType = format.Value writer.Header().Set("Content-Type", contentType) marshaller = ContentTypeMarshallers[contentType] } // Error in negotiation or marshaller not found. if err != nil || marshaller == nil { // This should never happen... Just in case... log.Infof("No marshaler for [%s] found in %s, %s\n", contentType, ContentTypeMarshallers, ContentTypeMarshallers["application/json"]) writer.WriteHeader(http.StatusUnsupportedMediaType) sct := SupportedContentTypesMessage dataOut, _ := defaultMarshaller.Marshal(sct) writer.Write(dataOut) return } dataOut, _ := marshaller.Marshal(NewError404("URI", request.RequestURI)) writer.Write(dataOut) return }
// CreateDefaultRule creates iptables rule for a chain with the // specified target func (fw *IPtables) CreateDefaultRule(chain int, target string) error { log.Infof("In CreateDefaultRule() %s rules for chain %d", target, chain) chainName := fw.chains[chain].ChainName body := fmt.Sprintf("%s %s %s", chainName, "-j", target) rule := &IPtablesRule{ Body: body, State: setRuleInactive.String(), } // First create rule record in database. err0 := fw.addIPtablesRule(rule) if err0 != nil { log.Error("In CreateDefaultRule() create db record for iptables rule ", rule.GetBody()) return err0 } err1 := fw.EnsureRule(rule, EnsureLast) if err1 != nil { log.Errorf("In CreateDefaultRule() %s rules failed", target) return err1 } // Finally, set 'active' flag in database record. if err2 := fw.Store.switchIPtablesRule(rule, setRuleActive); err2 != nil { log.Error("In CreateDefaultRule() iptables rule created but activation failed ", rule.GetBody()) return err2 } log.Info("In CreateDefaultRule() success") return nil }
// ensureIPtablesChain checks if iptables chain in a desired state. func (fw *IPtables) ensureIPtablesChain(chainName string, opType chainState) error { log.Infof("In ensureIPtablesChain(): %s %s", opType.String(), chainName) log.Tracef(trace.Inside, "In ensureIPtablesChain(): Testing chain ", chainName) exists := fw.isChainExistByName(chainName) log.Tracef(trace.Inside, "In ensureIPtablesChain(): Test for chain %s returned %b", chainName, exists) var iptablesAction string switch opType { case ensureChainExists: if exists { log.Tracef(trace.Inside, "In ensureIPtablesChain(): nothing to do for chain %s", chainName) return nil } else { iptablesAction = "-N" } case ensureChainAbsent: if exists { iptablesAction = "-D" } else { log.Tracef(trace.Inside, "In ensureIPtablesChain(): nothing to do for chain %s", chainName) return nil } } args := []string{iptablesAction, chainName} _, err := fw.os.Exec(iptablesCmd, args) return err }
// ListenAndServe is same as http.ListenAndServe except it returns // the address that will be listened on (which is useful when using // arbitrary ports). // See https://github.com/golang/go/blob/master/src/net/http/server.go func ListenAndServe(svr *http.Server) (*RestServiceInfo, error) { log.Infof("Entering ListenAndServe(%p)", svr) if svr.Addr == "" { svr.Addr = ":0" } ln, err := net.Listen("tcp", svr.Addr) if err != nil { return nil, err } realAddr := ln.Addr().String() channel := make(chan ServiceMessage) l := svr.ErrorLog if l == nil { l = clog.New(os.Stderr, "[negroni] ", 0) } go func() { channel <- Starting l.Printf("ListenAndServe(%p): listening on %s (asked for %s) with configuration %v, handler %v\n", svr, realAddr, svr.Addr, svr, svr.Handler) err := svr.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) if err != nil { log.Criticalf("RestService: Fatal error %v", err) os.Exit(255) } }() return &RestServiceInfo{Address: realAddr, Channel: channel}, nil }
// If the path of request is common.AuthPath, this does nothing, as // the request is for authentication in the first place. Otherwise, // checks token from request. If the token is not valid, returns a // 403 FORBIDDEN status. func (am AuthMiddleware) ServeHTTP(writer http.ResponseWriter, request *http.Request, next http.HandlerFunc) { if request.URL.Path == AuthPath { // Let this one through, no token yet. next(writer, request) return } contentType := writer.Header().Get("Content-Type") marshaller := ContentTypeMarshallers[contentType] if am.PublicKey != nil { f := func(token *jwt.Token) (interface{}, error) { return am.PublicKey, nil } log.Infof("Parsing request for auth token\n") token, err := jwt.ParseFromRequest(request, f) if err != nil { writer.WriteHeader(http.StatusForbidden) httpErr := NewHttpError(http.StatusForbidden, err.Error()) outData, _ := marshaller.Marshal(httpErr) writer.Write(outData) return } if !token.Valid { writer.WriteHeader(http.StatusForbidden) httpErr := NewHttpError(http.StatusForbidden, "Invalid token.") outData, _ := marshaller.Marshal(httpErr) writer.Write(outData) return } context.Set(request, ContextKeyRoles, token.Claims["roles"].([]string)) } next(writer, request) }
// podDownHandler cleans up after pod deleted. func (a *Agent) podDownHandler(input interface{}, ctx common.RestContext) (interface{}, error) { log.Trace(trace.Private, "Agent: Entering podDownHandler()") netReq := input.(*NetworkRequest) netif := netReq.NetIf // We need new firewall instance here to use its Cleanup() // to uninstall firewall rules related to the endpoint. fw, err := firewall.NewFirewall(a.getFirewallType()) if err != nil { return nil, err } err = fw.Init(a.Helper.Executor, a.store, a.networkConfig) if err != nil { return nil, err } err = fw.Cleanup(netif) if err != nil { return nil, err } // Spawn new thread to process the request log.Infof("Agent: Got request for pod teardown %v\n", netReq) return "OK", nil }
// write500 writes out a 500 error based on provided err func write500(writer http.ResponseWriter, m Marshaller, err error) { writer.WriteHeader(http.StatusInternalServerError) httpErr := NewError500(err) // Should never error out - it's a struct we know. outData, _ := m.Marshal(httpErr) log.Infof("Made\n\t%+v\n\tfrom\n\t%+v\n\t%s", httpErr, err, string(outData)) writer.Write(outData) }
// EnsureRule verifies if given iptables rule exists and creates if it's not. func (fw IPtables) EnsureRule(rule FirewallRule, opType RuleState) error { ruleExists := fw.isRuleExist(rule) args := []string{} if ruleExists { switch opType { case EnsureAbsent: args = append(args, "-D") default: log.Info("In EnsureRule - nothing to do ", rule.GetBody()) return nil } } else { switch opType { case EnsureLast: args = append(args, "-A") case EnsureFirst: args = append(args, "-I") default: log.Info("In EnsureRule - nothing to do ", rule.GetBody()) return nil } } args = append(args, strings.Split(rule.GetBody(), " ")...) cmdStr := iptablesCmd + " " + strings.Join(args, " ") out, err := fw.os.Exec(iptablesCmd, args) if err != nil { log.Errorf("[%s]: %s failed for rule %s with error %v, saying [%s]", cmdStr, opType, rule.GetBody(), err, string(out)) } else { if out != nil && len(out) > 0 { log.Infof("%s success %s: [%s]", opType, rule.GetBody(), string(out)) } else { log.Infof("%s success %s", opType, rule.GetBody()) } } return err }
func (t *Translator) Init(client *common.RestClient, segmentLabelName, tenantLabelName string) { t.cacheMu = &sync.Mutex{} t.restClient = client err := t.updateCache() if err == nil { log.Infof("Translator cache updated - have %d tenant entries", len(t.tenantsCache)) } else { log.Errorf("Translator cache update failed, %s", err) } t.segmentLabelName = segmentLabelName t.tenantLabelName = tenantLabelName }
// DbToHttpError produces an appropriate HttpError given an error, if it can // (for example, producing a 409 CONFLICT in case of a unique or primary key // constraint violation). If it cannot, it returns the original error. func DbToHttpError(err error) error { switch err := err.(type) { case sqlite3.Error: if err.Code == sqlite3.ErrConstraint { if err.ExtendedCode == sqlite3.ErrConstraintUnique || err.ExtendedCode == sqlite3.ErrConstraintPrimaryKey { log.Infof("Error: %s", err) return HttpError{StatusCode: http.StatusConflict} } } else if err.Code == sqlite3.ErrCantOpen { log.Infof("Cannot open database file.") return NewError500("Database error.") } log.Infof("DbToHttpError(): Unknown sqlite3 error: %d|%d|%s", err.Code, err.ExtendedCode, err.Error()) return err case *mysql.MySQLError: if err.Number == MySQLUniqueConstraintErrorCode { log.Infof("Error: %s", err) return HttpError{StatusCode: http.StatusConflict} } log.Infof("DbToHttpError(): Unknown MySQL error: %d %s", err.Number, err.Message) return err default: log.Infof("DbToHttpError(): Unknown error: [%T] %+v", err, err) return err } }
// createSchemaSqlite3 creates schema for a sqlite3 db func createSchemaSqlite3(dbStore *DbStore, force bool) error { schemaName := dbStore.Config.Database log.Infof("Entering createSchemaSqlite3() with %s", schemaName) var err error if force { finfo, err := os.Stat(schemaName) exist := finfo != nil || os.IsExist(err) log.Infof("Before attempting to drop %s, exists: %t, stat: [%v] ... [%v]", schemaName, exist, finfo, err) if exist { err = os.Remove(schemaName) if err != nil { return err } } } err = dbStore.Connect() if err != nil { return err } entities := dbStore.ServiceStore.Entities() log.Infof("Creating tables for %v", entities) for _, entity := range entities { log.Infof("sqlite3: Creating table for %T", entity) db := dbStore.Db.CreateTable(entity) if db.Error != nil { return db.Error } } errs := dbStore.Db.GetErrors() log.Infof("sqlite3: Errors: %v", errs) err2 := MakeMultiError(errs) if err2 != nil { return err2 } return dbStore.ServiceStore.CreateSchemaPostProcess() }
// makeRules extracts data from netif and initializes tenant/segment // specific fields of IPtables struct. func (fw *IPtables) makeRules(netif FirewallEndpoint) error { log.Infof("In makeRules() with %s", netif.GetName()) var err error fw.u32filter, fw.chainPrefix, err = fw.prepareU32Rules(netif.GetIP()) if err != nil { // TODO need personalized error here, or even panic return err } fw.interfaceName = netif.GetName() fw.chains = append(fw.chains, IPtablesChain{ BaseChain: "INPUT", Directions: []string{"i"}, ChainName: "ROMANA-INPUT", }) fw.chains = append(fw.chains, IPtablesChain{ BaseChain: "OUTPUT", Directions: []string{"o"}, ChainName: "ROMANA-FORWARD-IN", }) fw.chains = append(fw.chains, IPtablesChain{ BaseChain: "FORWARD", Directions: []string{"i"}, ChainName: "ROMANA-FORWARD-OUT", }) fw.chains = append(fw.chains, IPtablesChain{ BaseChain: "FORWARD", Directions: []string{"o"}, // Using ROMANA-FORWARD-IN second time to capture both // traffic from host to endpoint and // traffic from endpoint to another endpoint. ChainName: "ROMANA-FORWARD-IN", }) log.Infof("In makeRules() created chains %v", fw.chains) return nil }
// setupHooks sets up before and after hooks for each service func setupHooks(routes Routes, hooks []Hook) error { for i, hook := range hooks { if strings.ToLower(hook.When) != "before" && strings.ToLower(hook.When) != "after" { return errors.New(fmt.Sprintf("InitializeService(): Invalid value for when: %s", hook.When)) } m := strings.ToUpper(hook.Method) if m != "POST" && m != "PUT" && m != "GET" && m != "DELETE" && m != "HEAD" { return errors.New(fmt.Sprintf("Invalid method: %s", m)) } found := false for j, _ := range routes { r := &routes[j] if r.Pattern == hook.Pattern && strings.ToUpper(r.Method) == m { found = true r.Hook = &hooks[i] log.Infof("InitializeService(): [%d] Added hook to run %s %s %s %s", j, hook.Executable, hook.When, r.Method, r.Pattern) break } } for i, r := range routes { log.Infof("InitializeService(): Modified route[%d]: %s %s %v", i, r.Method, r.Pattern, r.Hook) } if !found { return errors.New(fmt.Sprintf("No route matching pattern %s and method %s found in %v", hook.Pattern, hook.Method, routes)) } finfo, err := os.Stat(hook.Executable) if err != nil { return errors.New(fmt.Sprintf("Problem with specified executable %s: %v", hook.Executable, err)) } if finfo.Mode().Perm()&0111 == 0 { return errors.New(fmt.Sprintf("%s is not an executable", hook.Executable)) } } return nil }
// ReadConfig parses the configuration file provided and returns // ReadConfig reads config from file to structure func ReadConfig(fname string) (Config, error) { // Created new... config := &Config{} absFname, err := filepath.Abs(fname) if err != nil { return *config, err } if fname != absFname { log.Infof("ReadConfig(): Normalized %s to %s", fname, absFname) fname = absFname } yamlConfig := yamlConfig{} if fname != "" { data, err := ioutil.ReadFile(fname) if err != nil { return *config, err } err = yaml.Unmarshal(data, &yamlConfig) if err != nil { log.Infof("ReadConfig(): Error reading config: %v", err) return *config, err } serviceConfigs := yamlConfig.Services config.Services = make(map[string]ServiceConfig) // Now convert this to map for easier reading... for i := range serviceConfigs { c := serviceConfigs[i] api := Api{Host: c.Api.Host, Port: c.Api.Port, Hooks: c.Api.Hooks} cleanedConfig := cleanupMap(c.Config) commonConfig := CommonConfig{Api: &api, Credential: nil, PublicKey: nil} config.Services[c.Service] = ServiceConfig{Common: commonConfig, ServiceSpecific: cleanedConfig} } return *config, nil } return *config, errors.New("Empty filename.") }
// podUpHandler handles HTTP requests for endpoints provisioning. func (a *Agent) podUpHandler(input interface{}, ctx common.RestContext) (interface{}, error) { log.Trace(trace.Private, "Agent: Entering podUpHandler()") netReq := input.(*NetworkRequest) log.Infof("Agent: Got request for network configuration: %v\n", netReq) // Spawn new thread to process the request // TODO don't know if fork-bombs are possible in go but if they are this // need to be refactored as buffered channel with fixed pool of workers go a.podUpHandlerAsync(*netReq) // TODO I wonder if this should actually return something like a // link to a status of this request which will later get updated // with success or failure -- Greg. return "OK", nil }
// NewRouter creates router for a new service. func newRouter(routes []Route) *mux.Router { router := mux.NewRouter().StrictSlash(true) router.NotFoundHandler = notFoundHandler{} for _, route := range routes { handler := route.Handler if route.Hook != nil { log.Infof("Calling wrapHandler with %s %s %s", route.Method, route.Pattern, route.Hook.Executable) } wrappedHandler := wrapHandler(handler, route) router. Methods(route.Method). Path(route.Pattern). Handler(wrappedHandler) } return router }
// vmUpHandler handles HTTP requests for endpoints provisioning. // Currently tested with Romana ML2 driver. func (a *Agent) vmUpHandler(input interface{}, ctx common.RestContext) (interface{}, error) { // Parse out NetIf form the request netif := input.(*NetIf) log.Infof("Agent: Got interface: Name %s, IP %s Mac %s\n", netif.Name, netif.IP, netif.Mac) // Spawn new thread to process the request // TODO don't know if fork-bombs are possible in go but if they are this // need to be refactored as buffered channel with fixed pool of workers go a.vmUpHandlerAsync(*netif) // TODO I wonder if this should actually return something like a // link to a status of this request which will later get updated // with success or failure -- Greg. return "OK", nil }
// updateCache contacts romana Tenant service, lists // all resources and loads them into memory. func (t *Translator) updateCache() error { log.Info("In updateCache") tenantURL, err := t.restClient.GetServiceUrl("tenant") if err != nil { return TranslatorError{ErrorCacheUpdate, err} } tenants := []tenant.Tenant{} err = t.restClient.Get(tenantURL+"/tenants", &tenants) if err != nil { log.Errorf("updateCache(): Error getting tenant information: %s", err) return TranslatorError{ErrorCacheUpdate, err} } if t.restClient == nil { log.Critical("REST client is nil") os.Exit(255) } // tenants := []tenant.Tenant{} // _ = t.restClient.Find(&tenants, common.FindAll) t.cacheMu.Lock() defer func() { log.Infof("Exiting updateCache with %d tenants", len(t.tenantsCache)) t.cacheMu.Unlock() }() t.tenantsCache = nil for _, ten := range tenants { segments := []tenant.Segment{} fullUrl := fmt.Sprintf("%s/tenants/%d/segments", tenantURL, ten.ID) err = t.restClient.Get(fullUrl, &segments) // ignore 404 error here which means no segments // considered to be a zero segments rather then // an error. if err != nil && !checkHttp404(err) { log.Errorf("updateCache(): Error getting segment information for tenant %d: %s", ten.ID, err) return TranslatorError{ErrorCacheUpdate, err} } t.tenantsCache = append(t.tenantsCache, TenantCacheEntry{ten, segments}) } return nil }