 Okay. Good afternoon. I'm just stealing a short period of time. And my name is Matthias Runge. I'm a software developer at Red Hat and also a packager. And upstream in Horizon as well. So during the past, we had the issues about what do we do with Horizon when we do updates of packages or installing tar balls or whatever. And we previously customized Horizon. And I'm going to tell you about what to do without breaking or how not to break on updates. So this is Horizon as it looks like or as you probably know it. It has this vertical navigation bar at the left side. And in many cases, it's not desired by corporates or so. You could easily change that. And it might look like this one with the horizontal navigation bar. This is currently deployed by Red Hat. Let's take a step back and come back to this later. What is OpenStack dashboard? It's the dashboard implementation. It's built on top of Django as the framework. And it's quite easy to configure it because you just need to point it to a Keystone endpoint. And everything else comes from Keystone directly. Not entirely correct, but probably. And it talks directly to underlying services via API calls. And as we know, the source code is available at GitHub. So when speaking of deployment, most probably you will deploy stable releases. So Ice House was released just a few weeks ago. And this is the currently planned update schedule for Ice House. And as you see, we have quite a few releases planned. And if you would configure it, like it, or modify it as it's described on upstream docs, you will lose it at every update. And, well, so at most times, you would add a company logo, maybe change the font, change a different background color, or change the navigation bar, and so on. Or this is one thing. Just to change the look and feel. Or on the other side, you could, for example, disable image uploading by ordinary users or something else. This is just a policy change, but this is often a desire change if you are going to deploy Horizon. Looking at our upstream docs, we just have very few options to change the look of Horizon. We have the site title. It's named SiteBranding. It's just a configuration option in the settings file. And the recommended way to change the logo is by overwriting the corresponding file, which will break, of course, at every package update. And the logo file is this logo on top in the red circle. And you could also change the brand link, which is the bottom red cycle, which could point to anything else. It's just what happens if you click on the currently open stack logo. Okay, better. Using the quick and dirty way would be to replace that logo file. I just chose that cat because everybody loves cats. And the dimension of that file should be 216 by 35 pixels. And if you're doing that to your cat, it's not entirely correct, but it's just awful. And the rest of the presentation is about how to do it right and how not to do this. Let's take another step back. What's a software package? And why is it cool? Or why do we use it? Because it maintains dependencies. If you're installing a package like OpenStack dashboard, that package knows, oh, yes, I'm relying on Nova Client and Heat Client and so on. So all those dependencies are pulled in during install. And often or in almost all cases packages are organized and repositories. So if you're going to push an update to somewhere, you're just doing an update on your package repository. And all your clients will pull those changes from the package repository. And in many, many cases, you just need to have one repository or a tree of repositories. But compared to Windows, for example, each application is pulling for own updates. This is not desired in many cases. And packages provide metadata. For example, you could ask with the first command to which package this specific file belongs to. So you could check your file system and ask which file on your file system does not belong to a package. This is something you added manually, because everything else should be packaged. Or you could ask the package manager, tell me all files provided by package blah or who. And when you're installing a package or updating a package, all packages listed in the package are replaced. Instead, not entirely correct, configuration files are not replaced. And this is the main difference between RPN and, for example, Debian. RPM doesn't touch your configuration files. And Debian tries to do the smartest thing, whatever that is. So if you're looking at the OpenStack dashboard configuration files, they are currently two, mainly. It's the settings.py living somewhere under user share. And in our case, the other one is OpenStack, et cetera, OpenStack dashboard and local settings. And everything below local settings is to be configured by the user. And the rest doesn't interest anybody. And the last line just lists all policy files. I come to this because I mentioned earlier the change of a policy and forbidding a user to upload an image. This is mapped in the local settings where those policy files are mapped to et cetera OpenStack dashboard. And you see the dictionary on the bottom. So I have a small demo on this. Just a second. Where's my mouse key? I can't spot help. Great. Certainly I'm unable to see the mouse. There's no mouse pointer at all. Ah, better. So I'm just logging in and go to images. And you see the create image button. Now I'm going to remove that button. I'm not removing it, but I'm making this admin only. And just reloading, it's gone. Magic. The other things to configure is allowed hosts. And I've seen many configurations where this is just set to as the risk, which is not secure at all. I wouldn't recommend it. I would set it to the name or the IP address of the host where OpenStack dashboard is installed. Nothing else. Debug or setting debug to true will help you while debugging issues. And basically OpenStack host is the host where your keystone is installed. So if you're moving your keystone to a different IP address or host, you're just changing that specific config option and you're done. And all that dirty details you'll find upstream at the developer documentation. So let's have a quick tour through the dashboard code. Basically you see two, mainly two directories. One directory named Horizon. And you could think about that directory as a library, providing everything you need to build up a dashboard. And OpenStack dashboard, which holds the OpenStack dashboard itself. And this is currently the implementation. And below that directory dashboards, the actual dashboards are located. Enabled is a directory to put configuration files. This is an ice house feature and it's not included in Havana or earlier. And all that stuff I'm telling you, it's basically based on that. Static and templates, static files and templates. Static files are, for example, the logo or JavaScript files and so on. And templates are just what you can see when browsing through your dashboard. And if you're going to change the look and feel of your Horizon, you'll be putting your changed logo and so on below static files. Or within the dashboard's folder in your customization module. And Django has a quite cool feature. You saw earlier the manage.py file. And it's Django file meant to talk with your implementation. And it's, for example, it could be used to find static files. In this specific case, the dashboard image logo. And it will list, or it will list every static file named in that way. In your templates, are you specifying, just give me a file located below that path. You could have several of them. So you have an explicit order on that. And to verify if you're pulling the right file or the file you intended to pull, you could use that command. For templates, we have the same. And this, we have an option to override provided templates. I mean, upstream provided templates. And this is the key to change everything you had on your dashboard. Side course, we are also using Django Compressor, which is an application to compress JavaScript files. It takes a whole bunch of JavaScript files and produces just one minimized file and ships it to the user. And also handles all mappings between them. So you just specify in your template, I need this and that and that and that. And Compressor just takes all of them, compresses them and just ships one file to the user. And this is in upstream configuration. This is done online. It's cached, but it's done online. So on demand. If you're requesting such a file, it's done it. It could take, in worst case, up to one minute to compress all those files or translate it, especially when it comes to less and translate less to CSS. So there's an option as well to pre-compress everything, put it to your file system and deliver it when the user requests it. So when we are going to customize our dashboard, we will be putting a directory below dashboards. And that will probably look like this one. Dashboard is a file, just, it's just a file and I'll show the contents later. Most files are empty or just contain one single line. And what's the second file not being empty? It's called panel.py. So for example, for this example, I just created a dashboard and a panel and I named that dashboard, for example, Kitten and the panel Kitten Index. But it doesn't matter. You could choose whatever you want. This is just the demonstration how this would look like. You give it a name and give it a short title that would be showing up in your URL unless you set navigation to true. And I set it to false so it shouldn't show up at all. And I'm registering it into a horizon. I'm doing this with the panel as well. And because that's so complicated, we have two shortcuts to do this. And if you're doing those shortcuts or running those shortcuts, which are also mentioned in our upstream docs, just as example, how to create a dashboard or a panel, those folders will be created on top level directory and you probably should move it to somewhere else. I proposed the dashboard's directory. And last but not least, you need a configuration file. This is an additional file. There are several configurations files as well. So this is just derived from that. But you need to copy some basic style sheets or templates. Yeah, and basically that's it. I did this, all that stuff to produce something like the, on this third slide, shown navigation bar. This one. It's just, I took those previously provided files, changed them, and shipped them in a different directory. And this enables you to switch it on or switch it off just by changing a value in the config file or removing that config file. And yeah, that's it. So if you're going to change the template files for your company, I assume it will take more than half an hour to look into those and to see, ah, this template snippet includes a different template and this template inherits from that template and so on. So it's a huge stack of templates included from other templates. It's not that easy, I must admit. Good thing is, we have extensive docs on that, especially on the Django project page. Just for your understanding, the listed commands, the first one includes a file named foo, which will be located through the template finder, which could reside below your, for example, a kitten file system or could be located somewhere else. We have some blocks in those template files and they are meant to be filled out by Django. So Django just takes this template and fills in values and renders the rest. Everything inside the Compress tag is taken for the compressor and will be compressed and delivered to the user. If you're going to display some variables, the next setting is useful. And if you're going to use it, I urge you to look that up on the Django project page. So our last file currently looks like this and I told you earlier the logo needs to have 216 by 35 pixels and this is where that comes from. No, this is the logo splash. This is the one. We currently have two logos. I forgot to mention. The first one is the logo on the login page and the second one is the smaller logo on the left side on top of the navigation bar. So suggest you should add static files to your application you just created by running those two commands and in your freshly created directory you find a static directory and you just should copy your static files there. And after changing or adding a static file you need to run manage.py collect static to copy all those static files to central storage. And if you're going to change less files and have Compress offline enabled, remember to refresh those offline compressed CSS files. I must admit it's quite a pain to debug if something goes wrong and if you're going to change all those things, it's very likely you'll see an issue and I suggest to set a debug to true. It will help a lot. And if you're doing some changes on your settings file, you need to restart your htdpd. It's an often made mistake. Currently, unfortunately, it has some limitations. It doesn't support internationalization. Yet you could do that, but it's a bit harder to do. It's not generally upgrade safe, meaning if you have this installed and deployed and going to upgrade to Juno, that could have changed something and I cannot guarantee you'll be safe on your upgrade. It's likely you are safe, but no one can guarantee that. And for this thing, Icehouse is required because we are relying on that plug-ins feature we just introduced during the Icehouse development cycle. And that's it. Slides are on my web page as well. And I think we are through. And I'm gifting you some lifetime back also. Thank you very much. Questions? They are going to be videotaped and shown on YouTube. Not to push any pressure. I have a question about the CSS modification. What do you think about some tools like Bower which allow you to manage your dependencies and to avoid forking or reason directly? For example, I want to change my CSS, but I don't want to have to patch every time the CSS file in production. So if I have a Bower repository with all the CSS of horizon, I just modify it and I just have to change my dependency to have the change in horizon. For example, in my company, we have made some modification on OpenStack OS and it was a great tool to have a PIP to interchange our package. So what do you think of this making separate packages for the front? For example, CSS or JS or everything else. And we have more facilities to change the front end appearance of horizon without forking all the repository. You are just introducing a second tool to manage dependencies. I wouldn't recommend it at all because you just have the packaging system and you could rely on that packaging system. If you are doing it separately, okay, go ahead. And on the other side, you just need to copy your modified CSS or less below your newly created panel and let horizon do the rest. You don't need to hassle with your changes. You just put your changes and you don't need to patch it all. You copy your new thing and you even could include that old less file. Yeah, but for example, if a horizon have a modification in the less file and I just copy the new one, I have to make a diff between the two files. No, you don't have. If I want to add some modification and no horizon as a less file with modification. Why do you need a diff? Because you're just putting your original file to the file system and rely on your modifications. You just rely on your new file and you shouldn't care on a diff also. Yeah, but if, for example, I made a CSS for the Havana release and now I'm migrating my horizon to Icehouse. The CSS file has changed upstream but mine is the same. So I have to make a diff that's one time task. But if you're using Bower or some other tools, you need to do the diff. Bower is just an example. On every upgrade you might have to change your CSS. That's what I said or mentioned earlier. As I said, it's not in general upgrade safe. Because you might have to change something. But that's the nature of the thing. And you cannot circumvent that in no case because you cannot know what will be happening during Juno release cycle. Yeah, and I have to make a diff. But if we have a repository, I can just quick see the difference between the package I've made and the package which is upstream with this solution. When I have to copy my file, I have to make a diff by hand instead of using some tools like git or things like that. I disagree. Let's look into that after the session. I guess it'll take some time. Okay, that's all for me. My questions. Okay. Okay. Thank you for your time and enjoy your evening.