{"id":339,"date":"2013-07-20T01:04:42","date_gmt":"2013-07-20T01:04:42","guid":{"rendered":"http:\/\/www.danplanet.com\/blog\/?p=339"},"modified":"2013-07-20T01:04:42","modified_gmt":"2013-07-20T01:04:42","slug":"a-brief-overview-of-novas-new-object-model-part-3","status":"publish","type":"post","link":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/","title":{"rendered":"A brief overview of Nova\u2019s new object model (Part 3)"},"content":{"rendered":"<p>In parts <a href=\"https:\/\/www.danplanet.com\/blog\/2013\/07\/12\/a-brief-overview-of-novas-new-object-model-part-1\/\">one<\/a> and <a href=\"https:\/\/www.danplanet.com\/blog\/2013\/07\/12\/a-brief-overview-of-novas-new-object-model-part-2\/\">two<\/a>, I talked about the reasoning for developing an object model inside of Nova, as well as showed a sample implementation for a toy object. In this part, I will examine parts of some &#8220;real&#8221; objects that are currently under development in the Nova tree.<\/p>\n<p>The biggest object in Nova is (and probably always will be) <a href=\"https:\/\/github.com\/openstack\/nova\/blob\/master\/nova\/objects\/instance.py\">Instance<\/a>. It&#8217;s fairly complicated though, so let&#8217;s start with something a little simpler, such as the <a href=\"https:\/\/github.com\/openstack\/nova\/blob\/master\/nova\/objects\/security_group.py\">SecurityGroup<\/a> object. Here is the field definition:<\/p>\n<pre style=\"font-size: 11px;\">class SecurityGroup(base.NovaObject):\r\n    fields = {\r\n        'id': int,\r\n        'name': str,\r\n        'description': str,\r\n        'user_id': str,\r\n        'project_id': str,\r\n    }<\/pre>\n<p>There is an integral ID and a few strings, so it is pretty simple. There are two ways to query for those objects, by name or by ID:<\/p>\n<pre style=\"font-size: 11px;\">@base.remotable_classmethod\r\ndef get(cls, context, secgroup_id):\r\n    db_secgroup = db.security_group_get(context, secgroup_id)\r\n    return cls._from_db_object(cls(), db_secgroup)\r\n\r\n@base.remotable_classmethod\r\ndef get_by_name(cls, context, project_id, group_name):\r\n    db_secgroup = db.security_group_get_by_name(context,\r\n                                                project_id,\r\n                                                group_name)\r\n    return cls._from_db_object(cls(), db_secgroup)<\/pre>\n<p>Both of these methods use a common pattern as many of the other objects, which is to query the database for the SQLAlchemy model, and then pass that to a generic function (not shown here) that constructs the new object. Both of these are decorated with <strong>remotable_classmethod<\/strong>, which makes them callable from across RPC and at a class level. Querying for a security group would look something like this:<\/p>\n<pre style=\"font-size: 11px;\">from nova.objects import security_group\r\nsecgroup = security_group.SecurityGroup.get(context, 1234)<\/pre>\n<p>Unlike the fictitious example in Part 2, there is another way to query for security group objects, which is by a collection based on some common attribute. This is often done by project ID, for example. The objects framework provides a way to easily define an object that is a list of objects, such that the list can be queried directly or over RPC in the same way, and so that the list itself contains inbuilt serialization, which handles the serialization of the objects contained within. See the <strong>SecurityGroupList<\/strong> object:<\/p>\n<pre style=\"font-size: 11px;\">class SecurityGroupList(base.ObjectListBase, base.NovaObject):\r\n    @base.remotable_classmethod\r\n    def get_all(cls, context):\r\n        return _make_secgroup_list(\r\n            context, cls(),\r\n            db.security_group_get_all(context))\r\n\r\n    @base.remotable_classmethod\r\n    def get_by_project(cls, context, project_id):\r\n        return _make_secgroup_list(\r\n            context, cls(),\r\n            db.security_group_get_by_project(\r\n                context, project_id))\r\n\r\n    @base.remotable_classmethod\r\n    def get_by_instance(cls, context, instance):\r\n        return _make_secgroup_list(\r\n            context, cls(),\r\n            db.security_group_get_by_instance(\r\n                context, instance.uuid))<\/pre>\n<p>The first line shows that this special object is not only a <strong>NovaObject<\/strong>, but also an <strong>ObjectListBase<\/strong>, which provides the special list behavior. Note that the order of inheritance is important, so they must be in the order shown.<\/p>\n<p>The <strong>ObjectListBase<\/strong> definition assumes a single field of &#8220;objects&#8221; and handles typical list-like behaviors like iteration of the things in the objects field, as well as membership (i.e. contains) operations. Thus, all you need to do is fill out the &#8220;foo.objects&#8221; list, like the <strong>_make_secgroup_list()<\/strong> helper function does:<\/p>\n<pre style=\"font-size: 11px;\">def _make_secgroup_list(context, secgroup_list, db_secgroup_list):\r\n    secgroup_list.objects = []\r\n    for db_secgroup in db_secgroup_list:\r\n        secgroup = SecurityGroup._from_db_object(\r\n            SecurityGroup(), db_secgroup)\r\n        secgroup._context = context\r\n        secgroup_list.objects.append(secgroup)\r\n    secgroup_list.obj_reset_changes()\r\n    return secgroup_list<\/pre>\n<p>This method simply populates the &#8220;objects&#8221; list of the <strong>SecurityGroupList<\/strong> object with <strong>SecurityGroup<\/strong> objects it constructs from the raw database models provided. It uses the same <strong>_from_db_object()<\/strong> helper method as the <strong>SecurityGroup<\/strong> object itself. You can use the result of this just like a real list:<\/p>\n<pre style=\"font-size: 11px;\">secgroups = security_group.SecurityGroupList.get_all(context)\r\nfor secgroup in secgroups:\r\n    print secgroup.name<\/pre>\n<p>The massive Instance object is similar to what we&#8217;ve seen in previous examples, and the <strong>SecurityGroup<\/strong> example above. There is a base <strong>Instance<\/strong> object, and an <strong>InstanceList<\/strong> object to provide an implementation for all the ways we can query for multiple instances at once. It&#8217;s too big to show here, but here is a subset of the field definition:<\/p>\n<pre style=\"font-size: 11px;\">class Instance(base.NovaObject):\r\n    fields = {\r\n        'id': int,\r\n        'user_id': obj_utils.str_or_none,\r\n        'project_id': obj_utils.str_or_none,\r\n        'launch_index': obj_utils.int_or_none,\r\n        'scheduled_at': obj_utils.datetime_or_str_or_none,\r\n        'launched_at': obj_utils.datetime_or_str_or_none,\r\n        'terminated_at': obj_utils.datetime_or_str_or_none,\r\n        'locked': bool,\r\n        'access_ip_v4': obj_utils.ip_or_none(4),\r\n        'access_ip_v6': obj_utils.ip_or_none(6),\r\n . . . }<\/pre>\n<p>Finally, an object with some interesting fields! We see the usual integral ID field at the top, but notice that most of the other fields use &#8220;or none&#8221; helpers from the utils module. Since many of the fields in the instance can be empty (nullable=True in the database definition), we need to handle &#8220;either a string or None&#8221; in cases such as <strong>user_id<\/strong>. The utils module provides some helpers for datetime and ip address functions, which return <strong>datetime.datetime<\/strong> and <strong>netaddr.IPAddress<\/strong> objects respectively. Just like the <strong>int<\/strong>\u00a0and <strong>str<\/strong> type functions, these take a string and convert it into the complex type when someone does something like this:<\/p>\n<pre style=\"font-size: 11px;\">inst = instance.Instance()\r\ninst.access_ip_v4 = '1.2.3.4'  # Stored as netaddr.IPAddress('1.2.3.4')<\/pre>\n<p>These fields with complicated data types bring us to our first concrete example of something needing special handling during serialization and deserialization. The <strong>Instance<\/strong> object contains methods like <strong>_attr_scheduled_at_to_primitive()<\/strong> and <strong>_attr_scheduled_at_from_primitive()<\/strong> that handle converting the <strong>datetime<\/strong> objects to and from strings properly. Handlers (and handler-builders) for these types are provided in the <a href=\"https:\/\/github.com\/openstack\/nova\/master\/nova\/objects\/utils.py\">utils<\/a> module. The IP address fields provide a useful example for illustration, such as this serialization method for the IPv4 address:<\/p>\n<pre style=\"font-size: 11px;\">    def _attr_access_ip_v4_to_primitive(self):\r\n        if self.access_ip_v4 is not None:\r\n            return str(self.access_ip_v4)\r\n        else:\r\n            return None<\/pre>\n<p>This gets called by the object&#8217;s serialization method when it encounters the complex IPv4 address field. Although not obvious to the layer above us, the <strong>netaddr.IPAddress<\/strong> object can serialize itself through simple string coercion, so we do just that. However, since the field could be None, we want to be sure not to convert that to a string resulting with the string &#8220;None&#8221; instead of None itself. Luckily, we need no special deserialization because the result of the above string coercion is sufficient to pass to the field&#8217;s type function itself, which the deserialization routine will try if no special handler is provided.<\/p>\n<p>In a subsequent part, I will talk about advanced topics like lazy-loading, versioning, and object nesting.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In parts one and two, I talked about the reasoning for developing an object model inside of Nova, as well as showed a sample implementation for a toy object. In this part, I will examine parts of some &#8220;real&#8221; objects &hellip; <a href=\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[97],"tags":[112,93,107,106,92,111,113],"class_list":["post-339","post","type-post","status-publish","format-standard","hentry","category-openstack","tag-instance","tag-nova","tag-novaobject","tag-objects","tag-openstack_","tag-securitygroup","tag-serialization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>A brief overview of Nova\u2019s new object model (Part 3) - Right Angles<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"A brief overview of Nova\u2019s new object model (Part 3) - Right Angles\" \/>\n<meta property=\"og:description\" content=\"In parts one and two, I talked about the reasoning for developing an object model inside of Nova, as well as showed a sample implementation for a toy object. In this part, I will examine parts of some &#8220;real&#8221; objects &hellip; Continue reading &rarr;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\" \/>\n<meta property=\"og:site_name\" content=\"Right Angles\" \/>\n<meta property=\"article:published_time\" content=\"2013-07-20T01:04:42+00:00\" \/>\n<meta name=\"author\" content=\"Dan\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dan\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\"},\"author\":{\"name\":\"Dan\",\"@id\":\"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c\"},\"headline\":\"A brief overview of Nova\u2019s new object model (Part 3)\",\"datePublished\":\"2013-07-20T01:04:42+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\"},\"wordCount\":796,\"publisher\":{\"@id\":\"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c\"},\"keywords\":[\"Instance\",\"nova\",\"NovaObject\",\"objects\",\"openstack\",\"SecurityGroup\",\"serialization\"],\"articleSection\":[\"OpenStack\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\",\"url\":\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\",\"name\":\"A brief overview of Nova\u2019s new object model (Part 3) - Right Angles\",\"isPartOf\":{\"@id\":\"https:\/\/www.danplanet.com\/blog\/#website\"},\"datePublished\":\"2013-07-20T01:04:42+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.danplanet.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"A brief overview of Nova\u2019s new object model (Part 3)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.danplanet.com\/blog\/#website\",\"url\":\"https:\/\/www.danplanet.com\/blog\/\",\"name\":\"Right Angles\",\"description\":\"If they&#039;re not right...they&#039;re wrong\",\"publisher\":{\"@id\":\"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.danplanet.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c\",\"name\":\"Dan\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9b73782704be64dd8c030087af2d1ae0c1dc488cad69093ff0366dbaad2de673?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9b73782704be64dd8c030087af2d1ae0c1dc488cad69093ff0366dbaad2de673?s=96&d=mm&r=g\",\"caption\":\"Dan\"},\"logo\":{\"@id\":\"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/image\/\"},\"url\":\"https:\/\/www.danplanet.com\/blog\/author\/dan\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"A brief overview of Nova\u2019s new object model (Part 3) - Right Angles","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/","og_locale":"en_US","og_type":"article","og_title":"A brief overview of Nova\u2019s new object model (Part 3) - Right Angles","og_description":"In parts one and two, I talked about the reasoning for developing an object model inside of Nova, as well as showed a sample implementation for a toy object. In this part, I will examine parts of some &#8220;real&#8221; objects &hellip; Continue reading &rarr;","og_url":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/","og_site_name":"Right Angles","article_published_time":"2013-07-20T01:04:42+00:00","author":"Dan","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Dan","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/#article","isPartOf":{"@id":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/"},"author":{"name":"Dan","@id":"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c"},"headline":"A brief overview of Nova\u2019s new object model (Part 3)","datePublished":"2013-07-20T01:04:42+00:00","mainEntityOfPage":{"@id":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/"},"wordCount":796,"publisher":{"@id":"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c"},"keywords":["Instance","nova","NovaObject","objects","openstack","SecurityGroup","serialization"],"articleSection":["OpenStack"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/","url":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/","name":"A brief overview of Nova\u2019s new object model (Part 3) - Right Angles","isPartOf":{"@id":"https:\/\/www.danplanet.com\/blog\/#website"},"datePublished":"2013-07-20T01:04:42+00:00","breadcrumb":{"@id":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.danplanet.com\/blog\/2013\/07\/20\/a-brief-overview-of-novas-new-object-model-part-3\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.danplanet.com\/blog\/"},{"@type":"ListItem","position":2,"name":"A brief overview of Nova\u2019s new object model (Part 3)"}]},{"@type":"WebSite","@id":"https:\/\/www.danplanet.com\/blog\/#website","url":"https:\/\/www.danplanet.com\/blog\/","name":"Right Angles","description":"If they&#039;re not right...they&#039;re wrong","publisher":{"@id":"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.danplanet.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/0f6920aa6d63cae437bf8b122200287c","name":"Dan","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9b73782704be64dd8c030087af2d1ae0c1dc488cad69093ff0366dbaad2de673?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9b73782704be64dd8c030087af2d1ae0c1dc488cad69093ff0366dbaad2de673?s=96&d=mm&r=g","caption":"Dan"},"logo":{"@id":"https:\/\/www.danplanet.com\/blog\/#\/schema\/person\/image\/"},"url":"https:\/\/www.danplanet.com\/blog\/author\/dan\/"}]}},"_links":{"self":[{"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/posts\/339","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/comments?post=339"}],"version-history":[{"count":5,"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/posts\/339\/revisions"}],"predecessor-version":[{"id":344,"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/posts\/339\/revisions\/344"}],"wp:attachment":[{"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/media?parent=339"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/categories?post=339"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.danplanet.com\/blog\/wp-json\/wp\/v2\/tags?post=339"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}