Inline... Sent from my iPhone
> On Feb 23, 2018, at 4:05 PM, Leschke, Scott <[email protected]> wrote: > > Well, the ConfigurationAdmin.createFactoryConfiguration method call works in > the version of ConfigurationAdmin that gets installed into Karaf 4.2M2, ie. a > service gets created and is activated. If that's not what you're referring > to, then I guess I'm misunderstanding. That has always worked:-) however it generates a new pid for the configuration and you have no control over it. In R7 you can specify the pid. I think what is happening to you is that the ca call is generating a configuration with one pid, then you write it to a .cfg file and file install reads it and generates a new configuration with a different pid. A future R7 fileinstall ought to be able to determine that you only intend one configuration and update it instead. I’m not very familiar with fileinstall so there might be a proprietary non-spec way to do that already; if there is I don’t know about it. > > I currently only have 1 instance and it's unlikely I'll ever go to a > multi-instance setup. If I ever do go to a such an architecture, the service > being created would only apply to a single instance and the service would be > specific to a team who is associated with the instance. In that case, yes I > imagine that there would be one instance that acted as a manager for the > others. More likely, each team would get a separate instance to use in their > own VM thereby keeping things pretty much like they are now. > > I'd have to check to be sure, but I think configuration changes are already > written out to .cfg files now. Seems to me that you can make updates to a > configuration via the Karaf console and they end up in the associated .cfg. > My recollection is that it was even careful to not mess up the formatting of > the .cfg. I thought I remembered something like that, but I’ve never known exactly what it does or where the change detection happens. David Jencks > > Thanks for the help. I appreciate the input. > > Regards, > > Scott > > -----Original Message----- > From: David Jencks [mailto:[email protected]] > Sent: Friday, February 23, 2018 5:14 PM > To: [email protected] > Subject: Re: On another topic: Creating services programatically again > > Nothing R7 is released yet, the specs aren’t final, so I doubt very much that > karaf implements any of it. > > I don’t think you’ve considered very many ramifications of what you’re > proposing. In my experience an osgi web server has its port and interface > configured via config admin, so you aren’t going to be able to have two > instances with the same set of configurations. Therefore IMO having a CA > implementation that somehow uses a shared persistence location isn’t going to > be useful, ignoring whether it’s spec compliant or not (I think not). > > If all of your instances have the same services running on them, then you’d > need all of them to get the stimulus to create the factory configuration, or > they will respond differently; with a shared fileinstall directory you get > the behavior you have now, where one instance gets 2 copies of the service > and the others presumably get one, or without the shared fileinstall you get > one or two services on one instance and none on the others. > > If one of your instances (or a separate process) is acting as a management > agent for config admin, then that has to give all the instances the same > stimulus. I’m suggesting that since the stimulus for all the other instances > is fileinstall noticing the new .cfg file, you can use that for the instance > that is acting as the management agent as well. Note that config admin is > asynchronous, so at best the delay is shorter if you create the config in > code rather than letting fileinstall find it. > > There might possibly be a way to configure fileinstall to detect > configuration changes and write them back out, but when I’ve thought that > class of approaches to configuration management I’ve decided the behavior is > too hard to reason about for it to be a plausible solution to anything except > making an unusable system. Other people might have different points of view. > > david jencks > >> On Feb 23, 2018, at 1:49 PM, Leschke, Scott <[email protected]> wrote: >> >> The fundamental question is: >> >> What is the best way to create service instances (from a factory component) >> programmatically and store the associated configurations such that they >> persist across installations/upgrades of the platform, preferably using the >> facilities of the platform itself (ie. no DB). >> Preferably, default configuration values are defined in a single location, >> code or file, if possible. >> >> It would seem that at the moment at least, you probably need to lead by >> writing the .cfg file and just deal with the FIleInstall delay even though >> it seems to me that using ConfigurationAdmin.createFactoryConfiguration >> would be the preferred approach. >> >> Scott >> >> -----Original Message----- >> From: Leschke, Scott [mailto:[email protected]] >> Sent: Friday, February 23, 2018 3:14 PM >> To: [email protected] >> Subject: RE: On another topic: Creating services programatically again >> >> I should have clarified that this is running on Karaf 4.2 M2 so I suppose >> that's R7. The only issue with writing the .cfg myself and relying on Felix >> FileInstall to do its thing is that I really didn't want to have to wait for >> FIleInstall to hit its poll interval since the UI needs to update the >> display with the new service. >> >> I have to wait for the service to get created either way but if I create the >> configuration first I can look up the associated service by its >> configuration PID. It would be if you could have the ConfigurationAdmin >> service write a .cfg file at the location of your choosing but that doesn't >> seem to be the case. >> >> Scott >> >> -----Original Message----- >> From: David Jencks [mailto:[email protected]] >> Sent: Friday, February 23, 2018 2:57 PM >> To: [email protected] >> Subject: Re: On another topic: Creating services programatically again >> >> I’m not sure what all of your code is doing. However, pre R7 you can’t >> specify the pid of a factory configuration. You might get the desired result >> by, on only one karaf instance, writing the .cfg file without creating a >> factory configuration yourself. >> >> David Jencks >> >> Sent from my iPhone >> >>> On Feb 23, 2018, at 11:59 AM, Leschke, Scott <[email protected]> wrote: >>> >>> That should have read "a service from a factory". To clarify, I have a >>> component that is a factory (component), I create a new instance of the >>> configuration and service using cfgAdmin.createFactoryConfiguration as >>> shown below. I have a single Karaf instance but if I had multiple, since >>> my hierarchy is outside of the Karaf installation, I think they would all >>> just look at the same folder structure. >>> >>> My experience that Karaf DOES NOT write a .cfg file when a configuration is >>> created. If it wrote a file to the location given by >>> "felix.fileinstall.filename", this would solve my problem. >>> >>> private void createConfig(String cpid, String dir, String name, >>> Map<String,Object> props) >>> throws Exception >>> { >>> Configuration conf = >>> parent.cfgAdmin.createFactoryConfiguration(cpid, "?"); >>> >>> dir = (dir.endsWith("/") ? dir : dir + '/'); >>> name = name.replaceAll(" ", "_").toLowerCase(); >>> File cfg = new File(dir + cpid + '-' + name + ".cfg"); >>> >>> Dictionary<String,Object> confProps = toDictionary(props); >>> confProps.put("felix.fileinstall.filename", >>> cfg.toURI().toString()); >>> >>> try >>> { >>> conf.update(confProps); >>> >>> // Get the properties for the new service object >>> props = getProps(conf.getPid()); >>> >>> // Create .cfg file with initial property set >>> ITemplate tmp = parent.templateMgr.getTemplate( >>> configTemplates.get(cpid) ); >>> tmp.bind("cfg", props); >>> >>> try (FileLineWriter w = new FileLineWriter(cfg)) >>> { >>> w.putLine(tmp.render()); >>> } >>> } >>> catch (Exception e) >>> { >>> cfg.delete(); >>> conf.delete(); >>> throw e; >>> } >>> } >>> >>> -----Original Message----- >>> From: David Jencks [mailto:[email protected]] >>> Sent: Friday, February 23, 2018 12:23 PM >>> To: [email protected] >>> Subject: Re: On another topic: Creating services programatically >>> again >>> >>> What do you mean by “create instances of service from a factory” and how >>> would doing this result in a configuration at all? >>> How are you proposing to replicate the configuration or .cfg file across >>> multiple karaf instances? >>> >>> I’m not sure if or when karaf writes out a .cfg for a ca configuration >>> created through the ca api, but doing both of creating a configuration and >>> writing out a .cfg file is pretty sure to result in 2 instances, at least >>> until the r7 ca changes let you specify the pid of a factory configuration. >>> >>> David Jencks >>> >>> Sent from my iPhone >>> >>>> On Feb 23, 2018, at 9:20 AM, Leschke, Scott <[email protected]> wrote: >>>> >>>> That's exactly what I'm currently doing but I want to create instances of >>>> service from a factory and write the resulting configuration to .cfg. I >>>> need to do this so that I can save the configurations across Karaf >>>> installs. My app hierarchy resides outside of the Karaf installation so >>>> this works well. Unfortunately, the code I show below gives me two >>>> separate service instances. >>>> >>>> Scott >>>> >>>> -----Original Message----- >>>> From: David Jencks [mailto:[email protected]] >>>> Sent: Friday, February 23, 2018 11:03 AM >>>> To: [email protected] >>>> Subject: Re: On another topic: Creating services programatically >>>> again >>>> >>>> Rather than using a relatively low level api such as ManagedServiceFactory >>>> I’d suggest considering a ds component with configuration required and >>>> supplying it with factory configurations to get multiple instances. By >>>> using a configuration annotation you can have the configuration injected >>>> in a typed form and you can supply default values for any keys not present >>>> in the factory configuration. >>>> >>>> David Jencks >>>> >>>> Sent from my iPhone >>>> >>>>> On Feb 23, 2018, at 6:32 AM, Leschke, Scott <[email protected]> wrote: >>>>> >>>>> OK, that sounds like it may be a good approach. Could you point me to >>>>> the Decanter code as a reference? >>>>> >>>>> Thanks, >>>>> >>>>> Scott >>>>> >>>>> -----Original Message----- >>>>> From: Jean-Baptiste Onofré [mailto:[email protected]] >>>>> Sent: Thursday, February 22, 2018 9:53 PM >>>>> To: [email protected] >>>>> Subject: Re: On another topic: Creating services programatically >>>>> again >>>>> >>>>> Hi Scott, >>>>> >>>>> Service Managed Factory is the other way around: you start from the cfg >>>>> file, then the service is created. The content of the file can be default >>>>> or whatever, it doesn't matter. >>>>> >>>>> Basically, you would have: >>>>> >>>>> etc/org.scott.foo-one.cfg >>>>> etc/org.scott.foo-two.cfg >>>>> etc/org.scott.foo-three.cfg >>>>> >>>>> with the corresponding service for each cfg file. If you create >>>>> etc/org.scott.foo-four.cfg, then, automatically, you will have a new >>>>> corresponding service created. >>>>> >>>>> For instance, it's what we are using in Decanter for the JMX collector: >>>>> you can create a new JMX collector "on the fly", just adding a new >>>>> etc/org.apache.karaf.decanter.collector.jmx-foobar.cfg file. >>>>> >>>>> Regards >>>>> JB >>>>> >>>>>> On 02/23/2018 04:47 AM, Leschke, Scott wrote: >>>>>> Thanks JB, >>>>>> >>>>>> Initially, the .cfg would be populated almost entirely with the defaults >>>>>> the service receives using a configuration type so the idea is that the >>>>>> service creation needs to come first so that the service can be used to >>>>>> get the values to write the .cfg. >>>>>> >>>>>> Is there a way to get those value without actually having a service >>>>>> instance or hard-coding them? >>>>>> >>>>>> Scott >>>>>> >>>>>> -----Original Message----- >>>>>> From: Jean-Baptiste Onofré [mailto:[email protected]] >>>>>> Sent: Thursday, February 22, 2018 9:38 PM >>>>>> To: [email protected] >>>>>> Subject: Re: On another topic: Creating services programatically >>>>>> again >>>>>> >>>>>> Hi Scott, >>>>>> >>>>>> why don't use a managed service factory ? >>>>>> >>>>>> It would automatically create a service based on a cfg. So for your >>>>>> user, he creates the cfg file, and then, automatically, the >>>>>> corresponding service is created. >>>>>> >>>>>> Thoughts ? >>>>>> >>>>>> Regards >>>>>> JB >>>>>> >>>>>>> On 02/22/2018 09:18 PM, Leschke, Scott wrote: >>>>>>> As I mentioned a few weeks ago, I'm trying to create a service >>>>>>> instance programmatically and write the associated .cfg file for it. >>>>>>> Based on feedback I got, I create the following method. >>>>>>> >>>>>>> >>>>>>> >>>>>>> The goal is to create the service instance and then get its >>>>>>> configuration which at this point will mostly be the defaults >>>>>>> that it receives in its configuration type (hence my previous >>>>>>> post). It /appears/ to work, except what is really happening is >>>>>>> that I get two services. One is created by >>>>>>> createFactoryConfguration call and the other by Felix FileInstall after >>>>>>> the .cfg file is written. >>>>>>> >>>>>>> >>>>>>> >>>>>>> Actually I'm a bit surprised that placeholder .cfg file isn't >>>>>>> created if property /felix.fileinstall.filename/is defined, as I >>>>>>> think that would solve this problem, but perhaps there's another way? >>>>>>> >>>>>>> >>>>>>> >>>>>>> Thoughts? >>>>>>> >>>>>>> * * >>>>>>> >>>>>>> * * >>>>>>> >>>>>>> *private**void* createConfig(String cpid, String dir, String >>>>>>> name, Map<String,Object> props) >>>>>>> >>>>>>> *throws* Exception >>>>>>> >>>>>>> { >>>>>>> >>>>>>> Configuration conf = >>>>>>> parent.cfgAdmin.createFactoryConfiguration(cpid, "?"); >>>>>>> >>>>>>> >>>>>>> >>>>>>> dir = (dir.endsWith("/") ? dir : dir + '/'); >>>>>>> >>>>>>> name = name.replaceAll(" ", "_").toLowerCase(); >>>>>>> >>>>>>> File cfg = *new* File(dir + cpid + '-' + name + ".cfg"); >>>>>>> >>>>>>> >>>>>>> >>>>>>> Dictionary<String,Object> confProps = toDictionary(props); >>>>>>> >>>>>>> confProps.put("felix.fileinstall.filename", >>>>>>> cfg.toURI().toString()); >>>>>>> >>>>>>> >>>>>>> >>>>>>> *try* >>>>>>> >>>>>>> { >>>>>>> >>>>>>> conf.update(confProps); >>>>>>> >>>>>>> >>>>>>> >>>>>>> // Get the properties for the new service object >>>>>>> >>>>>>> props = getProps(conf.getPid()); >>>>>>> >>>>>>> >>>>>>> >>>>>>> // Create .cfg file with initial property set >>>>>>> >>>>>>> ITemplate tmp = parent.templateMgr.getTemplate( >>>>>>> configTemplates.get(cpid) ); >>>>>>> >>>>>>> tmp.bind("cfg", props); >>>>>>> >>>>>>> >>>>>>> >>>>>>> *try* (FileLineWriter w = *new* FileLineWriter(cfg)) >>>>>>> >>>>>>> { >>>>>>> >>>>>>> w.putLine(tmp.render()); >>>>>>> >>>>>>> } >>>>>>> >>>>>>> } >>>>>>> >>>>>>> *catch* (Exception e) >>>>>>> >>>>>>> { >>>>>>> >>>>>>> cfg.delete(); >>>>>>> >>>>>>> conf.delete(); >>>>>>> >>>>>>> *throw* e; >>>>>>> >>>>>>> } >>>>>>> >>>>>>> } >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>>> -- >>>>>> Jean-Baptiste Onofré >>>>>> [email protected] >>>>>> http://blog.nanthrax.net >>>>>> Talend - http://www.talend.com >>>>>> >>>>> >>>>> -- >>>>> Jean-Baptiste Onofré >>>>> [email protected] >>>>> http://blog.nanthrax.net >>>>> Talend - http://www.talend.com >
