YaST2 Component Architecture

Author:
Mathias Kettner
Todo:
This is partially obsolete!

Design principles

The YaST2 component model is the foundation of the YaST2 architecture. It is important to understand at least the basic ideas in order to be able to write new Y2 components. It's based upon the following design principles:

YaST2 should be easily extensable. One should be able to exchange or add functionality independent of all other parts.This leads to a modular architecture. The interchangable parts are called 'components'.

It should be possible, that a component can be added or exchanged merely through the fact, that a file has been added or exchanged. This allows you to put configuration modules for a software into the same package as that software. For example you could write a configuration module for sendmail and put it into the sendmail package. As long as the sendmail package is installed, its YaST2 configuration module is available.

Despite the need for Y2 to be modular in concept, during execution time this should not lead to high communication overhead or large need in memory usage or the number of concurrently running processes.

The inter-component communication should be human readable, at least in debugging situations.

The inter-component communication should be network transparent.

It should be easy to write a component. Component implementing should not be restricted to a certain programming language.

Communication

All components speak a common language and act according to defined protocol. Both the language and the protocol are called YCP (YaST2 communication protocol). One protocol step consists of one of the partners sending exactly one of YCP Values to the other and the other receiving that value. In the next step, the component that just was receiving, is now sending and vice versa. The only exception is, that one of that partners may terminate the session and send a last result message after which - of course - the partner won't send another value.

Clients and Servers

There are two different kinds of components: server components and client components, which differ in how the control flows.

A server component is one that - once it's initialized - just waits for jobs to do. Another component can send a request and thus pass the control to the server. That does what is neccessary in order to do handle the request and returns an answer. Prominent examples for server components are the user interfaces. In YaST2 they play a passive role. They just wait for a command like "Show me this dialog, wait for the next user input and return me that input". A server component can also use the service of another server component. For example the SCR (System configuration repository) makes use of servers called agents, which realize subtrees of the SCR tree.

A client component is one that controls the flow. It may contain something like an "event loop". In order to do its work, it can use the services of other server components. Client components are sometimes called modules. Examples for modules are the single steps of the YaST2 "Installation Wizard" or the program that calls rpm to install packages. Other examples could be a module that configures the network setup of a workstation or one, that just sets the IP-number and the hostname of that workstation.

Modules can be hiearchically structured and hand over control to other modules that acomplish sub tasks and are called submodules in this context. An example is the structure of the YaST2 installer. The installation itself is a module. For each of the wizard window steps, it calls a submodule.

How components are realized

There are quite a number of ways how you can implement a component. A component can be:

  • An executable program (ELF, /bin/sh, or whatsoever)
  • A C++ class using libycp Library and liby2 Library
  • A YCP script executed by the Workflowmanager
  • Youself typing some YCP code at a terminal

Don't laugh over the last possibility! For debugging this is sometimes very helpful. You can simulate any component by typing to a terminal.

Executable programs

A component that exists as executable program is realized by a process that is created when the component is needed. If a component needs the services of an external program component, it launches a seperate process and starts a communication via two unix pipes, one in each direction.

The data flowing through these pipes is YCP Ascii representation. Each communication side needs a parser to analyse the data and a YCP syntax generater to write data to the pipe. Both can be found in the libycp Library, which can only used from C++ programs.

But the production of YCP code can in many cases very easily be done be printing to stdout, for example with echo (shell) or printf (C).

The parsing of YCP code is as bit more tricky. But in many cases you don't need a full featured parser, because you know beforehand what structure the value have that you get. This especially holds for client components, because they can decide, how the output from the server should look like.

C++ class using libycp and liby2

If you anyway decide to write your component in C++, it's by far the most conveniant way to use the functionality of libycp and liby2, whose only purpose is excactly to support component implementation.

What you have to do is to subclass at least two classes: Y2ComponentCreator and Y2Component and

Depending on whether you want to implement a server or a client component you have to override different methods. Many examples can be found within the liby2 itself.

One big advantage of writing a component in C++ is, that you can very easily create three external appearances of the component:

The YaST2 installer makes usage of the third variant only. All required components are linked together to y2base, which is statically linked against liby2 and libycp. The memory usage is reduced as well as the required disk space. Furthermore no creating and parsing of Ascii streams between the components is required. Protocol steps are simple function calls. Even for very large data structures, only one pointer has to be passed.

A YCP script executed by the Workflowmanager

If you have installed YaST2, you will find some files ending in .ycp lying around in /lib/YaST2/clients. These are YCP scripts implementing client components (modules). YCP is not only a protocol, it is also a full features programming language, which is in this case used to implement components. This is very conveniant as the language can directly operate on the protocol values and has some other nice features.

The client scripts are executed by the Workflowmanager, which is an extension to the core YCP language. It implements a couple of builtin functions that allow communication the the system and with other components. Here is a of builtins..

Youself typing YCP code at a terminal

You can be a component yourself :-). Just tell another component to communicate via stdio and speak with it. For example you can launch the component ycp by typing y2ycp stdio. Now you can enter YCP expressions and get the evaluation as answer.


Generated on a sunny day for yast2-core by doxygen 1.5.9