You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@metron.apache.org by nickwallen <gi...@git.apache.org> on 2017/09/08 15:30:04 UTC

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

GitHub user nickwallen opened a pull request:

    https://github.com/apache/metron/pull/740

    METRON-1167 Define Session Specific Global Configuration Values in the REPL

    Many Stellar functions accept configuration values from the Global configuration.  When using the REPL you can load the global configuration values by launching the REPL with the -z option, which loads the global configuration stored in Zookeeper.
    
    The only way to modify the global configuration within the REPL currently is to do the following steps.
    1. Retrieve the global configuration with conf := CONFIG_GET("global")
    2. Alter that global configuration by modifying the JSON contained in the `conf` variable.
    3. Push the new global configuration using CONFIG_PUT("global", conf)
    4. Close and then reopen the REPL.  Without restarting the REPL the new global configuration is not loaded.
    
    I want a way to do this directly in the REPL, without restarting it, and also in a way that does not modify the persisted global configuration in Zookeeper.  I may be monkeying with something the REPL, but I don't want to break one of my live Metron topologies.
    
    ### Test Drive
    
    1. Check-out this PR and build Metron. 
         ```
         mvn clean install -DskipTests -T1C
         ```
    
    1. Then from the root of the Metron source directory, launch the REPL.
        ```
        $ mvn exec:java \
            -Dexec.mainClass="org.apache.metron.stellar.common.shell.StellarShell" \
            -pl metron-stellar/stellar-common/
        ```
    
    1. Then ``%define`, `%undefine`, and `%globals` to your heart's content.
        ```
        [Stellar]>>> %globals
        {}
        [Stellar]>>> %define foo = bar
        [Stellar]>>> %globals
        {foo=bar}
        [Stellar]>>> %define baz=bash
        [Stellar]>>> %globals
        {foo=bar, baz=bash}
        [Stellar]>>> %undefine foo
        [Stellar]>>> %globals
        {baz=bash}
        ```

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/nickwallen/metron METRON-1167

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/metron/pull/740.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #740
    
----
commit dd91135a551a493ae9823db673c485824f2fe20c
Author: Nick Allen <ni...@nickallen.org>
Date:   2017-09-07T22:58:58Z

    METRON-1167 Define Session Specific Global Configuration Values in the REPL

----


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137841201
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    Never mind, calling getOrCreate will put the capability in. I see. Sorry


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    Can't we turn everything passed in into json and use the json patch stuff to "build out' the configuration?  Why not have the globals as a map<string,object> all the time?


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by cestella <gi...@git.apache.org>.
Github user cestella commented on the issue:

    https://github.com/apache/metron/pull/740
  
    yeah, we can definitely have complex types in the global config; that gets serialized as a `Map<String, Object>` and jackson will happily load a map of maps or lists.  The idea originally was that the global config could, for instance, hold static reference data that was super small, which could include maps.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    thanks @cestella.  I am waiting on an answer to the question on other functions that look for the GLOBAL_CONFIG flag.   See above, a couple of times.



---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    What flag am I co-opting?


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    I don't know if you saw my question, and it is hidden now so I'll restate:
    
    What about functions that check for the GLOBAL_ flag, and may make assumptions that do not hold with a non-z partial configuration?
    



---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    > Can't we turn everything passed in into json and use the json patch stuff to "build out' the configuration? Why not have the globals as a map<string,object> all the time?
    
    It still is always a map<string, object>, that has not changed. When I said "How about we just restrict %define to strings only for now.", that just means that a `%define` drops into the map<string, object>, values of strings without trying to interpret the value and create a complex type.
    
    The main itch that I'm trying to scratch here (which is maybe the 80% case?) is to just set a simple property value.
    ```
    %define bootstrap.servers=node1:6667
    KAFKA_GET("indexing", 10)
    ```
    
    If we treat `%define` arguments as JSON (so it behaves just like the `-z`) then it would have to look something like this, which is way more quotes and parens than I'd like to deal with.
    ```
    %define { "bootstrap.servers" : "node1:6667" }
    KAFKA_GET("indexing", 10)
    ```


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    Those options seem to add a bit more complexity than I'd like.  How about we just restrict %define to strings only for now.  If you need to use complex types, then you can still do the "CONFIG_GET, CONFIG_PUT, restart REPL" dance that I described in the PR description.


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137826193
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    I don't understand why we check for capabilities here, but not when setting.  It looks like I can define as much as I want, but only see if the capability is there?  Why do we only guard here?


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137926435
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -287,39 +294,131 @@ private void handleStellar(String expression) {
        * Executes a magic expression.
        * @param rawExpression The expression to execute.
        */
    -  private void handleMagic( String rawExpression) {
    -    String[] expression = rawExpression.trim().split(" ");
    +  private void handleMagic(String rawExpression) {
     
    +    String[] expression = rawExpression.trim().split("\\s+");
         String command = expression[0];
    -    if(MAGIC_FUNCTIONS.equals(command)) {
     
    -      // if '%functions FOO' then show only functions that contain 'FOO'
    -      Predicate<String> nameFilter = (name -> true);
    -      if(expression.length > 1) {
    -        nameFilter = (name -> name.contains(expression[1]));
    -      }
    +    if (MAGIC_FUNCTIONS.equals(command)) {
    +      handleMagicFunctions(expression);
    +
    +    } else if (MAGIC_VARS.equals(command)) {
    +      handleMagicVars();
     
    -      // list available functions
    -      String functions = StreamSupport
    -              .stream(executor.getFunctionResolver().getFunctionInfo().spliterator(), false)
    -              .map(info -> String.format("%s", info.getName()))
    -              .filter(nameFilter)
    -              .sorted()
    -              .collect(Collectors.joining(", "));
    -      writeLine(functions);
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +      handleMagicGlobals();
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_DEFINE.equals(command)) {
    +      handleMagicDefine(rawExpression);
     
    -      // list all variables
    -      executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +    } else if(MAGIC_UNDEFINE.equals(command)) {
    +      handleMagicUndefine(expression);
     
         } else {
           writeLine(ERROR_PROMPT + "undefined magic command: " + rawExpression);
         }
       }
     
       /**
    +   * Handle a magic '%functions'.  Lists all of the variables in-scope.
    +   * @param expression
    +   */
    +  private void handleMagicFunctions(String[] expression) {
    +
    +    // if '%functions FOO' then show only functions that contain 'FOO'
    +    Predicate<String> nameFilter = (name -> true);
    +    if (expression.length > 1) {
    +      nameFilter = (name -> name.contains(expression[1]));
    +    }
    +
    +    // '%functions' -> list all functions in scope
    +    String functions = StreamSupport
    +            .stream(executor.getFunctionResolver().getFunctionInfo().spliterator(), false)
    +            .map(info -> String.format("%s", info.getName()))
    +            .filter(nameFilter)
    +            .sorted()
    +            .collect(Collectors.joining(", "));
    +    writeLine(functions);
    +  }
    +
    +  /**
    +   * Handle a magic '%vars'.  Lists all of the variables in-scope.
    +   */
    +  private void handleMagicVars() {
    +    executor.getVariables()
    +            .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +  }
    +
    +  /**
    +   * Handle a magic '%globals'.  List all of the global configuration values.
    +   */
    +  private void handleMagicGlobals() {
    +    Map<String, Object> globals = getOrCreateGlobalConfig(executor);
    +    writeLine(globals.toString());
    +  }
    +
    +  /**
    +   * Handle a magic '%define var=value'.  Alter the global configuration.
    +   * @param expression The expression passed to %define
    +   */
    +  public void handleMagicDefine(String expression) {
    +
    +    // grab the expression in '%define <assign-expression>'
    +    String assignExpr = StringUtils.trimToEmpty(expression.substring(MAGIC_DEFINE.length()));
    +    if (assignExpr.length() > 0) {
    +
    +      // the expression must be an assignment
    +      if(StellarAssignment.isAssignment(assignExpr)) {
    +        StellarAssignment expr = StellarAssignment.from(assignExpr);
    --- End diff --
    
    Here I leveraged the same assignment code that is used elsewhere in the REPL.


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137864851
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    Nick. If I understand correctly, if there is no ZK, then this turns on the GLOBAL_CONFIG flag, and sets whatever properties.
    
    Is there any risk that other functions that check for GLOBAL_CONFIG can see the flag, but assuming the full config is present, when in this case only what the user has set is present?
    



---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137826444
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    Why wouldn't we getOrCreate here as well?


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    This is a replay of an offline conversation....  
    
    > Sorry for the confusion on my part @ottobackwards . I know much of the innards of Stellar is only documented in the code (if that), so let's level set on that.  
    > 
    > A "StellarExecutor" is responsible for running Stellar code for the REPL.  The executor can maintain additional "Context" that provides resources for the Stellar code that it is executing.  Each of these resources in the "Context" are called "Capabilities".   For example, a Zookeeper Client is available as a Capability called "ZOOKEEPER_CLIENT".  There is also the "GLOBAL_CONFIG" capability that exposes Metron's global configuration to Stellar code.
    > 
    > These capabilities, like the GLOBAL_CONFIG, are exposed to Stellar code in the same way when running either in the REPL or in a topology.  A Stellar function can be written that fails if the GLOBAL_CONFIG is not available.  It can also be written to use acceptable defaults, if a GLOBAL_CONFIG does not exist.
    > 
    > Previously the only way to create the GLOBAL_CONFIG in the REPL, was to have a Zookeeper service running with the Metron config deployed and then launch the REPL with `bin/stellar -z node1:2181".  Without doing that there was no GLOBAL_CONFIG.  Any function that was written to expect a GLOBAL_CONFIG, was not usable in the REPL, unless you launched and configured a Zk instance.
    > 
    > This PR provides the ability to...
    > (1) Create a GLOBAL_CONFIG manually in the REPL without the need for Zk and 
    > (2) Modify a GLOBAL_CONFIG manually within a single session, without modifying Zk.
    > 
    > There really is no such thing as an "incompletely formed" GLOBAL_CONFIG.  The GLOBAL_CONFIG is just a key/value store.  It contains whatever it contains.  But if there is a missing value in the GLOBAL_CONFIG that your function needs, then this change only makes it far simpler to add that missing value to the GLOBAL_CONFIG. 
    > 
    > And this is something you would need per your PR #690.  If you expect to run the REPL disconnected from a Metron cluster, then you need a way to create a GLOBAL_CONFIG without a Zk instance.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    So the GLOBAL_CONFIG is used when setting up stellar in a few places, and used in a couple of functions to determine what they return.  And may be used by other functions in the future both Metron's or UDFs.
    
    I am asking about co-opting this flag, and if we have thought about any unwanted consequences from this now or in the future, based on the intent of the flag.
    
    Is the scope of that flag only the shell?  Will the functions see it? If they do, and they expect a field to be set in the config, but it is not because the shell only set one property that the user did set, what will the behavior be?
    
    We may be able to say "Well, right now non of the functions that depend on that flag and specific properties will be called from the shell".  But what keeps someone from writing a UDF that depends on that flag from breaking in the shell because they don't understand that we do this?



---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    I agree, you are good to go


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137840091
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    Yep, it is prettier this way.  Thanks  @ottobackwards 


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    Yep, you are right.  How could I doubt you?  For your complex type example a %define would load the value as a string, and the -z would load it as a map.  So the behavior is different. But the reason it gets loaded as a map is because it is a map in JSON, not anything to do with Stellar itself.  
    
    So I am a little corn-fused about how to match the same functionality with %define.  I'd have to treat it as JSON?  The other thought I had would be to treat it as a Stellar expression and just execute it, but that would actually be different than `-z`.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by cestella <gi...@git.apache.org>.
Github user cestella commented on the issue:

    https://github.com/apache/metron/pull/740
  
    How would we, say, specify a global config value as a map (e.g. foo={'bar' : 'blah'})?  global config is also exposed as variables stellar in the parser and enrichments, so this could very well be a use-case.  complex global config is also used in the stellar config IIRC.


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by asfgit <gi...@git.apache.org>.
Github user asfgit closed the pull request at:

    https://github.com/apache/metron/pull/740


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    "a bit more complexity than I'd like" may just need to be read as "Nick is lazy", but I'll let you be the judge


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by cestella <gi...@git.apache.org>.
Github user cestella commented on the issue:

    https://github.com/apache/metron/pull/740
  
    so, what happens if we modify a field via `%define` from a stellar shell started with `-z` ?


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    I am +1 on this.
    
    While I think it is confusing to conceptually have a GLOBAL_CONF wrt the zookeeper global.js, good documentation and community feedback from use will get us there.
    
    I think UDF authors, when they 'guard' with the GLOBAL_CONF profile are not just requiring that there **is** any config at all, they really always want the GLOBAL_CONF **AND** some amount of the properties set there. Having them have to do secondary validation of config property presence doesn't seem right.
    
    
    I would like to see a jira for follow up documentation as part of the stellar UDF author's guide.
    
    Thanks for working on this and taking the time to answer my questions @nickwallen 
    
    



---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137841078
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    When would you not get an empty map?  It looks like if you are not using ZK you always get an empty map.  I must be missing something


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    Even if they don't now, I believe that is the intent of the feature


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by cestella <gi...@git.apache.org>.
Github user cestella commented on the issue:

    https://github.com/apache/metron/pull/740
  
    YES!  I love it.  We can create a follow-on for a `-g` option to initialize the global config, but I like this approach.  +1 by inspection, but I want to make sure @ottobackwards is cool with it as well before we go to master.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    "There really is no such thing as an "incompletely formed" GLOBAL_CONFIG. The GLOBAL_CONFIG is just a key/value store. It contains whatever it contains. But if there is a missing value in the GLOBAL_CONFIG that your function needs, then this change only makes it far simpler to add that missing value to the GLOBAL_CONFIG."
    
    Just a clarification.  Let's say the users here are the UDF developer, and the metron user.
    They don't know each other, never met, never talked nothing.  The User just installed 'bob's stellar lib'.
    
    Bob's stellar lib needs one of the properties from the metron global.js to work, and is guarded.
    User just runs the shell without zk and wants to use the function.
    
    It passes the guard, and he can call and use the function, but it blows up because it expects a property to be there, but it is not because it is running like this.
    User not happy, has no idea why it didn't work, has to track everything down...
    
    By the time it get's back to Bob, he makes the point that 'hey, i guard for the config, when do you have a metron config that is not a metron config?  what is that flag for?'



---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by cestella <gi...@git.apache.org>.
Github user cestella commented on the issue:

    https://github.com/apache/metron/pull/740
  
    I think I'd be ok without that capability if we had an ability to pass in a global config as a JSON blob, like we do the initial set of variables.  What do you think?


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by cestella <gi...@git.apache.org>.
Github user cestella commented on the issue:

    https://github.com/apache/metron/pull/740
  
    you could also make `%define nicks_new_global_field := my_complex_field`  That makes somewhat more sense since stellar assignment is `:=` and property assignment is `=`


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    I see this feedback as related to the design/use of global properties in general, versus anything that this PR does.  I'd suggest opening a discuss thread on this IMHO.
    
    Nothing wrong with thinking too far down the road.  Thanks @ottobackwards 
    
    Specific to this PR, I will take the two +1s on this as good enough to merge.  Please hollar, if I am wrong.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    > What about functions that check for the GLOBAL_ flag, and may make assumptions that do not hold with a non-z partial configuration?
    
     I thought I had responded to this, but I must not have.  Can you give an example?  I am not seeing a problem.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    I am not sure I know how else to explain it.


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137841605
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    Yep, exactly.  No worries.  I'm glad you're looking at it closely. 


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    > so, what happens if we modify a field via %define from a stellar shell started with -z ?
    
    If you loaded GLOBAL_CONFIG with -z, then `%define`'d the same value, that value would get overridden in the current REPL session only.  It does not change anything in Zk.  If you restarted your REPL, then the value would go back to what is in Zk.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by cestella <gi...@git.apache.org>.
Github user cestella commented on the issue:

    https://github.com/apache/metron/pull/740
  
    So, one way to do this is to allow users to refer to stellar fields:
    ```
    my_complex_field := { 'blah' : 7 }
    %define nicks_new_global_field=&my_complex_field
    ```
    
    Another option to support this is to just insist that `%define` is a string and you have a `replace_global` that takes a field as an argument and the field contains the new global config (in JSON form) and replaces the global config:
    ```
    new_global_config := SHELL_EDIT()
    %replace_global new_global_config
    ```



---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137838874
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    It is just not strictly needed since if I start out with an empty map and there is no global config in Zk, then we are just left with the empty map, so we're good.  So functionally getOrCreate is not needed here.
    
    That being said, I can see how it would bring a nice sense of symmetry to just use getOrCreate in this case also.  Let me try that out real quick.
    



---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137926399
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarExecutor.java ---
    @@ -203,6 +205,9 @@ public StellarExecutor(String zookeeperUrl, Console console, Properties properti
         index.put("quit", AutoCompleteType.TOKEN);
         index.put(StellarShell.MAGIC_FUNCTIONS, AutoCompleteType.FUNCTION);
         index.put(StellarShell.MAGIC_VARS, AutoCompleteType.FUNCTION);
    +    index.put(StellarShell.MAGIC_GLOBALS, AutoCompleteType.FUNCTION);
    +    index.put(StellarShell.MAGIC_DEFINE, AutoCompleteType.FUNCTION);
    +    index.put(StellarShell.MAGIC_UNDEFINE, AutoCompleteType.FUNCTION);
    --- End diff --
    
    I also made sure the new magics are added to the auto-complete feature.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    Oops.  Maybe I am wrong on the complex type thing.  I just noticed I had quotes around the {}.  Let me try that again, maybe I'm wrong.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    
    I am re-reading through everyone's comments just to make sure I haven't misjudged all the feedback that I have received so far (thanks to all for feedback).  
    
    > you could also make %define nicks_new_global_field := my_complex_field That makes somewhat more sense since stellar assignment is := and property assignment is =
    
    I think I misjudged this one @cestella .  I like this for a number of reasons.
    * This is still very simple for the user.  
    * This is more consistent with the existing assignment construct.
    * This makes it far easier to build complex types for a global %define; its easier to build a Stellar map, than a JSON string where the quotes need escaped in Stellar.
    
    So the simple case becomes this.
    ```
    %define bootstrap.servers: = node1:6667
    ```
    
    And the more complex case becomes this.
    ```
    value := { "foo": "bar" }
    %define bootstrap.servers := value
    ```



---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    - So we need to document what the flag actually means
    - We need UDF writers to understand the flag and how to guard for missing properties
    - Need the users to understand that the functions that require the global config will need THEM to define them somehow to use in this mode, in the function documentation maybe
    - Maybe part of the annotation should be required profile and properties: ?



---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    The latest commit implements the previous suggestion.  I like it... I like it a lot.  See the updated PR description which walks through the syntax.   Let me know what you guys think.


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    Yes, I think it would be useful to pass in a global config as a command line argument.  Maybe something like...
    ```
    bin/stellar -g config/zookeeper/global.json
    ```
    
    I think we could tackle that as a follow-on.



---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by ottobackwards <gi...@git.apache.org>.
Github user ottobackwards commented on the issue:

    https://github.com/apache/metron/pull/740
  
    I might be thinking a little too far down the road, sorry


---

[GitHub] metron pull request #740: METRON-1167 Define Session Specific Global Configu...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on a diff in the pull request:

    https://github.com/apache/metron/pull/740#discussion_r137924431
  
    --- Diff: metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/common/shell/StellarShell.java ---
    @@ -308,17 +315,68 @@ private void handleMagic( String rawExpression) {
                   .collect(Collectors.joining(", "));
           writeLine(functions);
     
    -    } else if(MAGIC_VARS.equals(command)) {
    +    } else if (MAGIC_VARS.equals(command)) {
     
    -      // list all variables
    +      // '%vars' -> list all variables in scope
           executor.getVariables()
    -              .forEach((k,v) -> writeLine(String.format("%s = %s", k, v)));
    +              .forEach((k, v) -> writeLine(String.format("%s = %s", k, v)));
    +
    +    } else if (MAGIC_GLOBALS.equals(command)) {
    +
    +      // '%globals' -> list all globals in scope
    +      Map<String, Object> globals = Collections.emptyMap();
    --- End diff --
    
    I do not see a problem here.  Functions need whatever GLOBAL_CONFIG settings they need.  This PR does not make it harder or less likely for functions to get the values they need.  This PR makes it easier for a user to provide the settings, or alter the settings that a function needs.  IMHO


---

[GitHub] metron issue #740: METRON-1167 Define Session Specific Global Configuration ...

Posted by nickwallen <gi...@git.apache.org>.
Github user nickwallen commented on the issue:

    https://github.com/apache/metron/pull/740
  
    And in terms of the complex types I can see the use case definitely.  In terms of the REPL and the changes in this PR, a `%define` does the same as when GLOBAL_CONFIG gets created with a `-z` for complex types.  In either case, the complex type gets loaded as a string. 
    
    For example, I launched Full Dev and created a GLOBAL_CONFIG that looks-like this.
    ```
    {
        ...
        "foo": "{'bar' : 'blah'}"
    }
    ```
    I then launched the REPL in a debug session with a -z.  The value for the key "foo" is a string.



---