[ http://issues.apache.org/jira/browse/GERONIMO-1207?page=all ] Aaron Mulder resolved GERONIMO-1207: ------------------------------------
Resolution: Fixed Assign To: Aaron Mulder Fixed in revision 355267. The change is pretty much: Previously, calling a "stop" function (deploy tool, console, etc.) on a configuration meant it was stopped and unloaded. However, the kernel was still aware of it (it was listed in the configuration list view, deployer list-modules, etc.). The loadRecursive function automatically bailed on any configuration that the kernel was aware of (it did a name query to list loaded configurations). The problem is that if you stop and unload a configuration, the kernel is still aware of it, and therefore loadRecursive would never load it again, and it caused this bug. I changed loadRecursive to only ignore configurations that were actually running. The basis for ignoring something is essentially "if it is running, we know it and all its dependencies must be loaded and running therefore we don't need to consider it further". So now, if a configuraiton is present and not loaded, or present and loaded but not running, loadRecursive will still process it (but not actually load it again if it's already loaded, just check its parents and stuff). Now we can stop and unload a module and then later call loadRecursive on it or a child of it and everything works properly. > Dependency / Lifecycle Woes > --------------------------- > > Key: GERONIMO-1207 > URL: http://issues.apache.org/jira/browse/GERONIMO-1207 > Project: Geronimo > Type: Bug > Components: kernel, console > Versions: 1.0-M5 > Reporter: Aaron Mulder > Assignee: Aaron Mulder > Priority: Critical > Fix For: 1.0 > > 1) Create a database pool > 2) Create a SQL security realm with the database pool as a parent > 3) Verify that both are in the running state > 4) Stop the database pool > 5) Verify that both are in the stopped state > 6) Using the console "System Modules", start the security realm -- produces > all kinds of exceptions > 7) Now security realm is in the "starting" state, database pool is stopped > 8) Starting the database pool does not get the security realm out of the > "starting" state, though if you're bold with URL hacking you can start it > again and it will start. > I think that step 6 should either start both modules or leave both in the > stopped state. Being stuck in the "starting" state is terrible -- at least > if it won't automatically recover to the "running" state when the missing > dependencies come online. > Here's the stack traces from step 6. > javax.portlet.PortletException: Configuration not found > at > org.apache.geronimo.console.configmanager.ConfigManagerPortlet.processAction(ConfigManagerPortlet.java:131) > at > org.apache.pluto.core.PortletServlet.dispatch(PortletServlet.java:229) > at org.apache.pluto.core.PortletServlet.doGet(PortletServlet.java:158) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.apache.pluto.core.PortletServlet.service(PortletServlet.java:153) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at org.mortbay.jetty.servlet.Dispatcher.dispatch(Dispatcher.java:277) > at org.mortbay.jetty.servlet.Dispatcher.include(Dispatcher.java:163) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.invoke(PortletInvokerImpl.java:120) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.action(PortletInvokerImpl.java:68) > at > org.apache.pluto.PortletContainerImpl.processPortletAction(PortletContainerImpl.java:164) > at > org.apache.pluto.portalImpl.core.PortletContainerWrapperImpl.processPortletAction(PortletContainerWrapperImpl.java:82) > at org.apache.pluto.portalImpl.Servlet.doGet(Servlet.java:227) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at > org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:568) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1565) > at > org.mortbay.jetty.servlet.WebApplicationContext.handle(WebApplicationContext.java:633) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1517) > at org.mortbay.http.HttpServer.service(HttpServer.java:954) > at org.mortbay.http.HttpConnection.service(HttpConnection.java:816) > at org.mortbay.http.HttpConnection.handleNext(HttpConnection.java:983) > at org.mortbay.http.HttpConnection.handle(HttpConnection.java:833) > at > org.mortbay.http.SocketListener.handleConnection(SocketListener.java:244) > at org.mortbay.util.ThreadedServer.handle(ThreadedServer.java:357) > at org.mortbay.util.ThreadPool$PoolThread.run(ThreadPool.java:534) > Caused by: org.apache.geronimo.kernel.config.InvalidConfigException: Could > not extract gbean data from configuration > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:130) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl$$FastClassByCGLIB$$fbed85d2.invoke(<generated>) > at net.sf.cglib.reflect.FastMethod.invoke(FastMethod.java:53) > at > org.apache.geronimo.gbean.runtime.FastMethodInvoker.invoke(FastMethodInvoker.java:38) > at > org.apache.geronimo.gbean.runtime.GBeanOperation.invoke(GBeanOperation.java:118) > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:800) > at > org.apache.geronimo.gbean.runtime.RawInvoker.invoke(RawInvoker.java:57) > at > org.apache.geronimo.kernel.basic.RawOperationInvoker.invoke(RawOperationInvoker.java:36) > at > org.apache.geronimo.kernel.basic.ProxyMethodInterceptor.intercept(ProxyMethodInterceptor.java:96) > at > org.apache.geronimo.kernel.config.ConfigurationManager$$EnhancerByCGLIB$$82cb3e95.loadGBeans(<generated>) > at > org.apache.geronimo.console.configmanager.ConfigManagerPortlet.processAction(ConfigManagerPortlet.java:109) > ... 37 more > Caused by: java.lang.IllegalStateException: Operations can only be invoke > while the GBean is running: geronimo.config:name="SecurityRealmPostgresPool" > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:833) > at > org.apache.geronimo.kernel.basic.BasicKernel.invoke(BasicKernel.java:180) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:128) > ... 47 more > Nested Exception is > org.apache.geronimo.kernel.config.InvalidConfigException: Could not extract > gbean data from configuration > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:130) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl$$FastClassByCGLIB$$fbed85d2.invoke(<generated>) > at net.sf.cglib.reflect.FastMethod.invoke(FastMethod.java:53) > at > org.apache.geronimo.gbean.runtime.FastMethodInvoker.invoke(FastMethodInvoker.java:38) > at > org.apache.geronimo.gbean.runtime.GBeanOperation.invoke(GBeanOperation.java:118) > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:800) > at > org.apache.geronimo.gbean.runtime.RawInvoker.invoke(RawInvoker.java:57) > at > org.apache.geronimo.kernel.basic.RawOperationInvoker.invoke(RawOperationInvoker.java:36) > at > org.apache.geronimo.kernel.basic.ProxyMethodInterceptor.intercept(ProxyMethodInterceptor.java:96) > at > org.apache.geronimo.kernel.config.ConfigurationManager$$EnhancerByCGLIB$$82cb3e95.loadGBeans(<generated>) > at > org.apache.geronimo.console.configmanager.ConfigManagerPortlet.processAction(ConfigManagerPortlet.java:109) > at > org.apache.pluto.core.PortletServlet.dispatch(PortletServlet.java:229) > at org.apache.pluto.core.PortletServlet.doGet(PortletServlet.java:158) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.apache.pluto.core.PortletServlet.service(PortletServlet.java:153) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at org.mortbay.jetty.servlet.Dispatcher.dispatch(Dispatcher.java:277) > at org.mortbay.jetty.servlet.Dispatcher.include(Dispatcher.java:163) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.invoke(PortletInvokerImpl.java:120) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.action(PortletInvokerImpl.java:68) > at > org.apache.pluto.PortletContainerImpl.processPortletAction(PortletContainerImpl.java:164) > at > org.apache.pluto.portalImpl.core.PortletContainerWrapperImpl.processPortletAction(PortletContainerWrapperImpl.java:82) > at org.apache.pluto.portalImpl.Servlet.doGet(Servlet.java:227) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at > org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:568) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1565) > at > org.mortbay.jetty.servlet.WebApplicationContext.handle(WebApplicationContext.java:633) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1517) > at org.mortbay.http.HttpServer.service(HttpServer.java:954) > at org.mortbay.http.HttpConnection.service(HttpConnection.java:816) > at org.mortbay.http.HttpConnection.handleNext(HttpConnection.java:983) > at org.mortbay.http.HttpConnection.handle(HttpConnection.java:833) > at > org.mortbay.http.SocketListener.handleConnection(SocketListener.java:244) > at org.mortbay.util.ThreadedServer.handle(ThreadedServer.java:357) > at org.mortbay.util.ThreadPool$PoolThread.run(ThreadPool.java:534) > Caused by: java.lang.IllegalStateException: Operations can only be invoke > while the GBean is running: geronimo.config:name="SecurityRealmPostgresPool" > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:833) > at > org.apache.geronimo.kernel.basic.BasicKernel.invoke(BasicKernel.java:180) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:128) > ... 47 more > 02:46:07,301 ERROR [Servlet] Exception caught: > javax.portlet.PortletException: Configuration not found > at > org.apache.geronimo.console.configmanager.ConfigManagerPortlet.processAction(ConfigManagerPortlet.java:131) > at > org.apache.pluto.core.PortletServlet.dispatch(PortletServlet.java:229) > at org.apache.pluto.core.PortletServlet.doGet(PortletServlet.java:158) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.apache.pluto.core.PortletServlet.service(PortletServlet.java:153) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at org.mortbay.jetty.servlet.Dispatcher.dispatch(Dispatcher.java:277) > at org.mortbay.jetty.servlet.Dispatcher.include(Dispatcher.java:163) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.invoke(PortletInvokerImpl.java:120) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.action(PortletInvokerImpl.java:68) > at > org.apache.pluto.PortletContainerImpl.processPortletAction(PortletContainerImpl.java:164) > at > org.apache.pluto.portalImpl.core.PortletContainerWrapperImpl.processPortletAction(PortletContainerWrapperImpl.java:82) > at org.apache.pluto.portalImpl.Servlet.doGet(Servlet.java:227) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at > org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:568) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1565) > at > org.mortbay.jetty.servlet.WebApplicationContext.handle(WebApplicationContext.java:633) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1517) > at org.mortbay.http.HttpServer.service(HttpServer.java:954) > at org.mortbay.http.HttpConnection.service(HttpConnection.java:816) > at org.mortbay.http.HttpConnection.handleNext(HttpConnection.java:983) > at org.mortbay.http.HttpConnection.handle(HttpConnection.java:833) > at > org.mortbay.http.SocketListener.handleConnection(SocketListener.java:244) > at org.mortbay.util.ThreadedServer.handle(ThreadedServer.java:357) > at org.mortbay.util.ThreadPool$PoolThread.run(ThreadPool.java:534) > Caused by: org.apache.geronimo.kernel.config.InvalidConfigException: Could > not extract gbean data from configuration > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:130) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl$$FastClassByCGLIB$$fbed85d2.invoke(<generated>) > at net.sf.cglib.reflect.FastMethod.invoke(FastMethod.java:53) > at > org.apache.geronimo.gbean.runtime.FastMethodInvoker.invoke(FastMethodInvoker.java:38) > at > org.apache.geronimo.gbean.runtime.GBeanOperation.invoke(GBeanOperation.java:118) > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:800) > at > org.apache.geronimo.gbean.runtime.RawInvoker.invoke(RawInvoker.java:57) > at > org.apache.geronimo.kernel.basic.RawOperationInvoker.invoke(RawOperationInvoker.java:36) > at > org.apache.geronimo.kernel.basic.ProxyMethodInterceptor.intercept(ProxyMethodInterceptor.java:96) > at > org.apache.geronimo.kernel.config.ConfigurationManager$$EnhancerByCGLIB$$82cb3e95.loadGBeans(<generated>) > at > org.apache.geronimo.console.configmanager.ConfigManagerPortlet.processAction(ConfigManagerPortlet.java:109) > ... 37 more > Caused by: java.lang.IllegalStateException: Operations can only be invoke > while the GBean is running: geronimo.config:name="SecurityRealmPostgresPool" > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:833) > at > org.apache.geronimo.kernel.basic.BasicKernel.invoke(BasicKernel.java:180) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:128) > ... 47 more > Nested Exception is > org.apache.geronimo.kernel.config.InvalidConfigException: Could not extract > gbean data from configuration > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:130) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl$$FastClassByCGLIB$$fbed85d2.invoke(<generated>) > at net.sf.cglib.reflect.FastMethod.invoke(FastMethod.java:53) > at > org.apache.geronimo.gbean.runtime.FastMethodInvoker.invoke(FastMethodInvoker.java:38) > at > org.apache.geronimo.gbean.runtime.GBeanOperation.invoke(GBeanOperation.java:118) > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:800) > at > org.apache.geronimo.gbean.runtime.RawInvoker.invoke(RawInvoker.java:57) > at > org.apache.geronimo.kernel.basic.RawOperationInvoker.invoke(RawOperationInvoker.java:36) > at > org.apache.geronimo.kernel.basic.ProxyMethodInterceptor.intercept(ProxyMethodInterceptor.java:96) > at > org.apache.geronimo.kernel.config.ConfigurationManager$$EnhancerByCGLIB$$82cb3e95.loadGBeans(<generated>) > at > org.apache.geronimo.console.configmanager.ConfigManagerPortlet.processAction(ConfigManagerPortlet.java:109) > at > org.apache.pluto.core.PortletServlet.dispatch(PortletServlet.java:229) > at org.apache.pluto.core.PortletServlet.doGet(PortletServlet.java:158) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.apache.pluto.core.PortletServlet.service(PortletServlet.java:153) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at org.mortbay.jetty.servlet.Dispatcher.dispatch(Dispatcher.java:277) > at org.mortbay.jetty.servlet.Dispatcher.include(Dispatcher.java:163) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.invoke(PortletInvokerImpl.java:120) > at > org.apache.pluto.invoker.impl.PortletInvokerImpl.action(PortletInvokerImpl.java:68) > at > org.apache.pluto.PortletContainerImpl.processPortletAction(PortletContainerImpl.java:164) > at > org.apache.pluto.portalImpl.core.PortletContainerWrapperImpl.processPortletAction(PortletContainerWrapperImpl.java:82) > at org.apache.pluto.portalImpl.Servlet.doGet(Servlet.java:227) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:595) > at javax.servlet.http.HttpServlet.service(HttpServlet.java:688) > at > org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:428) > at > org.apache.geronimo.jetty.JettyServletHolder.handle(JettyServletHolder.java:99) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:830) > at > org.mortbay.jetty.servlet.JSR154Filter.doFilter(JSR154Filter.java:171) > at > org.mortbay.jetty.servlet.WebApplicationHandler$CachedChain.doFilter(WebApplicationHandler.java:821) > at > org.mortbay.jetty.servlet.WebApplicationHandler.dispatch(WebApplicationHandler.java:471) > at > org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:568) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1565) > at > org.mortbay.jetty.servlet.WebApplicationContext.handle(WebApplicationContext.java:633) > at org.mortbay.http.HttpContext.handle(HttpContext.java:1517) > at org.mortbay.http.HttpServer.service(HttpServer.java:954) > at org.mortbay.http.HttpConnection.service(HttpConnection.java:816) > at org.mortbay.http.HttpConnection.handleNext(HttpConnection.java:983) > at org.mortbay.http.HttpConnection.handle(HttpConnection.java:833) > at > org.mortbay.http.SocketListener.handleConnection(SocketListener.java:244) > at org.mortbay.util.ThreadedServer.handle(ThreadedServer.java:357) > at org.mortbay.util.ThreadPool$PoolThread.run(ThreadPool.java:534) > Caused by: java.lang.IllegalStateException: Operations can only be invoke > while the GBean is running: geronimo.config:name="SecurityRealmPostgresPool" > at > org.apache.geronimo.gbean.runtime.GBeanInstance.invoke(GBeanInstance.java:833) > at > org.apache.geronimo.kernel.basic.BasicKernel.invoke(BasicKernel.java:180) > at > org.apache.geronimo.kernel.config.ConfigurationManagerImpl.loadGBeans(ConfigurationManagerImpl.java:128) > ... 47 more -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira